~ubuntu-branches/ubuntu/utopic/gettext/utopic

« back to all changes in this revision

Viewing changes to gettext-tools/misc/po-mode.el

  • Committer: Colin Watson
  • Date: 2010-08-01 21:36:08 UTC
  • mfrom: (2.1.10 sid)
  • Revision ID: cjwatson@canonical.com-20100801213608-yy7vkm8lpatep3ci
merge from Debian 0.18.1.1-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
;;; po-mode.el -- major mode for GNU gettext PO files
2
2
 
3
 
;; Copyright (C) 1995-1999, 2000-2002, 2005-2007 Free Software Foundation, Inc.
 
3
;; Copyright (C) 1995-1999, 2000-2002, 2005-2008, 2010 Free Software Foundation, Inc.
4
4
 
5
 
;; Authors: Fran�ois Pinard <pinard@iro.umontreal.ca>
 
5
;; Authors: François Pinard <pinard@iro.umontreal.ca>
6
6
;;          Greg McGary <gkm@magilla.cichlid.com>
7
7
;; Keywords: i18n gettext
8
8
;; Created: 1995
9
9
 
10
10
;; This file is part of GNU gettext.
11
11
 
12
 
;; GNU gettext is free software; you can redistribute it and/or modify
 
12
;; This program is free software: you can redistribute it and/or modify
13
13
;; it under the terms of the GNU General Public License as published by
14
 
;; the Free Software Foundation; either version 2, or (at your option)
15
 
;; any later version.
 
14
;; the Free Software Foundation; either version 3 of the License, or
 
15
;; (at your option) any later version.
16
16
 
17
 
;; GNU gettext is distributed in the hope that it will be useful,
 
17
;; This program is distributed in the hope that it will be useful,
18
18
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19
19
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
20
;; GNU General Public License for more details.
21
21
 
22
22
;; You should have received a copy of the GNU General Public License
23
 
;; along with GNU Emacs; see the file COPYING.  If not, write to the
24
 
;; Free Software Foundation, 51 Franklin Street, Fifth Floor,
25
 
;; Boston, MA 02110-1301, USA.
 
23
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
26
24
 
27
25
;;; Commentary:
28
26
 
64
62
 
65
63
;;; Code:
66
64
 
67
 
