Hello community,

here is the log from the commit of package i18nspector for openSUSE:Factory 
checked in at 2014-08-03 07:50:40
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/i18nspector (Old)
 and      /work/SRC/openSUSE:Factory/.i18nspector.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "i18nspector"

Changes:
--------
--- /work/SRC/openSUSE:Factory/i18nspector/i18nspector.changes  2014-07-12 
17:15:01.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.i18nspector.new/i18nspector.changes     
2014-08-03 07:50:43.000000000 +0200
@@ -1,0 +2,14 @@
+Mon Jul 21 11:58:41 UTC 2014 - lazy.k...@opensuse.org
+
+- Update to 0.14.
+  * Summary of tag changes:
+    + Added:
+      - translation-in-template
+  * Check for PO template files containing translated messages.
+  * Check for duplicate messages, for problems with message flags,
+    and for empty files even when encoding is broken or unknown.
+  * Check for inconsistent leading/trailing newlines between msgid
+    and msgid_plural even when encoding in unknown or broken.
+  * Improve the test suite.
+
+-------------------------------------------------------------------

Old:
----
  i18nspector-0.13.5.tar.gz
  i18nspector-0.13.5.tar.gz.asc

New:
----
  i18nspector-0.14.tar.gz
  i18nspector-0.14.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ i18nspector.spec ++++++
--- /var/tmp/diff_new_pack.PCFrMZ/_old  2014-08-03 07:50:44.000000000 +0200
+++ /var/tmp/diff_new_pack.PCFrMZ/_new  2014-08-03 07:50:44.000000000 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           i18nspector
-Version:        0.13.5
+Version:        0.14
 Release:        0
 Summary:        Tool for Checking gettext POT/PO/MO Files
 License:        MIT

++++++ i18nspector-0.13.5.tar.gz -> i18nspector-0.14.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/data/tags 
new/i18nspector-0.14/data/tags
--- old/i18nspector-0.13.5/data/tags    2014-07-07 15:08:07.000000000 +0200
+++ new/i18nspector-0.14/data/tags      2014-07-16 15:28:57.000000000 +0200
@@ -655,6 +655,12 @@
 references =
  https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
 
+[translation-in-template]
+severity = minor
+certainty = certain
+description =
+ The PO template file contains a translated message.
+
 [unable-to-determine-language]
 severity = normal
 certainty = wild-guess
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/doc/changelog 
new/i18nspector-0.14/doc/changelog
--- old/i18nspector-0.13.5/doc/changelog        2014-07-07 15:08:07.000000000 
+0200
+++ new/i18nspector-0.14/doc/changelog  2014-07-16 15:28:57.000000000 +0200
@@ -1,3 +1,18 @@
+i18nspector (0.14) unstable; urgency=low
+
+  * Summary of tag changes:
+    + Added:
+      - translation-in-template
+
+  * Check for PO template files containing translated messages.
+  * Check for duplicate messages, for problems with message flags, and for
+    empty files even when encoding is broken or unknown.
+  * Check for inconsistent leading/trailing newlines between msgid and
+    msgid_plural even when encoding in unknown or broken.
+  * Improve the test suite.
+
+ -- Jakub Wilk <jw...@jwilk.net>  Wed, 16 Jul 2014 15:28:40 +0200
+
 i18nspector (0.13.5) unstable; urgency=low
 
   * Use HTTPS URLs when they are available, in documentation and code.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/doc/i18nspector.1 
new/i18nspector-0.14/doc/i18nspector.1
--- old/i18nspector-0.13.5/doc/i18nspector.1    2014-07-07 15:08:08.000000000 
+0200
+++ new/i18nspector-0.14/doc/i18nspector.1      2014-07-16 15:28:58.000000000 
+0200
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH I18NSPECTOR 1 "2014-07-07" "i18nspector 0.13.5" ""
+.TH I18NSPECTOR 1 "2014-07-16" "i18nspector 0.14" ""
 .SH NAME
 i18nspector \- checking tool for gettext POT, PO and MO files
 .
@@ -1297,6 +1297,16 @@
 important, possible
 .UNINDENT
 .UNINDENT
+.SS translation\-in\-template
+.sp
+The PO template file contains a translated message.
+.sp
+Severity, certainty:
+.INDENT 0.0
+.INDENT 3.5
+minor, certain
+.UNINDENT
+.UNINDENT
 .SS unable\-to\-determine\-language
 .sp
 i18nspector was unable to determine language of this file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/doc/i18nspector.txt 
new/i18nspector-0.14/doc/i18nspector.txt
--- old/i18nspector-0.13.5/doc/i18nspector.txt  2014-07-07 15:08:07.000000000 
+0200
+++ new/i18nspector-0.14/doc/i18nspector.txt    2014-07-16 15:28:57.000000000 
+0200
@@ -7,7 +7,7 @@
 ----------------------------------------------
 
 :manual section: 1