(defconst po-mode-version-string "2.1" "\
 
65
(defconst po-mode-version-string "2.2" "\
68
66
Version number of this version of po-mode.el.")
69
67
 
70
68
;;; Emacs portability matters - part I.
119
117
  :type 'boolean
120
118
  :group 'po)
121
119
 
 
120
(defcustom po-auto-delete-previous-msgid t
 
121
  "*Automatically delete previous msgid (marked #|) when editing entry.
 
122
Value is nil, t, or ask."
 
123
  :type '(choice (const nil)
 
124
                 (const t)
 
125
                 (const ask))
 
126
  :group 'po)
 
127
 
122
128
(defcustom po-auto-select-on-unfuzzy nil
123
129
  "*Automatically select some new entry while making an entry not fuzzy."
124
130
  :type 'boolean
188
194
    ("(Afan) Oromo" . "om")
189
195
    ("Abkhazian" . "ab")
190
196
    ("Achinese" . "ace")
191
 
    ("Adangme" . "ad")
192
197
    ("Afar" . "aa")
193
198
    ("Afrikaans" . "af")
194
199
    ("Akan" . "ak")
208
213
    ("Balinese" . "ban")
209
214
    ("Baluchi" . "bal")
210
215
    ("Bambara" . "bm")
211
 
    ("Banda" . "bad")
212
216
    ("Bashkir" . "ba")
213
217
    ("Basque" . "eu")
214
 
    ("Batak" . "btk")
 
218
    ("Beja" . "bej")
215
219
    ("Belarusian" . "be")
216
220
    ("Bemba" . "bem")
217
221
    ("Bengali" . "bn")
228
232
    ("Burmese" . "my")
229
233
    ("Catalan" . "ca")
230
234
    ("Cebuano" . "ceb")
 
235
    ("Central Khmer" . "km")
231
236
    ("Chamorro" . "ch")
232
237
    ("Chechen" . "ce")
233
238
    ("Chinese" . "zh")
302
307
    ("Kashmiri" . "ks")
303
308
    ("Kashubian" . "csb")
304
309
    ("Kazakh" . "kk")
305
 
    ("Khmer" . "km")
 
310
    ("Khmer" . "km") ; old name
306
311
    ("Kikuyu" . "ki")
307
312
    ("Kimbundu" . "kmb")
308
313
    ("Kinyarwanda" . "rw")
369
374
    ("Old English" . "ang")
370
375
    ("Oriya" . "or")
371
376
    ("Ossetian" . "os")
372
 
    ("P�ez" . "pbb")
 
377
    ("Páez" . "pbb")
373
378
    ("Pali" . "pi")
374
379
    ("Pampanga" . "pam")
375
380
    ("Pangasinan" . "pag")
380
385
    ("Punjabi" . "pa")
381
386
    ("Quechua" . "qu")
382
387
    ("Rajasthani" . "raj")
383
 
    ("Rhaeto-Roman" . "rm")
 
388
    ("Rhaeto-Roman" . "rm") ; old name
384
389
    ("Romanian" . "ro")
 
390
    ("Romansh" . "rm")
385
391
    ("Russian" . "ru")
386
392
    ("Samoan" . "sm")
387
393
    ("Sango" . "sg")
389
395
    ("Santali" . "sat")
390
396
    ("Sardinian" . "sc")
391
397
    ("Sasak" . "sas")
392
 
    ("Scots" . "gd")
 
398
    ("Scots" . "gd") ; old name
 
399
    ("Scottish Gaelic" . "gd")
393
400
    ("Serbian" . "sr")
394
401
    ("Serer" . "srr")
395
402
    ("Sesotho" . "st")
688
695
(defvar po-start-of-entry)
689
696
(defvar po-start-of-msgctxt) ; = po-start-of-msgid if there is no msgctxt
690
697
(defvar po-start-of-msgid)
 
698
(defvar po-start-of-msgid_plural) ; = nil if there is no msgid_plural
691
699
(defvar po-start-of-msgstr-block)
692
700
(defvar po-start-of-msgstr-form)
693
701
(defvar po-end-of-msgstr-form)
694
702
(defvar po-end-of-entry)
695
703
(defvar po-entry-type)
696
 
(defvar po-msgstr-form-flavor)
697
704
 
698
705
;; A few counters are usefully shown in the Emacs mode line.
699
706
(defvar po-translated-counter)
1002
1009
                         (error (_"I do not know how to mail to '%s'") to))))))
1003
1010
  "Function to start composing an electronic message.")
1004
1011
 
 
1012
(defvar po-any-previous-msgctxt-regexp
 
1013
  "^#\\(~\\)?|[ \t]*msgctxt.*\n\\(#\\(~\\)?|[ \t]*\".*\n\\)*"
 
1014
  "Regexp matching a whole #| msgctxt field, whether obsolete or not.")
 
1015
 
 
1016
(defvar po-any-previous-msgid-regexp
 
1017
  "^#\\(~\\)?|[ \t]*msgid.*\n\\(#\\(~\\)?|[ \t]*\".*\n\\)*"
 
1018
  "Regexp matching a whole #| msgid field, whether obsolete or not.")
 
1019
 
 
1020
(defvar po-any-previous-msgid_plural-regexp
 
1021
  "^#\\(~\\)?|[ \t]*msgid_plural.*\n\\(#\\(~\\)?|[ \t]*\".*\n\\)*"
 
1022
  "Regexp matching a whole #| msgid_plural field, whether obsolete or not.")
 
1023
 
1005
1024
(defvar po-any-msgctxt-msgid-regexp
1006
1025
  "^\\(#~[ \t]*\\)?msg\\(ctxt\\|id\\).*\n\\(\\(#~[ \t]*\\)?\".*\n\\)*"
1007
1026
  "Regexp matching a whole msgctxt or msgid field, whether obsolete or not.")
1010
1029
  "^\\(#~[ \t]*\\)?msgid.*\n\\(\\(#~[ \t]*\\)?\".*\n\\)*"
1011
1030
  "Regexp matching a whole msgid field, whether obsolete or not.")
1012
1031
 
 
1032
(defvar po-any-msgid_plural-regexp
 
1033
  "^\\(#~[ \t]*\\)?msgid_plural.*\n\\(\\(#~[ \t]*\\)?\".*\n\\)*"
 
1034
  "Regexp matching a whole msgid_plural field, whether obsolete or not.")
 
1035
 
1013
1036
(defvar po-any-msgstr-block-regexp
1014
 
  "^\\(#~[ \t]*\\)?msgstr.*\n\\(\\(#~[ \t]*\\)?\".*\n\\)*\\(\\(#~[ \t]*\\)?msgstr\\[[0-9]\\].*\n\\(\\(#~[ \t]*\\)?\".*\n\\)*\\)*"
 
1037
  "^\\(#~[ \t]*\\)?msgstr\\([ \t]\\|\\[0\\]\\).*\n\\(\\(#~[ \t]*\\)?\".*\n\\)*\\(\\(#~[ \t]*\\)?msgstr\\[[0-9]\\].*\n\\(\\(#~[ \t]*\\)?\".*\n\\)*\\)*"
1015
1038
  "Regexp matching a whole msgstr or msgstr[] field, whether obsolete or not.")
1016
1039
 
1017
1040
(defvar po-any-msgstr-form-regexp
1160
1183
  (make-local-variable 'po-start-of-entry)
1161
1184
  (make-local-variable 'po-start-of-msgctxt)
1162
1185
  (make-local-variable 'po-start-of-msgid)
 
1186
  (make-local-variable 'po-start-of-msgid_plural)
1163
1187
  (make-local-variable 'po-start-of-msgstr-block)
1164
1188
  (make-local-variable 'po-end-of-entry)
1165
1189
  (make-local-variable 'po-entry-type)
1353
1377
                    ;; This is an oldish header.  Replace it all.
1354
1378
                    (goto-char end-of-header)
1355
1379
                    (while (> (point) (point-min))
1356
 
                      (previous-line 1)
 
1380
                      (forward-line -1)
1357
1381
                      (insert "#~ ")
1358
1382
                      (beginning-of-line))
1359
1383
                    (beginning-of-line)
1393
1417
                       t t))))
1394
1418
        (message ""))
1395
1419
    (message (_"PO-Revision-Date should be adjusted...")))
 
1420
  ;; Return nil to indicate that the buffer has not yet been saved.
1396
1421
  nil)
1397
1422
 
1398
1423
;;; Handling span of entry, entry type and entry attributes.
1399
1424
 
1400
1425
(defun po-find-span-of-entry ()
1401
1426
  "Find the extent of the PO file entry where the cursor is.
1402
 
Set variables PO-START-OF-ENTRY, PO-START-OF-MSGCTXT, PO-START-OF-MSGID,
1403
 
po-start-of-msgstr-block, PO-END-OF-ENTRY and PO-ENTRY-TYPE to meaningful
1404
 
values. Decreasing priority of type interpretation is: obsolete, fuzzy,
1405
 
untranslated or translated."
 
1427
Set variables po-start-of-entry, po-start-of-msgctxt, po-start-of-msgid,
 
1428
po-start-of-msgid_plural, po-start-of-msgstr-block, po-end-of-entry, and
 
1429
po-entry-type to meaningful values. po-entry-type may be set to: obsolete,
 
1430
fuzzy, untranslated, or translated."
1406
1431
  (let ((here (point)))
1407
1432
    (if (re-search-backward po-any-msgstr-block-regexp nil t)
1408
1433
        (progn
1460
1485
    (re-search-forward po-any-msgid-regexp)
1461
1486
    (setq po-start-of-msgid (match-beginning 0))
1462
1487
    (save-excursion
 
1488
      (goto-char po-start-of-msgid)
 
1489
      (setq po-start-of-msgid_plural
 
1490
            (if (re-search-forward po-any-msgid_plural-regexp
 
1491
                                   po-start-of-msgstr-block t)
 
1492
                (match-beginning 0)
 
1493
              nil)))
 
1494
    (save-excursion
1463
1495
      (when (>= here po-start-of-msgstr-block)
1464
1496
        ;; point was somewhere inside of msgstr*
1465
1497
        (goto-char here)
1466
1498
        (end-of-line)
1467
1499
        (re-search-backward "^\\(#~[ \t]*\\)?msgstr"))
1468
 
      ;; Detect the bounderies of the msgstr we are interested in.
 
1500
      ;; Detect the boundaries of the msgstr we are interested in.
1469
1501
      (re-search-forward po-any-msgstr-form-regexp)
1470
1502
      (setq po-start-of-msgstr-form (match-beginning 0)
1471
1503
            po-end-of-msgstr-form (match-end 0)))
1498
1530
              (insert ", " name)))
1499
1531
        (skip-chars-forward "\n")
1500
1532
        (while (eq (following-char) ?#)
1501
 
          (next-line 1))
 
1533
          (forward-line 1))
1502
1534
        (insert "#, " name "\n")))))