-:version: i18nspector 0.13.5
+:version: i18nspector 0.14
 :date: |date|
 
 Synopsis
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/doc/tags.txt 
new/i18nspector-0.14/doc/tags.txt
--- old/i18nspector-0.13.5/doc/tags.txt 2014-07-07 15:08:08.000000000 +0200
+++ new/i18nspector-0.14/doc/tags.txt   2014-07-16 15:28:57.000000000 +0200
@@ -922,6 +922,14 @@
 
  important, possible
 
+translation-in-template
+~~~~~~~~~~~~~~~~~~~~~~~
+The PO template file contains a translated message.
+
+Severity, certainty:
+
+ minor, certain
+
 unable-to-determine-language
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 i18nspector was unable to determine language of this file.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/doc/todo.txt 
new/i18nspector-0.14/doc/todo.txt
--- old/i18nspector-0.13.5/doc/todo.txt 2014-07-07 15:08:07.000000000 +0200
+++ new/i18nspector-0.14/doc/todo.txt   2014-07-16 15:28:57.000000000 +0200
@@ -82,8 +82,6 @@
 
 Use `blessings <https://pypi.python.org/pypi/blessings/>`_ for colored output.
 
-Check for POT files containing translations.
-
 Run ``msgfmt --check-format`` on PO files.
 
 Reimplement the EUC-TW codec with PyICU.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/lib/checker.py 
new/i18nspector-0.14/lib/checker.py
--- old/i18nspector-0.13.5/lib/checker.py       2014-07-07 15:08:07.000000000 
+0200
+++ new/i18nspector-0.14/lib/checker.py 2014-07-16 15:28:57.000000000 +0200
@@ -171,23 +171,26 @@
                     broken_encoding.encoding.upper(),
                 )
                 broken_encoding = True
-        # check_headers() modifies the file metadata,
-        # so it has to be the first check:
-        self.check_headers(file, is_template=is_template)
-        language = self.check_language(file, is_template=is_template)
-        self.check_plurals(file, is_template=is_template, language=language)
-        encoding = self.check_mime(file, is_template=is_template, 
language=language)
+        class ctx:
+            pass
+        ctx.file = file
+        ctx.is_template = is_template
+        self.check_headers(ctx)
+        self.check_language(ctx)
+        self.check_plurals(ctx)
+        self.check_mime(ctx)
         if broken_encoding:
-            encoding = None
-        self.check_dates(file, is_template=is_template)
-        self.check_project(file)
-        self.check_translator(file, is_template=is_template)
-        self.check_messages(file, encoding=encoding)
+            ctx.encoding = None
+        self.check_dates(ctx)
+        self.check_project(ctx)
+        self.check_translator(ctx)
+        self.check_messages(ctx)
 
     @checks_header_fields('Language', 'X-Poedit-Language', 'X-Poedit-Country')
-    def check_language(self, file, *, is_template):
+    def check_language(self, ctx):
+        ctx.language = None
         duplicate_meta_language = False
-        meta_languages = file.metadata['Language']
+        meta_languages = ctx.metadata['Language']
         if len(meta_languages) > 1:
             self.tag('duplicate-header-field-language')
             meta_languages = sorted(set(meta_languages))
@@ -198,7 +201,7 @@
         else:
             meta_language = None
         orig_meta_language = meta_language
-        if is_template:
+        if ctx.is_template:
             if meta_language is None:
                 self.tag('no-language-header-field')
             return
@@ -285,11 +288,11 @@
                     '!=',
                     meta_language, tags.safestr('(Language header field)')
                 )
-        poedit_languages = file.metadata['X-Poedit-Language']
+        poedit_languages = ctx.metadata['X-Poedit-Language']
         if len(poedit_languages) > 1:
             self.tag('duplicate-header-field-x-poedit', 'X-Poedit-Language')
             poedit_languages = sorted(set(poedit_languages))
-        poedit_countries = file.metadata['X-Poedit-Country']
+        poedit_countries = ctx.metadata['X-Poedit-Country']
         if len(poedit_countries) > 1:
             self.tag('duplicate-header-field-x-poedit', 'X-Poedit-Country')
             poedit_countries = sorted(set(poedit_countries))
@@ -317,11 +320,11 @@
             return
         if not orig_meta_language and not duplicate_meta_language:
             self.tag('no-language-header-field', tags.safestr('Language:'), 
language)
-        return language
+        ctx.language = language
 
     @checks_header_fields('Plural-Forms')
-    def check_plurals(self, file, *, is_template, language):
-        plural_forms = file.metadata['Plural-Forms']
+    def check_plurals(self, ctx):
+        plural_forms = ctx.metadata['Plural-Forms']
         if len(plural_forms) > 1:
             self.tag('duplicate-header-field-plural-forms')
             plural_forms = sorted(set(plural_forms))
@@ -333,11 +336,11 @@
             assert len(plural_forms) == 0
             plural_forms = None
         correct_plural_forms = None
-        if language is not None:
-            correct_plural_forms = language.get_plural_forms()
+        if ctx.language is not None:
+            correct_plural_forms = ctx.language.get_plural_forms()
         has_plurals = False  # messages with plural forms (translated or not)?
         expected_nplurals = {}  # number of plurals in _translated_ messages