1503
1535
 
1504
1536
(defun po-delete-attribute (name)
1671
1703
  (po-find-span-of-entry)
1672
1704
  (if (or (eq po-entry-type 'untranslated)
1673
1705
          (eq po-entry-type 'obsolete)
1674
 
          (y-or-n-p (_"Really lose previous translation? ")))
1675
 
      (po-set-msgstr-form (po-get-msgid)))
1676
 
  (message ""))
 
1706
          (prog1 (y-or-n-p (_"Really lose previous translation? "))
 
1707
                 (message "")))
 
1708
      ;; In an entry with plural forms, use the msgid_plural string,
 
1709
      ;; as it is more general than the msgid string.
 
1710
      (if (po-set-msgstr-form (or (po-get-msgid_plural) (po-get-msgid)))
 
1711
          (po-maybe-delete-previous-untranslated))))
1677
1712
 
1678
1713
;; Obsolete entries.
1679
1714
 
1714
1749
  (cond ((eq po-entry-type 'fuzzy)
1715
1750
         (po-decrease-type-counter)
1716
1751
         (po-delete-attribute "fuzzy")
 
1752
         (po-maybe-delete-previous-untranslated)
1717
1753
         (po-current-entry)
1718
1754
         (po-increase-type-counter)))
1719
1755
  (if po-auto-select-on-unfuzzy
1741
1777
    (po-previous-entry-with-regexp po-any-msgstr-block-regexp t)
1742
1778
    (po-find-span-of-entry)
1743
1779
    (while (not (eq po-entry-type 'translated))
1744
 
      (po-previous-entry-with-regexp po-untranslated-regexp t)
 
1780
      (po-previous-entry-with-regexp po-any-msgstr-block-regexp t)
1745
1781
      (po-find-span-of-entry))))
1746
1782
 
1747
1783
;; Auto-selection feature.
1889
1925
  "Extract and return the unquoted msgid string."
1890
1926
  (let ((string (po-extract-unquoted (current-buffer)
1891
1927
                                     po-start-of-msgid
1892
 
                                     po-start-of-msgstr-block)))
 
1928
                                     (or po-start-of-msgid_plural
 
1929
                                         po-start-of-msgstr-block))))
1893
1930
    string))
1894
1931
 
 
1932
(defun po-get-msgid_plural ()
 
1933
  "Extract and return the unquoted msgid_plural string.
 
1934
Return nil if it is not present."
 
1935
  (if po-start-of-msgid_plural
 
1936
      (let ((string (po-extract-unquoted (current-buffer)
 
1937
                                         po-start-of-msgid_plural
 
1938
                                         po-start-of-msgstr-block)))
 
1939
        string)
 
1940
    nil))
 
1941
 
1895
1942
(defun po-get-msgstr-flavor ()
1896
 
  "Helper function to detect msgstr and msgstr[] variants."
1897
 
  (beginning-of-line)
1898
 
  (re-search-forward "^\\(#~[ \t]*\\)?\\(msgstr\\(\\[[0-9]\\]\\)?\\)")
1899
 
  (match-string 2))
 
1943
  "Helper function to detect msgstr and msgstr[] variants.
 
1944
Returns one of \"msgstr\" or \"msgstr[i]\" for some i."
 
1945
  (save-excursion
 
1946
    (goto-char po-start-of-msgstr-form)
 
1947
    (re-search-forward "^\\(#~[ \t]*\\)?\\(msgstr\\(\\[[0-9]\\]\\)?\\)")
 
1948
    (match-string 2)))
1900
1949
 
1901
1950
(defun po-get-msgstr-form ()
1902
1951
  "Extract and return the unquoted msgstr string."
1903
 
  (let ((flavor (po-get-msgstr-flavor))
1904
 
        (string (po-extract-unquoted (current-buffer)
 
1952
  (let ((string (po-extract-unquoted (current-buffer)
1905
1953
                                     po-start-of-msgstr-form
1906
1954
                                     po-end-of-msgstr-form)))
1907
 
    (setq po-msgstr-form-flavor flavor)
1908
1955
    string))
1909
1956
 
1910
1957
(defun po-set-msgid (form)
1935
1982
Returns 'nil' if the buffer has not been modified, for if the new msgstr
1936
1983
described by FORM is merely identical to the msgstr already in place."
1937
1984
  (let ((string (po-eval-requoted form
1938
 
                                  po-msgstr-form-flavor
 
1985
                                  (po-get-msgstr-flavor)
1939
1986
                                  (eq po-entry-type 'obsolete))))
1940
1987
    (save-excursion
1941
1988
      (goto-char po-start-of-msgstr-form)
1961
2008
  "Empty the msgstr string from current entry, pushing it on the kill ring."
1962
2009
  (interactive)
1963
2010
  (po-kill-ring-save-msgstr)
1964
 
  (po-set-msgstr-form ""))
 
2011
  (if (po-set-msgstr-form "")
 
2012
      (po-maybe-delete-previous-untranslated)))
1965
2013
 
1966
2014
(defun po-yank-msgstr ()
1967
2015
  "Replace the current msgstr string by the top of the kill ring."
1968
2016
  (interactive)
1969
2017
  (po-find-span-of-entry)
1970
 
  (po-set-msgstr-form (if (eq last-command 'yank) '(yank-pop 1) '(yank)))
 
2018
  (if (po-set-msgstr-form (if (eq last-command 'yank) '(yank-pop 1) '(yank)))
 
2019
      (po-maybe-delete-previous-untranslated))
1971
2020
  (setq this-command 'yank))
1972
2021
 
1973
2022
(defun po-fade-out-entry ()
2090
2139
  (po-set-comment (if (eq last-command 'yank) '(yank-pop 1) '(yank)))
2091
2140
  (setq this-command 'yank)
2092
2141
  (po-redisplay))
2093
 
 
 
2142
 
 
2143
;;; Deleting the "previous untranslated" comment.
 
2144
 
 
2145
(defun po-previous-untranslated-region-for (rx)
 
2146
  "Return the list of previous untranslated regions (at most one) for the
 
2147
given regular expression RX."
 
2148
  (save-excursion
 
2149
    (goto-char po-start-of-entry)
 
2150
    (if (re-search-forward rx po-start-of-msgctxt t)
 
2151
        (list (cons (copy-marker (match-beginning 0))
 
2152
                    (copy-marker (match-end 0))))
 
2153
      nil)))
 
2154
 
 
2155
(defun po-previous-untranslated-regions ()
 
2156
  "Return the list of previous untranslated regions in the current entry."
 
2157
  (append (po-previous-untranslated-region-for po-any-previous-msgctxt-regexp)
 
2158
          (po-previous-untranslated-region-for po-any-previous-msgid-regexp)
 
2159
          (po-previous-untranslated-region-for po-any-previous-msgid_plural-regexp)))
 
2160
 
 
2161
(defun po-delete-previous-untranslated ()
 
2162
  "Delete the previous msgctxt, msgid, msgid_plural fields (marked as #|
 
2163
comments) from the current entry."
 
2164
  (interactive)
 
2165
  (po-find-span-of-entry)
 
2166
  (let ((buffer-read-only po-read-only))
 
2167
    (dolist (region (po-previous-untranslated-regions))
 
2168
      (delete-region (car region) (cdr region))))
 
2169
  (po-redisplay))
 
2170
 
 
2171
(defun po-maybe-delete-previous-untranslated ()
 
2172
  "Delete the previous msgctxt, msgid, msgid_plural fields (marked as #|
 
2173
comments) from the current entry, if the user gives the permission."
 
2174
  (po-find-span-of-entry)
 
2175
  (let ((previous-regions (po-previous-untranslated-regions)))
 
2176
    (if previous-regions
 
2177
        (if (or (eq po-auto-delete-previous-msgid t)
 
2178
                (and (eq po-auto-delete-previous-msgid 'ask)
 
2179
                     (let ((overlays nil))
 
2180
                       (unwind-protect
 
2181
                           (progn
 
2182
                             (setq overlays
 
2183
                                   (mapcar (function
 
2184
                                             (lambda (region)
 
2185
                                               (let ((overlay (po-create-overlay)))
 
2186
                                                 (po-highlight overlay (car region) (cdr region))
 
2187
                                                 overlay)))
 
2188
                                           previous-regions))
 
2189
                             ;; Scroll, to show the previous-regions.
 
2190
                             (goto-char (car (car previous-regions)))
 
2191
                             (prog1 (y-or-n-p (_"Delete previous msgid comments? "))
 
2192
                                    (message "")))
 
2193
                         (mapc 'po-dehighlight overlays)))))
 
2194
            (let ((buffer-read-only po-read-only))
 
2195
              (dolist (region previous-regions)
 
2196
                (delete-region (car region) (cdr region))))))))
 
2197
 
2094
2198
;;; Editing management and submode.
2095
2199
 
2096
2200
;; In a string edit buffer, BACK-POINTER points to one of the slots of the
2213
2317
          (erase-buffer)
2214
2318
          (insert-buffer-substring oldbuf start-1 end-1)
2215
2319
          (setq buffer-read-only t))
2216
 
        
 
2320
 
2217
2321
        (setq start-2 (point))
2218
2322
        (save-excursion
2219
2323
          ;; check for a third variant; if found ignore it
2265
2369
           (po-set-comment string)
2266
2370
           (po-redisplay))
2267
2371
          ((= (point) po-start-of-msgstr-form)
2268
 
           (let ((replaced (po-set-msgstr-form string)))
2269
 
             (if (and replaced
2270
 
                      po-auto-fuzzy-on-edit
2271
 
                      (eq po-entry-type 'translated))
2272
 
                 (progn
2273
 
                   (po-decrease-type-counter)
2274
 
                   (po-add-attribute "fuzzy")
2275
 
                   (po-current-entry)
2276
 
                   (po-increase-type-counter)))))
 
2372
           (if (po-set-msgstr-form string)
 
2373
               (progn
 
2374
                 (po-maybe-delete-previous-untranslated)
 
2375
                 (if (and po-auto-fuzzy-on-edit
 
2376
                          (eq po-entry-type 'translated))
 
2377
                     (progn
 
2378
                       (po-decrease-type-counter)
 
2379
                       (po-add-attribute "fuzzy")
 
2380
                       (po-current-entry)
 
2381
                       (po-increase-type-counter))))))
2277
2382
          (t (debug)))))
2278
2383
 
2279
2384
(defun po-edit-string (string type expand-tabs)
2304
2409
          (setq slot (list marker edit-buffer overlay)
2305
2410
                po-edited-fields (cons slot po-edited-fields))
2306
2411
          (pop-to-buffer edit-buffer)
 
2412
          (text-mode)
2307
2413
          (set (make-local-variable 'po-subedit-back-pointer) slot)
2308
2414
          (set (make-local-variable 'indent-line-function)
2309
2415
               'indent-relative)
2328
2434
  (interactive)
2329
2435
  (po-find-span-of-entry)
2330
2436
  (po-edit-string (po-get-comment nil) 'comment nil))
2331
 
  
 
2437
 
2332
2438
(defun po-edit-comment-and-ediff ()
2333
2439
  "Use `ediff' to edit the current translator comment.
2334
2440
This function calls `po-edit-msgstr' and `po-subedit-ediff'; for more info
3451
3557
;; Hey Emacs!
3452
3558
;; Local Variables:
3453
3559
;; indent-tabs-mode: nil
 
3560
;; coding: utf-8
3454
3561
;; End:
3455
3562
 
3456
3563
;;; po-mode.el ends here