-        for message in file:
+        for message in ctx.file:
             if message.obsolete:
                 continue
             if message.msgid_plural:
@@ -352,7 +355,7 @@
             for n, message in sorted(expected_nplurals.items()):
                 args += [n, message_repr(message, template='({})'), '!=']
             self.tag('inconsistent-number-of-plural-forms', *args[:-1])
-        if is_template:
+        if ctx.is_template:
             plural_forms_hint = 'nplurals=INTEGER; plural=EXPRESSION;'
         elif correct_plural_forms:
             plural_forms_hint = tags.safe_format(
@@ -368,7 +371,7 @@
                 else:
                     self.tag('no-plural-forms-header-field', plural_forms_hint)
             return
-        if is_template:
+        if ctx.is_template:
             return
         try:
             (n, expr) = gettext.parse_plural_forms(plural_forms)
@@ -448,9 +451,10 @@
                         self.tag('codomain-error-in-unused-plural-forms', 
message)
 
     @checks_header_fields('MIME-Version', 'Content-Transfer-Encoding', 
'Content-Type')
-    def check_mime(self, file, *, is_template, language):
+    def check_mime(self, ctx):
+        ctx.encoding = None
         # MIME-Version:
-        mime_versions = file.metadata['MIME-Version']
+        mime_versions = ctx.metadata['MIME-Version']
         if len(mime_versions) > 1:
             self.tag('duplicate-header-field-mime-version')
             mime_versions = sorted(set(mime_versions))
@@ -460,7 +464,7 @@
         if len(mime_versions) == 0:
             self.tag('no-mime-version-header-field', 
tags.safestr('MIME-Version: 1.0'))
         # Content-Transfer-Encoding:
-        ctes = file.metadata['Content-Transfer-Encoding']
+        ctes = ctx.metadata['Content-Transfer-Encoding']
         if len(ctes) > 1:
             self.tag('duplicate-header-field-content-transfer-encoding')
             ctes = sorted(set(ctes))
@@ -470,7 +474,7 @@
         if len(ctes) == 0:
             self.tag('no-content-transfer-encoding-header-field', 
tags.safestr('Content-Transfer-Encoding: 8bit'))
         # Content-Type:
-        cts = file.metadata['Content-Type']
+        cts = ctx.metadata['Content-Type']
         if len(cts) > 1:
             self.tag('duplicate-header-field-content-type')
             cts = sorted(set(cts))
@@ -488,7 +492,7 @@
                     is_ascii_compatible = 
encinfo.is_ascii_compatible_encoding(encoding, missing_ok=False)
                 except encinfo.EncodingLookupError:
                     if encoding == 'CHARSET':
-                        if not is_template:
+                        if not ctx.is_template:
                             self.tag('boilerplate-in-content-type', ct)
                     else:
                         self.tag('unknown-encoding', encoding)
@@ -505,8 +509,8 @@
                             encoding = new_encoding
                         else:
                             self.tag('non-portable-encoding', encoding)
-                    if language is not None:
-                        unrepresentable_characters = 
language.get_unrepresentable_characters(encoding)
+                    if ctx.language is not None:
+                        unrepresentable_characters = 
ctx.language.get_unrepresentable_characters(encoding)
                         if unrepresentable_characters:
                             if len(unrepresentable_characters) > 5:
                                 unrepresentable_characters[4:] = ['...']
@@ -520,18 +524,17 @@
             else:
                 self.tag('invalid-content-type', ct, '=>', content_type_hint)
         if len(encodings) == 1:
-            [encoding] = encodings
-            return encoding
+            [ctx.encoding] = encodings
 
     @checks_header_fields('POT-Creation-Date', 'PO-Revision-Date')
-    def check_dates(self, file, *, is_template):
+    def check_dates(self, ctx):
         try:
-            content_type = file.metadata['Content-Type'][0]
+            content_type = ctx.metadata['Content-Type'][0]
         except IndexError:
             content_type = ''
         is_publican = content_type.startswith('application/x-publican;')
         for field in 'POT-Creation-Date', 'PO-Revision-Date':
-            dates = file.metadata[field]
+            dates = ctx.metadata[field]
             if len(dates) > 1:
                 self.tag('duplicate-header-field-date', field)
                 dates = sorted(set(dates))
@@ -539,7 +542,7 @@
                 self.tag('no-date-header-field', field)
                 continue
             for date in dates:
-                if is_template and field.startswith('PO-') and (date == 
gettext.boilerplate_date):
+                if ctx.is_template and field.startswith('PO-') and (date == 
gettext.boilerplate_date):
                     continue
                 if 'T' in date and is_publican:
                     # Publican uses DateTime->now(), which uses the UTC 
timezone by default:
@@ -566,9 +569,9 @@
                     self.tag('ancient-date', tags.safestr(field + ':'), date)
 
     @checks_header_fields('Project-Id-Version', 'Report-Msgid-Bugs-To')
-    def check_project(self, file):
+    def check_project(self, ctx):
         # Project-Id-Version:
-        project_id_versions = file.metadata['Project-Id-Version']
+        project_id_versions = ctx.metadata['Project-Id-Version']
         if len(project_id_versions) > 1:
             self.tag('duplicate-header-field-project-id-version')
             project_id_versions = sorted(set(project_id_versions))
@@ -578,12 +581,12 @@
             if project_id_version in {'PACKAGE VERSION', 'PROJECT VERSION'}:
                 self.tag('boilerplate-in-project-id-version', 
project_id_version)
             else:
-                if not re.compile(r'[^_\d\W]', 
re.UNICODE).search(project_id_version):
+                if not re.compile(r'[^_\d\W]').search(project_id_version):
                     self.tag('no-package-name-in-project-id-version', 
project_id_version)
                 if not re.search(r'[0-9]', project_id_version):
                     self.tag('no-version-in-project-id-version', 
project_id_version)
         # Report-Msgid-Bugs-To:
-        report_msgid_bugs_tos = file.metadata['Report-Msgid-Bugs-To']
+        report_msgid_bugs_tos = ctx.metadata['Report-Msgid-Bugs-To']
         if len(report_msgid_bugs_tos) > 1:
             self.tag('duplicate-header-field-report-msgid-bugs-to')
             report_msgid_bugs_tos = sorted(set(report_msgid_bugs_tos))
@@ -603,9 +606,9 @@
                 self.tag('boilerplate-in-report-msgid-bugs-to', 
report_msgid_bugs_to)
 
     @checks_header_fields('Last-Translator', 'Language-Team')
-    def check_translator(self, file, *, is_template):
+    def check_translator(self, ctx):
         # Last-Translator:
-        translators = file.metadata['Last-Translator']
+        translators = ctx.metadata['Last-Translator']
         if len(translators) > 1:
             self.tag('duplicate-header-field-last-translator')
             translators = sorted(set(translators))
@@ -620,10 +623,10 @@
             elif domains.is_email_in_special_domain(translator_email):
                 self.tag('invalid-last-translator', translator)
             elif translator_email == 'EMAIL@ADDRESS':
-                if not is_template:
+                if not ctx.is_template:
                     self.tag('boilerplate-in-last-translator', translator)
         # Language-Team:
-        teams = file.metadata['Language-Team']
+        teams = ctx.metadata['Language-Team']
         if len(teams) > 1:
             self.tag('duplicate-header-field-language-team')
             teams = sorted(set(teams))
@@ -638,18 +641,18 @@
             elif domains.is_email_in_special_domain(team_email):
                 self.tag('invalid-language-team', team)
             elif team_email in {'l...@li.org', 'EMAIL@ADDRESS'}:
-                if not is_template:
+                if not ctx.is_template:
                     self.tag('boilerplate-in-language-team', team)
             else:
                 if team_email in translator_emails:
                     self.tag('language-team-equal-to-last-translator', team, 
translator)
 
-    def check_headers(self, file, *, is_template):
+    def check_headers(self, ctx):
         metadata = collections.defaultdict(list)
         strays = []
-        file.header_entry = None
+        ctx.file.header_entry = None
         seen_header_entry = False
-        for entry in file:
+        for entry in ctx.file:
             if not is_header_entry(entry) or entry.obsolete:
                 continue
             if seen_header_entry:
@@ -675,7 +678,7 @@
             flags = collections.Counter(resplit_flags(entry.flags))
             for flag, n in sorted(flags.items()):
                 if flag == 'fuzzy':
-                    if not is_template:
+                    if not ctx.is_template:
                         self.tag('fuzzy-header-entry')
                 elif difflib.get_close_matches(flag.lower(), ['fuzzy'], 
cutoff=0.8):
                     self.tag('unexpected-flag-for-header-entry', flag, '=>', 
'fuzzy')
@@ -683,7 +686,7 @@
                     self.tag('unexpected-flag-for-header-entry', flag)
                 if n > 1:
                     self.tag('duplicate-flag-for-header-entry', flag)
-            if entry is not file[0]:
+            if entry is not ctx.file[0]:
                 self.tag('distant-header-entry')
             unusual_chars = set(find_unusual_characters(msgstr))
             if unusual_chars:
@@ -719,119 +722,34 @@
                         self.tag('unknown-header-field', key, '=>', hint)
             if len(values) > 1 and key not in 
header_fields_with_dedicated_checks:
                 self.tag('duplicate-header-field', key)
-        file.metadata = metadata
-        del file.metadata_is_fuzzy
+        ctx.metadata = metadata
+        del ctx.file.metadata
+        del ctx.file.metadata_is_fuzzy
 
-    def check_messages(self, file, *, encoding):
-        if encoding is None:
-            return
+    def check_messages(self, ctx):
         found_unusual_characters = set()
         msgid_counter = collections.Counter()
-        messages = [msg for msg in file if not is_header_entry(msg)]
+        messages = [msg for msg in ctx.file if not is_header_entry(msg)]
         for message in messages:
             if message.obsolete:
                 continue
             if is_header_entry(message):
                 continue
-            flags = collections.Counter(resplit_flags(message.flags))
-            fuzzy = False
-            wrap = None
-            format_flags = collections.defaultdict(dict)
-            for flag, n in sorted(flags.items()):
-                known_flag = True
-                if flag == 'fuzzy':
-                    fuzzy = True
-                elif flag in {'wrap', 'no-wrap'}:
-                    new_wrap = flag == 'wrap'
-                    if wrap == (not new_wrap):
-                        self.tag('conflicting-message-flags',
-                            message_repr(message, template='{}:'),
-                            'wrap', 'no-wrap'
-                        )
-                    else:
-                        wrap = new_wrap
-                elif flag.startswith('range:'):
-                    if not message.msgid_plural:
-                        self.tag('range-flag-without-plural-string')
-                    match = re.match('([0-9]+)[.][.]([0-9]+)', 
flag[6:].strip(' \t\r\f\v'))
-                    if match is not None:
-                        i, j = map(int, match.groups())
-                        if i >= j:
-                            match = None
-                    if match is None:
-                        self.tag('invalid-range-flag',
-                            message_repr(message, template='{}:'),
-                            flag
-                        )
-                elif flag.endswith('-format'):
-                    known_flag = False
-                    for prefix in 'no-', 'possible-', 'impossible-', '':
-                        tp = prefix.rstrip('-')
-                        if not flag.startswith(prefix):
-                            continue
-                        string_format = flag[len(prefix):-7]
-                        if string_format in gettext.string_formats:
-                            known_flag = True
-                            format_flags[tp][string_format] = flag
-                            break
-                else:
-                    known_flag = False
-                if not known_flag:
-                    self.tag('unknown-message-flag',
-                        message_repr(message, template='{}:'),
-                        flag
-                    )
-                if n > 1 and flag:
-                    self.tag('duplicate-message-flag',
-                        message_repr(message, template='{}:'),
-                        flag
-                    )
-            positive_format_flags = format_flags['']
-            if len(positive_format_flags) > 1:
-                self.tag('conflicting-message-flags',
-                    message_repr(message, template='{}:'),
-                    *sorted(positive_format_flags.values())
-                )
-            elif len(positive_format_flags) == 1:
-                [[positive_format, positive_format_flag]] = 
positive_format_flags.items()
-                negative_format_flags = sorted(
-                    format_flag
-                    for fmt, format_flag in
-                    format_flags['no'].items()
-                    if fmt != positive_format
-                )
-                if negative_format_flags:
-                    args = (
-                        negative_format_flags +
-                        [tags.safe_format('(implied by 
{flag})'.format(flag=positive_format_flag))]
-                    )
-                    self.tag('redundant-message-flag',
-                        message_repr(message, template='{}:'),
-                        *args
-                    )
-            for positive_key, negative_key in [('', 'no'), ('', 'impossible'), 
('possible', 'impossible')]:
-                positive_format_flags = format_flags[positive_key]
-                negative_format_flags = format_flags[negative_key]
-                conflicting_formats = frozenset(positive_format_flags) & 
frozenset(negative_format_flags)
-                for fmt in sorted(conflicting_formats):
-                    self.tag('conflicting-message-flags',
-                        message_repr(message, template='{}:'),
-                        positive_format_flags[fmt],
-                        negative_format_flags[fmt],
-                    )
-            positive_format_flags = format_flags['']
-            possible_format_flags = format_flags['possible']
-            redundant_formats = frozenset(positive_format_flags) & 
frozenset(possible_format_flags)
-            for fmt in sorted(redundant_formats):
-                self.tag('redundant-message-flag',
-                    message_repr(message, template='{}:'),
-                    possible_format_flags[fmt],
-                    tags.safe_format('(implied by 
{flag})'.format(flag=positive_format_flags[fmt]))
+            fuzzy = self._check_message_flags(message)
+            msgid_counter[message.msgid, message.msgctxt] += 1
+            if msgid_counter[message.msgid, message.msgctxt] == 2:
+                self.tag('duplicate-message-definition', message_repr(message))
+            if ctx.is_template:
+                has_translations = (
+                    message.msgstr or
+                    any(message.msgstr_plural.values())
                 )
+                if has_translations:
+                    self.tag('translation-in-template', message_repr(message))
             leading_lf = message.msgid.startswith('\n')
             trailing_lf = message.msgid.endswith('\n')
             strings = [message.msgid_plural]
-            if not fuzzy:
+            if (not fuzzy) and (ctx.encoding is not None):
                 strings += [message.msgstr]
                 strings += message.msgstr_plural.values()
             strings = [s for s in strings if s != '']
@@ -843,6 +761,8 @@
                 if s.endswith('\n') != trailing_lf:
                     self.tag('inconsistent-trailing-newlines', 
message_repr(message))
                     break
+            if ctx.encoding is None:
+                continue
             msgid_uc = (
                 set(find_unusual_characters(message.msgid)) |
                 set(find_unusual_characters(message.msgid_plural))
@@ -864,16 +784,111 @@
                     if conflict_marker is not None:
                         conflict_marker = conflict_marker.group(0)
                         self.tag('conflict-marker-in-translation', 
message_repr(message), conflict_marker)
-            msgid_counter[message.msgid, message.msgctxt] += 1
-            if msgid_counter[message.msgid, message.msgctxt] == 2:
-                self.tag('duplicate-message-definition', message_repr(message))
         if len(msgid_counter) == 0:
             possible_hidden_strings = False
-            if isinstance(file, polib.MOFile):
-                possible_hidden_strings = file.possible_hidden_strings
+            if isinstance(ctx.file, polib.MOFile):
+                possible_hidden_strings = ctx.file.possible_hidden_strings
             if not possible_hidden_strings:
                 self.tag('empty-file')
 
+    def _check_message_flags(self, message):
+        flags = collections.Counter(resplit_flags(message.flags))
+        fuzzy = False
+        wrap = None
+        format_flags = collections.defaultdict(dict)
+        for flag, n in sorted(flags.items()):
+            known_flag = True
+            if flag == 'fuzzy':
+                fuzzy = True
+            elif flag in {'wrap', 'no-wrap'}:
+                new_wrap = flag == 'wrap'
+                if wrap == (not new_wrap):
+                    self.tag('conflicting-message-flags',
+                        message_repr(message, template='{}:'),
+                        'wrap', 'no-wrap'
+                    )
+                else:
+                    wrap = new_wrap
+            elif flag.startswith('range:'):
+                if not message.msgid_plural:
+                    self.tag('range-flag-without-plural-string')
+                match = re.match('([0-9]+)[.][.]([0-9]+)', flag[6:].strip(' 
\t\r\f\v'))
+                if match is not None:
+                    i, j = map(int, match.groups())
+                    if i >= j:
+                        match = None
+                if match is None:
+                    self.tag('invalid-range-flag',
+                        message_repr(message, template='{}:'),
+                        flag
+                    )
+            elif flag.endswith('-format'):
+                known_flag = False
+                for prefix in 'no-', 'possible-', 'impossible-', '':
+                    tp = prefix.rstrip('-')
+                    if not flag.startswith(prefix):
+                        continue
+                    string_format = flag[len(prefix):-7]
+                    if string_format in gettext.string_formats:
+                        known_flag = True
+                        format_flags[tp][string_format] = flag
+                        break
+            else:
+                known_flag = False
+            if not known_flag:
+                self.tag('unknown-message-flag',
+                    message_repr(message, template='{}:'),
+                    flag
+                )
+            if n > 1 and flag:
+                self.tag('duplicate-message-flag',
+                    message_repr(message, template='{}:'),
+                    flag
+                )
+        positive_format_flags = format_flags['']
+        if len(positive_format_flags) > 1:
+            self.tag('conflicting-message-flags',
+                message_repr(message, template='{}:'),
+                *sorted(positive_format_flags.values())
+            )
+        elif len(positive_format_flags) == 1:
+            [[positive_format, positive_format_flag]] = 
positive_format_flags.items()
+            negative_format_flags = sorted(
+                format_flag
+                for fmt, format_flag in
+                format_flags['no'].items()
+                if fmt != positive_format
+            )
+            if negative_format_flags:
+                args = (
+                    negative_format_flags +
+                    [tags.safe_format('(implied by 
{flag})'.format(flag=positive_format_flag))]
+                )
+                self.tag('redundant-message-flag',
+                    message_repr(message, template='{}:'),
+                    *args
+                )
+        for positive_key, negative_key in [('', 'no'), ('', 'impossible'), 
('possible', 'impossible')]:
+            positive_format_flags = format_flags[positive_key]
+            negative_format_flags = format_flags[negative_key]
+            conflicting_formats = frozenset(positive_format_flags) & 
frozenset(negative_format_flags)
+            for fmt in sorted(conflicting_formats):
+                self.tag('conflicting-message-flags',
+                    message_repr(message, template='{}:'),
+                    positive_format_flags[fmt],
+                    negative_format_flags[fmt],
+                )
+        positive_format_flags = format_flags['']
+        possible_format_flags = format_flags['possible']
+        redundant_formats = frozenset(positive_format_flags) & 
frozenset(possible_format_flags)
+        for fmt in sorted(redundant_formats):
+            self.tag('redundant-message-flag',
+                message_repr(message, template='{}:'),
+                possible_format_flags[fmt],
+                tags.safe_format('(implied by 
{flag})'.format(flag=positive_format_flags[fmt]))
+            )
+        return fuzzy
+
 __all__ = ['Checker']
 
 def is_header_entry(entry):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/lib/cli.py 
new/i18nspector-0.14/lib/cli.py
--- old/i18nspector-0.13.5/lib/cli.py   2014-07-07 15:08:07.000000000 +0200
+++ new/i18nspector-0.14/lib/cli.py     2014-07-16 15:28:57.000000000 +0200
@@ -37,7 +37,7 @@
 from . import tags
 from . import terminal
 
-__version__ = '0.13.5'
+__version__ = '0.14'
 
 def initialize_terminal():
     if sys.stdout.isatty():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/i18nspector-0.13.5/tests/blackbox_tests/coverage.txt 
new/i18nspector-0.14/tests/blackbox_tests/coverage.txt
--- old/i18nspector-0.13.5/tests/blackbox_tests/coverage.txt    2014-07-07 
15:08:07.000000000 +0200
+++ new/i18nspector-0.14/tests/blackbox_tests/coverage.txt      2014-07-16 
15:28:57.000000000 +0200
@@ -79,6 +79,7 @@
 [X] syntax-error-in-plural-forms
 [X] syntax-error-in-po-file
 [X] syntax-error-in-unused-plural-forms
+[X] translation-in-template
 [X] unable-to-determine-language
 [X] unexpected-flag-for-header-entry
 [X] unknown-encoding
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/duplicate-flag-for-header-entry.pot 
new/i18nspector-0.14/tests/blackbox_tests/duplicate-flag-for-header-entry.pot
--- 
old/i18nspector-0.13.5/tests/blackbox_tests/duplicate-flag-for-header-entry.pot 
    2014-07-07 15:08:07.000000000 +0200
+++ 
new/i18nspector-0.14/tests/blackbox_tests/duplicate-flag-for-header-entry.pot   
    2014-07-16 15:28:57.000000000 +0200
@@ -6,13 +6,13 @@
 "Project-Id-Version: Gizmo Enhancer 1.0\n"
 "Report-Msgid-Bugs-To: gizmoenhan...@jwilk.net\n"
 "POT-Creation-Date: 2012-11-01 14:42+0100\n"
-"PO-Revision-Date: 2012-11-01 14:42+0100\n"
-"Last-Translator: Jakub Wilk <jw...@jwilk.net>\n"
-"Language-Team: Latin <l...@li.org>\n"
-"Language: la\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <l...@li.org>\n"
+"Language: \n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
 msgid "A quick brown fox jumps over the lazy dog."
-msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis."
+msgstr ""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/empty-file.pot 
new/i18nspector-0.14/tests/blackbox_tests/empty-file.pot
--- old/i18nspector-0.13.5/tests/blackbox_tests/empty-file.pot  1970-01-01 
01:00:00.000000000 +0100
+++ new/i18nspector-0.14/tests/blackbox_tests/empty-file.pot    2014-07-16 
15:28:57.000000000 +0200
@@ -0,0 +1,15 @@
+# W: empty-file
+
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Gizmo Enhancer 1.0\n"
+"Report-Msgid-Bugs-To: gizmoenhan...@jwilk.net\n"
+"POT-Creation-Date: 2012-11-01 14:42+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <l...@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-leading-newlines-fuzzy.po
 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-leading-newlines-fuzzy.po
--- 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-leading-newlines-fuzzy.po
  2014-07-07 15:08:07.000000000 +0200
+++ 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-leading-newlines-fuzzy.po
    2014-07-16 15:28:57.000000000 +0200
@@ -12,5 +12,5 @@
 "Content-Transfer-Encoding: 8bit\n"
 
 #, fuzzy
-msgid "A quick brown fox jumps over the lazy dog."
-msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n"
+msgid "\nA quick brown fox jumps over the lazy dog."
+msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-leading-newlines.po 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-leading-newlines.po
--- 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-leading-newlines.po    
    2014-07-07 15:08:07.000000000 +0200
+++ new/i18nspector-0.14/tests/blackbox_tests/inconsistent-leading-newlines.po  
2014-07-16 15:28:57.000000000 +0200
@@ -1,4 +1,4 @@
-# E: inconsistent-trailing-newlines msgid 'A quick brown fox jumps over the 
lazy dog.'
+# E: inconsistent-leading-newlines msgid '\nA quick brown fox jumps over the 
lazy dog.'
 
 msgid ""
 msgstr ""
@@ -13,5 +13,5 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-msgid "A quick brown fox jumps over the lazy dog."
-msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n"
+msgid "\nA quick brown fox jumps over the lazy dog."
+msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-leading-newlines.pot 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-leading-newlines.pot
--- 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-leading-newlines.pot   
    1970-01-01 01:00:00.000000000 +0100
+++ new/i18nspector-0.14/tests/blackbox_tests/inconsistent-leading-newlines.pot 
2014-07-16 15:28:57.000000000 +0200
@@ -0,0 +1,20 @@
+# E: inconsistent-leading-newlines msgid '\n%d quick brown fox jumps over the 
lazy dog.'
+
+msgid ""
+msgstr ""
+"Project-Id-Version: Gizmo Enhancer 1.0\n"
+"Report-Msgid-Bugs-To: gizmoenhan...@jwilk.net\n"
+"POT-Creation-Date: 2012-11-01 14:42+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <l...@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+msgid "\n%d quick brown fox jumps over the lazy dog."
+msgid_plural "%d quick brown foxes jump over the lazy dog."
+msgstr[0] ""
+msgstr[1] ""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-trailing-newlines-fuzzy.po
 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-trailing-newlines-fuzzy.po
--- 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-trailing-newlines-fuzzy.po
 2014-07-07 15:08:07.000000000 +0200
+++ 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-trailing-newlines-fuzzy.po
   2014-07-16 15:28:57.000000000 +0200
@@ -12,5 +12,5 @@
 "Content-Transfer-Encoding: 8bit\n"
 
 #, fuzzy
-msgid "\nA quick brown fox jumps over the lazy dog."
-msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis."
+msgid "A quick brown fox jumps over the lazy dog."
+msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-trailing-newlines.po 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-trailing-newlines.po
--- 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-trailing-newlines.po   
    2014-07-07 15:08:07.000000000 +0200
+++ new/i18nspector-0.14/tests/blackbox_tests/inconsistent-trailing-newlines.po 
2014-07-16 15:28:57.000000000 +0200
@@ -1,4 +1,4 @@
-# E: inconsistent-leading-newlines msgid '\nA quick brown fox jumps over the 
lazy dog.'
+# E: inconsistent-trailing-newlines msgid 'A quick brown fox jumps over the 
lazy dog.'
 
 msgid ""
 msgstr ""
@@ -13,5 +13,5 @@
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-msgid "\nA quick brown fox jumps over the lazy dog."
-msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis."
+msgid "A quick brown fox jumps over the lazy dog."
+msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-trailing-newlines.pot 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-trailing-newlines.pot
--- 
old/i18nspector-0.13.5/tests/blackbox_tests/inconsistent-trailing-newlines.pot  
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/i18nspector-0.14/tests/blackbox_tests/inconsistent-trailing-newlines.pot    
    2014-07-16 15:28:57.000000000 +0200
@@ -0,0 +1,20 @@
+# E: inconsistent-trailing-newlines msgid '%d quick brown fox jumps over the 
lazy dog.'
+
+msgid ""
+msgstr ""
+"Project-Id-Version: Gizmo Enhancer 1.0\n"
+"Report-Msgid-Bugs-To: gizmoenhan...@jwilk.net\n"
+"POT-Creation-Date: 2012-11-01 14:42+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <l...@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+msgid "%d quick brown fox jumps over the lazy dog."
+msgid_plural "%d quick brown foxes jump over the lazy dog.\n"
+msgstr[0] ""
+msgstr[1] ""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/no-plural-forms.pot 
new/i18nspector-0.14/tests/blackbox_tests/no-plural-forms.pot
--- old/i18nspector-0.13.5/tests/blackbox_tests/no-plural-forms.pot     
2014-07-07 15:08:08.000000000 +0200
+++ new/i18nspector-0.14/tests/blackbox_tests/no-plural-forms.pot       
2014-07-16 15:28:57.000000000 +0200
@@ -10,7 +10,7 @@
 "Language-Team: LANGUAGE <l...@li.org>\n"
 "Language: \n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 
 msgid "%d quick brown fox jumps over the lazy dog."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/plural-forms-okay.pot 
new/i18nspector-0.14/tests/blackbox_tests/plural-forms-okay.pot
--- old/i18nspector-0.13.5/tests/blackbox_tests/plural-forms-okay.pot   
2014-07-07 15:08:08.000000000 +0200
+++ new/i18nspector-0.14/tests/blackbox_tests/plural-forms-okay.pot     
2014-07-16 15:28:57.000000000 +0200
@@ -8,7 +8,7 @@
 "Language-Team: LANGUAGE <l...@li.org>\n"
 "Language: \n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Type: text/plain; charset=CHARSET\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/translation-in-template.pot 
new/i18nspector-0.14/tests/blackbox_tests/translation-in-template.pot
--- old/i18nspector-0.13.5/tests/blackbox_tests/translation-in-template.pot     
1970-01-01 01:00:00.000000000 +0100
+++ new/i18nspector-0.14/tests/blackbox_tests/translation-in-template.pot       
2014-07-16 15:28:57.000000000 +0200
@@ -0,0 +1,17 @@
+# W: translation-in-template msgid 'A quick brown fox jumps over the lazy dog.'
+
+msgid ""
+msgstr ""
+"Project-Id-Version: Gizmo Enhancer 1.0\n"
+"Report-Msgid-Bugs-To: gizmoenhan...@jwilk.net\n"
+"POT-Creation-Date: 2012-11-01 14:42+0100\n"
+"PO-Revision-Date: 2012-11-01 14:42+0100\n"
+"Last-Translator: Jakub Wilk <jw...@jwilk.net>\n"
+"Language-Team: Latin <l...@li.org>\n"
+"Language: la\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "A quick brown fox jumps over the lazy dog."
+msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis."
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/i18nspector-0.13.5/tests/blackbox_tests/zero-bytes-file.po.tags 
new/i18nspector-0.14/tests/blackbox_tests/zero-bytes-file.po.tags
--- old/i18nspector-0.13.5/tests/blackbox_tests/zero-bytes-file.po.tags 
2014-07-07 15:08:08.000000000 +0200
+++ new/i18nspector-0.14/tests/blackbox_tests/zero-bytes-file.po.tags   
2014-07-16 15:28:57.000000000 +0200
@@ -9,3 +9,4 @@
 W: no-report-msgid-bugs-to-header-field
 W: no-last-translator-header-field
 P: no-language-team-header-field
+W: empty-file

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to