i18nspector-0.25.5/0000755000000000000000000000000013147102074012147 5ustar0000000000000000i18nspector-0.25.5/tests/0000755000000000000000000000000013147102065013311 5ustar0000000000000000i18nspector-0.25.5/tests/tools.py0000644000000000000000000000707413147102065015033 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import functools import os import sys import tempfile import traceback import nose temporary_file = functools.partial( tempfile.NamedTemporaryFile, prefix='i18nspector.tests.', ) temporary_directory = functools.partial( tempfile.TemporaryDirectory, prefix='i18nspector.tests.', ) class IsolatedError(Exception): pass def _n_relevant_tb_levels(tb): n = 0 while tb and '__unittest' not in tb.tb_frame.f_globals: n += 1 tb = tb.tb_next return n def fork_isolation(f): EXIT_EXCEPTION = 101 EXIT_SKIP_TEST = 102 exit = os._exit # pylint: disable=redefined-builtin,protected-access # sys.exit() can't be used here, because nose catches all exceptions, # including SystemExit @functools.wraps(f) def wrapper(*args, **kwargs): readfd, writefd = os.pipe() pid = os.fork() if pid == 0: # child: os.close(readfd) try: f(*args, **kwargs) except nose.SkipTest as exc: s = str(exc).encode('UTF-8') with os.fdopen(writefd, 'wb') as fp: fp.write(s) exit(EXIT_SKIP_TEST) except Exception: # pylint: disable=broad-except exctp, exc, tb = sys.exc_info() s = traceback.format_exception(exctp, exc, tb, _n_relevant_tb_levels(tb)) s = ''.join(s).encode('UTF-8') del tb with os.fdopen(writefd, 'wb') as fp: fp.write(s) exit(EXIT_EXCEPTION) exit(0) else: # parent: os.close(writefd) with os.fdopen(readfd, 'rb') as fp: msg = fp.read() msg = msg.decode('UTF-8').rstrip('\n') pid, status = os.waitpid(pid, 0) if status == (EXIT_EXCEPTION << 8): raise IsolatedError('\n\n' + msg) elif status == (EXIT_SKIP_TEST << 8): raise nose.SkipTest(msg) elif status == 0 and msg == '': pass else: raise RuntimeError('unexpected isolated process status {}'.format(status)) return wrapper basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) basedir = os.environ.get('I18NSPECTOR_BASEDIR', basedir) basedir = os.path.join(basedir, '') os.stat(basedir) datadir = os.path.join(basedir, 'data') os.stat(datadir) sys.path[:0] = [basedir] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_xml.py0000644000000000000000000000505213147102065015524 0ustar0000000000000000# Copyright © 2014 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import re import xml.etree.ElementTree as etree from nose.tools import ( assert_is_none, assert_is_not_none, assert_raises, ) import lib.xml as M class test_well_formed: def t(self, s): M.check_fragment(s) def test_ok(self): self.t('eggs') self.t('ham spam') def test_unknown_entity(self): self.t('&eggs;') class test_malformed: def t(self, s): with assert_raises(M.SyntaxError): M.check_fragment(s) def test_non_xml_character(self): self.t('\x01') def test_open_tag(self): self.t('ham') def test_closed_tag(self): self.t('eggs') def test_broken_entity(self): self.t('&#eggs;') def test_entity_def(self): s = ( ']>' '&eggs;' ) etree.fromstring(s) self.t(s) class test_name_re(): regexp = re.compile(r'\A{re}\Z'.format(re=M.name_re)) def test_good(self): def t(s): match = self.regexp.match(s) assert_is_not_none(match) t(':') t('_') t('e') t('e0') t('eggs') t('eggs-ham') t('eggs:ham') def test_bad(self): def t(s): match = self.regexp.match(s) assert_is_none(match) t('') t('0') t('-') t('e\N{GREEK QUESTION MARK}') # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_version.py0000644000000000000000000000356713147102065016422 0ustar0000000000000000# Copyright © 2012-2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os from nose.tools import ( assert_equal, ) from lib.cli import __version__ here = os.path.dirname(__file__) docdir = os.path.join(here, os.pardir, 'doc') def test_changelog(): path = os.path.join(docdir, 'changelog') with open(path, 'rt', encoding='UTF-8') as file: line = file.readline() changelog_version = line.split()[1].strip('()') assert_equal(changelog_version, __version__) def test_manpage(): path = os.path.join(docdir, 'i18nspector.txt') manpage_version = None with open(path, 'rt', encoding='UTF-8') as file: for line in file: if line.startswith(':version:'): manpage_version = line.split()[-1] break assert_equal(manpage_version, __version__) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_terminal.py0000644000000000000000000000653413147102065016545 0ustar0000000000000000# Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import functools import os import pty import sys import lib.terminal as T from nose.tools import ( assert_equal, ) from . import tools def test_strip_delay(): def t(s, r=b''): assert_equal(T._strip_delay(s), r) # pylint: disable=protected-access t(b'$<1>') t(b'$<2/>') t(b'$<3*>') t(b'$<4*/>') t(b'$<.5*/>') t(b'$<0.6*>') s = b'$<\x9b20>' t(s, s) def _get_colors(): return ( value for name, value in sorted(vars(T.colors).items()) if name.isalpha() ) def assert_tseq_equal(s, expected): if sys.version_info < (3, 3) and (T._curses is T._dummy_curses): # pylint: disable=protected-access expected = '' class S(str): # assert_equal() does detailed comparison for instances of str, # but not their subclasses. We don't want detailed comparisons, # because diff could contain control characters. pass assert_equal(S(expected), S(s)) def test_dummy(): t = assert_tseq_equal for i in _get_colors(): t(T.attr_fg(i), '') t(T.attr_reset(), '') def pty_fork_isolation(term): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): (master_fd, slave_fd) = pty.openpty() os.dup2(slave_fd, pty.STDOUT_FILENO) os.close(slave_fd) sys.stdout = sys.__stdout__ os.environ['TERM'] = term T.initialize() try: return func(*args, **kwargs) finally: os.close(master_fd) return tools.fork_isolation(wrapper) return decorator @pty_fork_isolation('vt100') def test_vt100(): t = assert_tseq_equal for i in _get_colors(): t(T.attr_fg(i), '') t(T.attr_reset(), '\x1b[m\x0f') @pty_fork_isolation('ansi') def test_ansi(): t = assert_tseq_equal t(T.attr_fg(T.colors.black), '\x1b[30m') t(T.attr_fg(T.colors.red), '\x1b[31m') t(T.attr_fg(T.colors.green), '\x1b[32m') t(T.attr_fg(T.colors.yellow), '\x1b[33m') t(T.attr_fg(T.colors.blue), '\x1b[34m') t(T.attr_fg(T.colors.magenta), '\x1b[35m') t(T.attr_fg(T.colors.cyan), '\x1b[36m') t(T.attr_fg(T.colors.white), '\x1b[37m') t(T.attr_reset(), '\x1b[0;10m') # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_tags.py0000644000000000000000000000632313147102065015664 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import ast import importlib import inspect import pkgutil from nose.tools import ( assert_equal, assert_is_instance, ) import lib.check import lib.tags as M class test_escape: def t(self, s, expected): result = M.safe_format('{}', s) assert_is_instance(result, M.safestr) assert_equal( result, expected ) def test_safe(self): s = 'fox' self.t(s, s) def test_trailing_newline(self): s = 'fox\n' self.t(s, repr(s)) def test_colon(self): s = 'fox:' self.t(s, repr(s)) def test_space(self): s = 'brown fox' self.t(s, repr(s)) def ast_to_tagnames(node): for child in ast.iter_child_nodes(node): for t in ast_to_tagnames(child): yield t ok = ( isinstance(node, ast.Call) and isinstance(node.func, ast.Attribute) and node.func.attr == 'tag' and node.args and isinstance(node.args[0], ast.Str) ) if ok: yield node.args[0].s def test_consistency(): source_tagnames = set() def visit_mod(modname): module = importlib.import_module(modname) source_path = inspect.getsourcefile(module) with open(source_path, 'rt', encoding='UTF-8') as file: source = file.read() node = ast.parse(source, filename=source_path) source_tagnames.update(ast_to_tagnames(node)) visit_mod('lib.check') for _, modname, _ in pkgutil.walk_packages(lib.check.__path__, 'lib.check.'): visit_mod(modname) tagnames = frozenset(tag.name for tag in M.iter_tags()) def test(tag): if tag not in source_tagnames: raise AssertionError('tag never emitted: ' + tag) if tag not in tagnames: raise AssertionError( 'tag missing in data/tags:\n\n' '[{tag}]\n' 'severity = wishlist\n' 'certainty = wild-guess\n' 'description = TODO'.format(tag=tag) ) for tag in sorted(source_tagnames | tagnames): yield test, tag # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_strformat_python.py0000644000000000000000000002107013147102065020344 0ustar0000000000000000# Copyright © 2014-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import struct from nose.tools import ( assert_equal, assert_greater, assert_is_instance, assert_raises, assert_sequence_equal, ) import lib.strformat.python as M def test_SSIZE_MAX(): struct.pack('=i', M.SSIZE_MAX) with assert_raises(struct.error): struct.pack('=i', M.SSIZE_MAX + 1) def test_lone_percent(): with assert_raises(M.Error): M.FormatString('%') def test_invalid_conversion_spec(): with assert_raises(M.Error): M.FormatString('%!') def test_add_argument(): fmt = M.FormatString('%s') with assert_raises(RuntimeError): fmt.add_argument(None, None) with assert_raises(RuntimeError): fmt.add_argument('eggs', None) def test_text(): fmt = M.FormatString('eggs%dbacon%dspam') assert_equal(len(fmt), 5) fmt = list(fmt) assert_equal(fmt[0], 'eggs') assert_equal(fmt[2], 'bacon') assert_equal(fmt[4], 'spam') class test_map: def t(self, key): s = '%(' + key + ')s' fmt = M.FormatString(s) assert_equal(len(fmt), 1) assert_sequence_equal(fmt.seq_arguments, []) [pkey] = fmt.map_arguments.keys() assert_equal(key, pkey) def test_simple(self): self.t('eggs') def test_balanced_parens(self): self.t('eggs(ham)spam') def test_unbalanced_parens(self): with assert_raises(M.Error): self.t('eggs(ham') class test_types: def t(self, s, tp, warn_type=None): fmt = M.FormatString(s) [conv] = fmt assert_is_instance(conv, M.Conversion) assert_equal(conv.type, tp) assert_equal(len(fmt.map_arguments), 0) if tp == 'None': assert_sequence_equal(fmt.seq_arguments, []) else: [arg] = fmt.seq_arguments assert_equal(arg.type, tp) if warn_type is None: assert_equal(len(fmt.warnings), 0) else: [warning] = fmt.warnings assert_is_instance(warning, warn_type) def test_integer(self): t = self.t for c in 'oxXdi': yield t, '%' + c, 'int' yield t, '%u', 'int', M.ObsoleteConversion def test_float(self): t = self.t for c in 'eEfFgG': yield t, '%' + c, 'float' def test_str(self): t = self.t yield t, '%c', 'chr' yield t, '%s', 'str' def test_repr(self): t = self.t for c in 'ra': yield t, '%' + c, 'object' def test_void(self): yield self.t, '%%', 'None' def test_length(): def t(l): fmt = M.FormatString('%' + l + 'd') [warning] = fmt.warnings assert_is_instance(warning, M.RedundantLength) for l in 'hlL': yield t, l class test_indexing: def test_percent(self): with assert_raises(M.ForbiddenArgumentKey): M.FormatString('%(eggs)%') def test_indexing_mixture(self): def t(s): with assert_raises(M.ArgumentIndexingMixture): M.FormatString(s) t('%s%(eggs)s') t('%(eggs)s%s') # TODO: "u" should be everywhere, where "d" is class test_multiple_flags: def t(self, s): fmt = M.FormatString(s) [exc] = fmt.warnings assert_is_instance(exc, M.RedundantFlag) def test_duplicate(self): self.t('%--17d') def test_minus_zero(self): self.t('%-017d') def test_plus_space(self): self.t('%+ d') def test_single_flag(): def t(s, expected): fmt = M.FormatString(s) assert_equal(len(fmt), 1) if expected: assert_sequence_equal(fmt.warnings, []) else: [exc] = fmt.warnings assert_is_instance(exc, M.RedundantFlag) for c in 'dioxXeEfFgGcrsa%': yield t, ('%#' + c), (c in 'oxXeEfFgG') for flag in '0 +': yield t, ('%' + flag + c), (c in 'dioxXeEfFgG') yield t, ('%-' + c), True class test_width: def test_ok(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) assert_sequence_equal(fmt.warnings, []) for c in 'dioxXeEfFgGcrsa%': yield t, ('%1' + c) def test_too_large(self): fmt = M.FormatString('%{0}d'.format(M.SSIZE_MAX)) assert_equal(len(fmt), 1) assert_equal(len(fmt.seq_arguments), 1) assert_equal(len(fmt.map_arguments), 0) with assert_raises(M.WidthRangeError): M.FormatString('%{0}d'.format(M.SSIZE_MAX + 1)) def test_variable(self): fmt = M.FormatString('%*s') assert_equal(len(fmt), 1) assert_equal(len(fmt.map_arguments), 0) [a1, a2] = fmt.seq_arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'str') def test_indexing_mixture(self): def t(s): with assert_raises(M.ArgumentIndexingMixture): M.FormatString(s) t('%*s%(eggs)s') t('%(eggs)s%*s') class test_precision: def test_ok(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) for c in 'dioxXeEfFgGrsa': yield t, ('%.1' + c) def test_redundant_0(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) [warning] = fmt.warnings assert_is_instance(warning, M.RedundantFlag) for c in 'dioxX': yield t, ('%0.1' + c) def test_non_redundant_0(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) assert_sequence_equal(fmt.warnings, []) for c in 'eEfFgG': yield t, ('%0.1' + c) def test_unexpected(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) [warning] = fmt.warnings assert_is_instance(warning, M.RedundantPrecision) for c in 'c%': yield t, ('%.1' + c) def test_too_large(self): fmt = M.FormatString('%.{0}f'.format(M.SSIZE_MAX)) assert_equal(len(fmt), 1) with assert_raises(M.PrecisionRangeError): M.FormatString('%.{0}f'.format(M.SSIZE_MAX + 1)) def test_variable(self): fmt = M.FormatString('%.*f') assert_equal(len(fmt), 1) assert_equal(len(fmt.map_arguments), 0) [a1, a2] = fmt.seq_arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'float') def test_indexing_mixture(self): def t(s): with assert_raises(M.ArgumentIndexingMixture): M.FormatString(s) t('%.*f%(eggs)f') t('%(eggs)f%.*f') class test_type_compatibility: def test_okay(self): def t(s, tp): fmt = M.FormatString(s) assert_equal(len(fmt.seq_arguments), 0) [args] = fmt.map_arguments.values() assert_greater(len(args), 1) for arg in args: assert_equal(arg.type, tp) t('%(eggs)d%(eggs)d', 'int') t('%(eggs)d%(eggs)i', 'int') def test_mismatch(self): def t(s): with assert_raises(M.ArgumentTypeMismatch): M.FormatString(s) t('%(eggs)d%(eggs)s') def test_seq_conversions(): def t(s, n): fmt = M.FormatString(s) assert_equal(len(fmt.seq_conversions), n) for arg in fmt.seq_conversions: assert_is_instance(arg, M.Conversion) t('%d', 1) t('%d%d', 2) t('eggs%dham', 1) t('%(eggs)d', 0) t('%*d', 1) t('%.*d', 1) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_strformat_pybrace.py0000644000000000000000000002215513147102065020455 0ustar0000000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import functools import struct try: import unittest.mock as mock except ImportError: try: import mock except ImportError: mock = None import nose from nose.tools import ( assert_equal, assert_is, assert_is_instance, assert_raises, ) import lib.strformat.pybrace as M def test_SSIZE_MAX(): struct.pack('=i', M.SSIZE_MAX) with assert_raises(struct.error): struct.pack('=i', M.SSIZE_MAX + 1) if mock is not None: small_SSIZE_MAX = mock.patch('lib.strformat.pybrace.SSIZE_MAX', 42) # Setting SSIZE_ARGMAX to a small number makes it possible to test for # a very large number of arguments without running out of memory. else: def small_SSIZE_MAX(func): @functools.wraps(func) def wrapper(*args, **kwargs): del args, kwargs raise nose.SkipTest('mock module missing') return wrapper def test_lone_lcb(): with assert_raises(M.Error): M.FormatString('{') def test_lone_rcb(): with assert_raises(M.Error): M.FormatString('}') def test_invalid_field(): with assert_raises(M.Error): M.FormatString('{@}') def test_add_argument(): fmt = M.FormatString('{}') with assert_raises(RuntimeError): fmt.add_argument(None, None) with assert_raises(RuntimeError): fmt.add_argument('eggs', None) def test_text(): fmt = M.FormatString('eggs{}bacon{}spam') assert_equal(len(fmt), 5) fmt = list(fmt) assert_equal(fmt[0], 'eggs') assert_equal(fmt[2], 'bacon') assert_equal(fmt[4], 'spam') class test_types: def t(self, k, *types): types = frozenset(tp.__name__ for tp in types) fmt = M.FormatString('{:' + k + '}') [fld] = fmt assert_is_instance(fld, M.Field) assert_equal(fld.types, types) assert_equal(len(fmt.argument_map), 1) [(key, [afld])] = fmt.argument_map.items() assert_equal(key, 0) assert_is(fld, afld) def test_default(self): self.t('', int, float, str) def test_s(self): self.t('s', str) def test_int(self): for k in 'bcdoxX': self.t(k, int) def test_n(self): self.t('n', int, float) def test_float(self): for k in 'eEfFgG': self.t(k, float) class test_conversion: def t(self, c, k, *types): types = frozenset(tp.__name__ for tp in types) fmt = M.FormatString('{!' + c + ':' + k + '}') [fld] = fmt assert_is_instance(fld, M.Field) assert_equal(fld.types, types) assert_equal(len(fmt.argument_map), 1) [(key, [afld])] = fmt.argument_map.items() assert_equal(key, 0) assert_is(fld, afld) def test_default(self): for c in 'sra': self.t(c, '', int, float, str) def test_s(self): for c in 'sra': self.t(c, 's', str) def test_numeric(self): for c in 'sra': for k in 'bcdoxXneEfFgG': with assert_raises(M.FormatTypeMismatch): self.t(c, k, int) def test_bad(self): with assert_raises(M.ConversionError): self.t('z', '') class test_numbered_arguments: tp_int = frozenset({'int'}) tp_float = frozenset({'float'}) def t(self, s, *types): fmt = M.FormatString(s) assert_equal(len(fmt), len(types)) assert_equal(len(fmt.argument_map), len(types)) for (key, args), (xkey, xtype) in zip(sorted(fmt.argument_map.items()), enumerate(types)): [arg] = args assert_equal(key, xkey) assert_equal(arg.types, frozenset({xtype.__name__})) def test_unnumbered(self): self.t('{:d}{:f}', int, float) def test_numbered(self): self.t('{0:d}{1:f}', int, float) def test_swapped(self): self.t('{1:d}{0:f}', float, int) def test_mixed(self): with assert_raises(M.ArgumentNumberingMixture): self.t('{0:d}{:f}') with assert_raises(M.ArgumentNumberingMixture): self.t('{:d}{0:f}') def test_numbered_out_of_range(self): def t(i): s = ('{' + str(i) + '}') M.FormatString(s) t(M.SSIZE_MAX) with assert_raises(M.ArgumentRangeError): t(M.SSIZE_MAX + 1) @small_SSIZE_MAX def test_unnumbered_out_of_range(self): def t(i): s = '{}' * i M.FormatString(s) t(M.SSIZE_MAX + 1) with assert_raises(M.ArgumentRangeError): t(M.SSIZE_MAX + 2) class test_named_arguments: def test_good(self): fmt = M.FormatString('{spam}') [fld] = fmt [(aname, [afld])] = fmt.argument_map.items() assert_equal(aname, 'spam') assert_is(fld, afld) def test_bad(self): with assert_raises(M.Error): M.FormatString('{3ggs}') class test_format_spec: def test_bad_char(self): with assert_raises(M.Error): M.FormatString('{:@}') def test_bad_letter(self): with assert_raises(M.Error): M.FormatString('{:Z}') def test_comma(self): def t(k): M.FormatString('{:,' + k + '}') t('') for k in 'bcdoxXeEfFgG': t(k) for k in 'ns': with assert_raises(M.Error): t(k) def test_alt_sign(self): def t(c, k): M.FormatString('{:' + c + k + '}') for c in ' +-#': t(c, '') for k in 'bcdoxXneEfFgG': t(c, k) with assert_raises(M.Error): t(c, 's') def test_align(self): def t(c, k): M.FormatString('{:' + c + k + '}') for c in '<>^': t(c, '') for k in 'bcdoxXneEfFgGs': t(c, k) t(c + '0', k) for c in '=0': t(c, '') for k in 'bcdoxXneEfFgG': t(c, k) with assert_raises(M.Error): t(c, 's') def test_width(self): def t(w, k): if k == '\0': k = '' M.FormatString('{:' + str(w) + k + '}') for k in 'bcdoxXneEfFgGs\0': for i in 4, 37, M.SSIZE_MAX: t(i, k) with assert_raises(M.Error): t(M.SSIZE_MAX + 1, k) def test_precision(self): def t(w, k): if k == '\0': k = '' M.FormatString('{:.' + str(w) + k + '}') for k in 'neEfFgGs\0': for i in {4, 37, M.SSIZE_MAX}: t(i, k) with assert_raises(M.Error): t(M.SSIZE_MAX + 1, k) for k in 'bcdoxX': for i in {4, 37, M.SSIZE_MAX, M.SSIZE_MAX + 1}: with assert_raises(M.Error): t(i, k) def test_type_compat(self): def t(k1, k2): s = '{0:' + k1 + '}{0:' + k2 + '}' M.FormatString(s) def e(k1, k2): with assert_raises(M.ArgumentTypeMismatch): t(k1, k2) ks = 'bcdoxXneEfFgGs' compat = [ ('s', 's'), ('bcdoxX', 'bcdoxXn'), ('n', 'bcdoxXneEfFgG'), ('eEfFgG', 'neEfFgG'), ] for k in ks: t(k, '') t('', k) for (k1s, k2s) in compat: for k1 in k1s: for k2 in k2s: t(k1, k2) for k2 in ks: if k2 not in k2s: e(k1, k2) def test_nested_fields(self): def t(v=None, f=None): if v is None: v = '' if f is None: f = '' s = '{' + str(v) + ':{' + str(f) + '}}' return M.FormatString(s) fmt = t() assert_equal(len(fmt.argument_map), 2) t(v=0, f=M.SSIZE_MAX) with assert_raises(M.ArgumentRangeError): t(v=0, f=(M.SSIZE_MAX + 1)) with assert_raises(M.ArgumentNumberingMixture): t(v=0) with assert_raises(M.ArgumentNumberingMixture): t(f=0) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_strformat_c.py0000644000000000000000000004020613147102065017247 0ustar0000000000000000# Copyright © 2014-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import struct import sys try: import unittest.mock as mock except ImportError: try: import mock except ImportError: mock = None import nose from nose.tools import ( assert_equal, assert_greater, assert_is_instance, assert_raises, assert_sequence_equal, ) import lib.strformat.c as M def test_INT_MAX(): struct.pack('=i', M.INT_MAX) with assert_raises(struct.error): struct.pack('=i', M.INT_MAX + 1) def test_NL_ARGMAX(): if sys.platform.startswith('linux'): assert_equal( M.NL_ARGMAX, os.sysconf('SC_NL_ARGMAX') ) else: raise nose.SkipTest('Linux-specific test') if mock is not None: small_NL_ARGMAX = mock.patch('lib.strformat.c.NL_ARGMAX', 42) # Setting NL_ARGMAX to a small number makes the *_index_out_of_range() tests # much faster. else: def small_NL_ARGMAX(func): return func def test_lone_percent(): with assert_raises(M.Error): M.FormatString('%') def test_invalid_conversion_spec(): with assert_raises(M.Error): M.FormatString('%!') def test_add_argument(): fmt = M.FormatString('%s') with assert_raises(RuntimeError): fmt.add_argument(2, None) def test_text(): fmt = M.FormatString('eggs%dbacon%dspam') assert_equal(len(fmt), 5) fmt = list(fmt) assert_equal(fmt[0], 'eggs') assert_equal(fmt[2], 'bacon') assert_equal(fmt[4], 'spam') class test_types: def t(self, s, tp, warn_type=None, integer=False): fmt = M.FormatString(s) [conv] = fmt assert_is_instance(conv, M.Conversion) assert_equal(conv.type, tp) if tp == 'void': assert_sequence_equal(fmt.arguments, []) else: [[arg]] = fmt.arguments assert_equal(arg.type, tp) if warn_type is None: assert_sequence_equal(fmt.warnings, []) else: [warning] = fmt.warnings assert_is_instance(warning, warn_type) assert_equal(conv.integer, integer) def test_integer(self): def t(s, tp, warn_type=None): integer = not suffix self.t(s, tp + suffix, warn_type, integer) for c in 'din': suffix = '' if c == 'n': suffix = ' *' yield t, ('%hh' + c), 'signed char' yield t, ('%h' + c), 'short int' yield t, ('%' + c), 'int' yield t, ('%l' + c), 'long int' yield t, ('%ll' + c), 'long long int' yield t, ('%L' + c), 'long long int', M.NonPortableConversion yield t, ('%q' + c), 'long long int', M.NonPortableConversion yield t, ('%j' + c), 'intmax_t' yield t, ('%z' + c), 'ssize_t' yield t, ('%Z' + c), 'ssize_t', M.NonPortableConversion yield t, ('%t' + c), 'ptrdiff_t' for c in 'ouxX': suffix = '' yield t, ('%hh' + c), 'unsigned char' yield t, ('%h' + c), 'unsigned short int' yield t, ('%' + c), 'unsigned int' yield t, ('%l' + c), 'unsigned long int' yield t, ('%ll' + c), 'unsigned long long int' yield t, ('%L' + c), 'unsigned long long int', M.NonPortableConversion yield t, ('%q' + c), 'unsigned long long int', M.NonPortableConversion yield t, ('%j' + c), 'uintmax_t' yield t, ('%z' + c), 'size_t' yield t, ('%Z' + c), 'size_t', M.NonPortableConversion yield t, ('%t' + c), '[unsigned ptrdiff_t]' def test_double(self): t = self.t for c in 'aefgAEFG': yield t, ('%' + c), 'double' yield t, ('%l' + c), 'double', M.NonPortableConversion yield t, ('%L' + c), 'long double' def test_char(self): t = self.t yield t, '%c', 'char' yield t, '%lc', 'wint_t' yield t, '%C', 'wint_t', M.NonPortableConversion yield t, '%s', 'const char *' yield t, '%ls', 'const wchar_t *' yield t, '%S', 'const wchar_t *', M.NonPortableConversion def test_void(self): t = self.t yield t, '%p', 'void *' yield t, '%m', 'void' yield t, '%%', 'void' def test_c99_macros(self): # pylint: disable=undefined-loop-variable def _t(s, tp): return self.t(s, tp, integer=True) def t(s, tp): return ( _t, '%<{macro}>'.format(macro=s.format(c=c, n=n)), ('u' if unsigned else '') + tp.format(n=n) ) # pylint: enable=undefined-loop-variable for c in 'diouxX': unsigned = c not in 'di' for n in {8, 16, 32, 64}: yield t('PRI{c}{n}', 'int{n}_t') yield t('PRI{c}LEAST{n}', 'int_least{n}_t') yield t('PRI{c}FAST{n}', 'int_fast{n}_t') yield t('PRI{c}MAX', 'intmax_t') yield t('PRI{c}PTR', 'intptr_t') class test_invalid_length: def t(self, s): with assert_raises(M.LengthError): M.FormatString(s) _lengths = ['hh', 'h', 'l', 'll', 'q', 'j', 'z', 't', 'L'] def test_double(self): t = self.t for c in 'aefgAEFG': for l in self._lengths: if l in 'lL': continue yield t, ('%' + l + c) def test_char(self): t = self.t for c in 'cs': for l in self._lengths: if l != 'l': yield t, '%' + l + c yield t, ('%' + l + c.upper()) def test_void(self): t = self.t for c in 'pm%': for l in self._lengths: yield t, ('%' + l + c) class test_numeration: def test_percent(self): with assert_raises(M.ForbiddenArgumentIndex): M.FormatString('%1$%') def test_errno(self): # FIXME? fmt = M.FormatString('%1$m') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 0) def test_swapped(self): fmt = M.FormatString('%2$s%1$d') assert_equal(len(fmt), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'const char *') def test_numbering_mixture(self): def t(s): with assert_raises(M.ArgumentNumberingMixture): M.FormatString(s) t('%s%2$s') t('%2$s%s') @small_NL_ARGMAX def test_index_out_of_range(self): with assert_raises(M.ArgumentRangeError): M.FormatString('%0$d') def fs(n): s = ''.join( '%{0}$d'.format(i) for i in range(1, n + 1) ) return M.FormatString(s) fmt = fs(M.NL_ARGMAX) assert_equal(len(fmt), M.NL_ARGMAX) assert_equal(len(fmt.arguments), M.NL_ARGMAX) with assert_raises(M.ArgumentRangeError): fs(M.NL_ARGMAX + 1) def test_initial_gap(self): with assert_raises(M.MissingArgument): M.FormatString('%2$d') def test_gap(self): with assert_raises(M.MissingArgument): M.FormatString('%3$d%1$d') class test_redundant_flag: def t(self, s): fmt = M.FormatString(s) [exc] = fmt.warnings assert_is_instance(exc, M.RedundantFlag) def test_duplicate(self): self.t('%--17d') def test_minus_zero(self): self.t('%-017d') def test_plus_space(self): self.t('%+ d') # TODO: Check for other redundant flags, for example “%+s”. class test_expected_flag: def t(self, s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) def test_hash(self): for c in 'oxXaAeEfFgG': yield self.t, ('%#' + c) def test_zero(self): for c in 'diouxXaAeEfFgG': yield self.t, ('%0' + c) def test_apos(self): for c in 'diufFgG': yield self.t, ("%'" + c) def test_other(self): for flag in '- +I': for c in 'diouxXaAeEfFgGcCsSpm': yield self.t, ('%' + flag + c) class test_unexpected_flag: def t(self, s): with assert_raises(M.FlagError): M.FormatString(s) def test_hash(self): for c in 'dicCsSnpm%': yield self.t, ('%#' + c) def test_zero(self): for c in 'cCsSnpm%': yield self.t, ('%0' + c) def test_apos(self): for c in 'oxXaAeEcCsSnpm%': yield self.t, ("%'" + c) def test_other(self): for c in '%n': for flag in '- +I': yield self.t, ('%' + flag + c) class test_width: def test_ok(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) for c in 'diouxXaAeEfFgGcCsSp': yield t, ('%1' + c) yield t, '%1m' # FIXME? def test_invalid(self): for c in '%n': with assert_raises(M.WidthError): M.FormatString('%1' + c) def test_too_large(self): fmt = M.FormatString('%{0}d'.format(M.INT_MAX)) assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 1) with assert_raises(M.WidthRangeError): M.FormatString('%{0}d'.format(M.INT_MAX + 1)) def test_variable(self): fmt = M.FormatString('%*s') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'const char *') def _test_index(self, i): fmt = M.FormatString('%2$*{0}$s'.format(i)) assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'const char *') def test_index(self): self._test_index(1) def test_leading_zero_index(self): self._test_index('01') self._test_index('001') @small_NL_ARGMAX def test_index_out_of_range(self): with assert_raises(M.ArgumentRangeError): M.FormatString('%1$*0$s') def fs(n): s = ''.join( '%{0}$d'.format(i) for i in range(2, n) ) + '%1$*{0}$s'.format(n) return M.FormatString(s) fmt = fs(M.NL_ARGMAX) assert_equal(len(fmt), M.NL_ARGMAX - 1) assert_equal(len(fmt.arguments), M.NL_ARGMAX) with assert_raises(M.ArgumentRangeError): fs(M.NL_ARGMAX + 1) def test_numbering_mixture(self): def t(s): with assert_raises(M.ArgumentNumberingMixture): M.FormatString(s) t('%1$*s') t('%*1$s') t('%s%1$*2$s') t('%1$*2$s%s') class test_precision: def test_ok(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) for c in 'diouxXaAeEfFgGsS': yield t, ('%.1' + c) def test_redundant_0(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) [warning] = fmt.warnings assert_is_instance(warning, M.RedundantFlag) for c in 'diouxX': yield t, ('%0.1' + c) def test_non_redundant_0(self): def t(s): fmt = M.FormatString(s) assert_equal(len(fmt), 1) assert_sequence_equal(fmt.warnings, []) for c in 'aAeEfFgG': yield t, ('%0.1' + c) def test_unexpected(self): def t(s): with assert_raises(M.PrecisionError): M.FormatString(s) for c in 'cCpnm%': yield t, ('%.1' + c) def test_too_large(self): fmt = M.FormatString('%.{0}f'.format(M.INT_MAX)) assert_equal(len(fmt), 1) with assert_raises(M.PrecisionRangeError): M.FormatString('%.{0}f'.format(M.INT_MAX + 1)) def test_variable(self): fmt = M.FormatString('%.*f') assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'double') def _test_index(self, i): fmt = M.FormatString('%2$.*{0}$f'.format(i)) assert_equal(len(fmt), 1) assert_equal(len(fmt.arguments), 2) [a1], [a2] = fmt.arguments assert_equal(a1.type, 'int') assert_equal(a2.type, 'double') def test_index(self): self._test_index(1) def test_leading_zero_index(self): self._test_index('01') self._test_index('001') @small_NL_ARGMAX def test_index_out_of_range(self): with assert_raises(M.ArgumentRangeError): M.FormatString('%1$.*0$f') def fs(n): s = ''.join( '%{0}$d'.format(i) for i in range(2, n) ) + '%1$.*{0}$f'.format(n) return M.FormatString(s) fmt = fs(M.NL_ARGMAX) assert_equal(len(fmt), M.NL_ARGMAX - 1) assert_equal(len(fmt.arguments), M.NL_ARGMAX) with assert_raises(M.ArgumentRangeError): fs(M.NL_ARGMAX + 1) def test_numbering_mixture(self): def t(s): with assert_raises(M.ArgumentNumberingMixture): M.FormatString(s) t('%1$.*f') t('%.*1$f') t('%f%2$.*1$f') t('%2$.*1$f%f') class test_type_compatibility: def test_okay(self): def t(s, tp): fmt = M.FormatString(s) [args] = fmt.arguments assert_greater(len(args), 1) for arg in args: assert_equal(arg.type, tp) t('%1$d%1$d', 'int') t('%1$d%1$i', 'int') def test_mismatch(self): def t(s): with assert_raises(M.ArgumentTypeMismatch): M.FormatString(s) t('%1$d%1$hd') t('%1$d%1$u') t('%1$d%1$s') @small_NL_ARGMAX def test_too_many_conversions(): def t(s): with assert_raises(M.ArgumentRangeError): M.FormatString(s) s = M.NL_ARGMAX * '%d' fmt = M.FormatString(s) assert_equal(len(fmt), M.NL_ARGMAX) t(s + '%f') t(s + '%*f') t(s + '%.*f') class test_get_last_integer_conversion: def test_overflow(self): fmt = M.FormatString('%s%d') for n in [-1, 0, 3]: with assert_raises(IndexError): fmt.get_last_integer_conversion(n=n) def t(self, s, n, tp=M.Conversion): fmt = M.FormatString(s) conv = fmt.get_last_integer_conversion(n=n) if tp is None: tp = type(tp) assert_is_instance(conv, tp) return conv def test_okay(self): self.t('%d', 1) self.t('%s%d', 1) def test_non_integer(self): self.t('%s', 1, None) self.t('%c', 1, None) def test_too_many(self): self.t('%s%d', 2, None) self.t('%d%d', 2, None) def test_var(self): self.t('%*d', 1) self.t('%*d', 2) self.t('%.*d', 2) self.t('%1$*2$d', 2) self.t('%2$*3$.*1$d', 3) def test_broken_var(self): self.t('%1$*2$d', 1, None) self.t('%1$*2$d%3$d', 2, None) self.t('%1$*3$d%2$d', 2, None) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_polib4us.py0000644000000000000000000000377413147102065016476 0ustar0000000000000000# Copyright © 2013-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import polib import lib.polib4us as M from nose.tools import ( assert_list_equal, assert_true, ) from . import tools minimal_header = r''' msgid "" msgstr "Content-Type: text/plain; charset=US-ASCII\n" ''' class test_codecs: @tools.fork_isolation def test_trailing_obsolete_message(self): s = minimal_header + ''' msgid "a" msgstr "b" #~ msgid "b" #~ msgstr "c" ''' def t(): with tools.temporary_file(mode='wt', encoding='ASCII') as file: file.write(s) file.flush() po = polib.pofile(file.name) assert_true(po[-1].obsolete) t() M.install_patches() t() @tools.fork_isolation def test_flag_splitting(): M.install_patches() e = polib.POEntry() e.flags = ['fuzzy,c-format'] assert_list_equal( e.flags, ['fuzzy', 'c-format'] ) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_moparser.py0000644000000000000000000000476013147102065016561 0ustar0000000000000000# Copyright © 2014-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import random import lib.moparser as M from nose.tools import ( assert_equal, assert_raises, ) from . import tools def parser_for_bytes(data): with tools.temporary_file(suffix='.mo') as file: file.write(data) file.flush() return M.Parser(file.name) class test_magic: def test_value(self): assert_equal(M.little_endian_magic, b'\xDE\x12\x04\x95') assert_equal(M.big_endian_magic, b'\x95\x04\x12\xDE') def test_short(self): for j in range(0, 3): data = M.little_endian_magic[:j] with assert_raises(M.SyntaxError) as cm: parser_for_bytes(data) assert_equal(str(cm.exception), 'unexpected magic') def test_full(self): for magic in {M.little_endian_magic, M.big_endian_magic}: with assert_raises(M.SyntaxError) as cm: parser_for_bytes(magic) assert_equal(str(cm.exception), 'truncated file') def test_random(self): while True: random_magic = bytes( random.randrange(0, 0x100) for i in range(0, 4) ) if random_magic in {M.little_endian_magic, M.big_endian_magic}: continue break with assert_raises(M.SyntaxError) as cm: parser_for_bytes(random_magic) assert_equal(str(cm.exception), 'unexpected magic') # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_misc.py0000644000000000000000000001042613147102065015660 0ustar0000000000000000# Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import datetime import os import stat import tempfile import time import lib.misc as M from nose.tools import ( assert_almost_equal, assert_equal, assert_is_instance, assert_is_not_none, assert_raises, assert_true, ) from . import tools class test_unsorted: def t(self, lst, expected): assert_is_instance(lst, list) r = M.unsorted(lst) assert_equal(r, expected) r = M.unsorted(x for x in lst) assert_equal(r, expected) def test_0(self): self.t([], None) def test_1(self): self.t([17], None) def test_2(self): self.t([17, 23], None) self.t([23, 17], (23, 17)) def test_3(self): self.t([17, 23, 37], None) self.t([17, 37, 23], (37, 23)) self.t([23, 17, 37], (23, 17)) self.t([23, 37, 17], (37, 17)) self.t([37, 17, 23], (37, 17)) self.t([37, 23, 17], (37, 23)) def test_inf(self): def iterable(): yield 17 yield 37 while True: yield 23 r = M.unsorted(iterable()) assert_equal(r, (37, 23)) class test_check_sorted: def test_sorted(self): M.check_sorted([17, 23, 37]) def test_unsorted(self): with assert_raises(M.DataIntegrityError) as cm: M.check_sorted([23, 37, 17]) assert_equal(str(cm.exception), '37 > 17') def test_sorted_vk(): lst = ['eggs', 'spam', 'ham'] d = dict(enumerate(lst)) assert_equal( lst, list(M.sorted_vk(d)) ) class test_utc_now: def test_types(self): now = M.utc_now() assert_is_instance(now, datetime.datetime) assert_is_not_none(now.tzinfo) assert_equal(now.tzinfo.utcoffset(now), datetime.timedelta(0)) @tools.fork_isolation def test_tz_resistance(self): def t(tz): os.environ['TZ'] = tz time.tzset() return M.utc_now() now1 = t('Etc/GMT-4') now2 = t('Etc/GMT+2') tdelta = (now1 - now2).total_seconds() assert_almost_equal(tdelta, 0, places=1) class test_format_range: def t(self, x, y, max, expected): # pylint: disable=redefined-builtin assert_equal( M.format_range(range(x, y), max=max), expected ) def test_max_is_lt_4(self): with assert_raises(ValueError): self.t(5, 10, 3, None) def test_len_lt_max(self): self.t(5, 10, 4, '5, 6, ..., 9') self.t(23, 43, 6, '23, 24, 25, 26, ..., 42') def test_len_eq_max(self): self.t(5, 10, 5, '5, 6, 7, 8, 9') def test_len_gt_max(self): self.t(5, 10, 6, '5, 6, 7, 8, 9') def test_huge(self): self.t(5, 42 ** 17, 5, '5, 6, 7, ..., 3937657486715347520027492351') def test_namespace(): ns = M.Namespace() with assert_raises(AttributeError): ns.eggs # pylint: disable=pointless-statement ns.eggs = 37 assert_equal(ns.eggs, 37) def test_throwaway_tempdir(): with M.throwaway_tempdir('test'): d = tempfile.gettempdir() st = os.stat(d) assert_equal(stat.S_IMODE(st.st_mode), 0o700) assert_true(stat.S_ISDIR(st.st_mode)) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_ling.py0000644000000000000000000004544413147102065015666 0ustar0000000000000000# Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import lib.encodings import lib.ling import nose from nose.tools import ( assert_equal, assert_false, assert_in, assert_is, assert_is_instance, assert_is_none, assert_not_equal, assert_not_in, assert_raises, assert_true, ) from . import tools L = lib.ling T = lib.ling.Language E = lib.encodings class test_fix_codes: def t(self, l1, l2): lang = L.parse_language(l1) assert_equal(str(lang), l1) if l1 == l2: assert_is_none(lang.fix_codes()) else: assert_is(lang.fix_codes(), True) assert_equal(str(lang), l2) def test_2_to_2(self): self.t('grc', 'grc') self.t('grc_GR', 'grc_GR') def test_1_to_1(self): self.t('el', 'el') self.t('el_GR', 'el_GR') def test_2t_to_1(self): self.t('ell', 'el') self.t('ell_GR', 'el_GR') def test_2b_to_1(self): self.t('gre', 'el') self.t('gre_GR', 'el_GR') def test_ll_not_found(self): with assert_raises(L.FixingLanguageCodesFailed): self.t('ry', '') def test_cc_not_found(self): with assert_raises(L.FixingLanguageCodesFailed): self.t('el_RY', '') def test_language_repr(): # Language.__repr__() is never used by i18nspector itself, # but it's useful for debugging test failures. lng = T('el') assert_equal(repr(lng), '') class test_language_equality: # ==, !=, is_almost_equal() def test_eq(self): l1 = T('el', 'GR') l2 = T('el', 'GR') assert_equal(l1, l2) assert_equal(l2, l1) def test_ne(self): l1 = T('el') l2 = T('el', 'GR') assert_not_equal(l1, l2) assert_not_equal(l2, l1) def test_ne_other_type(self): l1 = T('el') assert_not_equal(l1, 42) assert_not_equal(42, l1) def test_almost_equal(self): l1 = T('el') l2 = T('el', 'GR') assert_true(l1.is_almost_equal(l2)) assert_true(l2.is_almost_equal(l1)) def test_not_almost_equal(self): l1 = T('el', 'GR') l2 = T('grc', 'GR') assert_false(l1.is_almost_equal(l2)) assert_false(l2.is_almost_equal(l1)) def test_not_almost_equal_other_type(self): l1 = T('el') with assert_raises(TypeError): l1.is_almost_equal(42) class test_remove_encoding: def t(self, l1, l2): lang = L.parse_language(l1) assert_equal(str(lang), l1) if l1 == l2: assert_is_none(lang.remove_encoding()) else: assert_is(lang.remove_encoding(), True) assert_equal(str(lang), l2) def test_without_encoding(self): self.t('el', 'el') def test_with_encoding(self): self.t('el.UTF-8', 'el') class test_remove_nonlinguistic_modifier: def t(self, l1, l2): lang = L.parse_language(l1) assert_equal(str(lang), l1) if l1 == l2: assert_is_none(lang.remove_nonlinguistic_modifier()) else: assert_is(lang.remove_nonlinguistic_modifier(), True) assert_equal(str(lang), l2) def test_quot(self): self.t('en@quot', 'en@quot') self.t('en@boldquot', 'en@boldquot') def test_latin(self): self.t('sr@latin', 'sr@latin') def test_euro(self): self.t('de_AT@euro', 'de_AT') class test_lookup_territory_code: def test_found(self): cc = L.lookup_territory_code('GR') assert_equal(cc, 'GR') def test_not_found(self): cc = L.lookup_territory_code('RG') assert_is_none(cc) class test_get_language_for_name: def t(self, name, expected): lang = L.get_language_for_name(name) assert_is_instance(lang, T) assert_equal(str(lang), expected) def test_found(self): self.t('Greek', 'el') def test_found_multi(self): self.t('Old Church Slavonic', 'cu') def test_found_as_ascii(self): self.t('Norwegian Bokmål', 'nb') def test_found_semicolon(self): self.t('Chichewa; Nyanja', 'ny') def test_found_comma(self): self.t('Ndebele, South', 'nr') def test_found_comma_as_semicolon(self): self.t('Pashto, Pushto', 'ps') def test_lone_comma(self): with assert_raises(LookupError): self.t(',', None) def test_not_found(self): with assert_raises(LookupError): self.t('Nadsat', None) class test_parse_language: def test_ll(self): lang = L.parse_language('el') assert_equal(lang.language_code, 'el') assert_is_none(lang.territory_code) assert_is_none(lang.encoding) assert_is_none(lang.modifier) def test_lll(self): lang = L.parse_language('ell') assert_equal(lang.language_code, 'ell') assert_is_none(lang.territory_code) assert_is_none(lang.encoding) assert_is_none(lang.modifier) def test_ll_cc(self): lang = L.parse_language('el_GR') assert_equal(lang.language_code, 'el') assert_equal(lang.territory_code, 'GR') assert_is_none(lang.encoding) assert_is_none(lang.modifier) def test_ll_cc_enc(self): lang = L.parse_language('el_GR.UTF-8') assert_equal(lang.language_code, 'el') assert_equal(lang.territory_code, 'GR') assert_equal(lang.encoding, 'UTF-8') assert_is_none(lang.modifier) def test_ll_cc_modifier(self): lang = L.parse_language('en_US@quot') assert_equal(lang.language_code, 'en') assert_equal(lang.territory_code, 'US') assert_is_none(lang.encoding) assert_equal(lang.modifier, 'quot') def test_syntax_error(self): with assert_raises(L.LanguageSyntaxError): L.parse_language('GR') class test_get_primary_languages: def test_found(self): langs = L.get_primary_languages() assert_in('el', langs) def test_not_found(self): langs = L.get_primary_languages() assert_not_in('ry', langs) def test_iso_639(self): def t(lang_str): lang = L.parse_language(lang_str) assert_is_none(lang.fix_codes()) assert_equal(str(lang), lang_str) for lang_str in L.get_primary_languages(): yield t, lang_str class test_get_plural_forms: def t(self, lang): lang = L.parse_language(lang) return lang.get_plural_forms() def test_found_ll(self): assert_equal( self.t('el'), ['nplurals=2; plural=n != 1;'] ) def test_found_ll_cc(self): assert_equal( self.t('el_GR'), ['nplurals=2; plural=n != 1;'] ) def test_en_ca(self): assert_equal( self.t('en'), self.t('en_CA'), ) def test_pt_br(self): assert_not_equal( self.t('pt'), self.t('pt_BR'), ) def test_not_known(self): assert_is_none(self.t('la')) def test_not_found(self): assert_is_none(self.t('ry')) class test_principal_territory: def test_found_2(self): # el -> el_GR lang = L.parse_language('el') cc = lang.get_principal_territory_code() assert_equal(cc, 'GR') def test_remove_2(self): # el_GR -> el lang = L.parse_language('el_GR') assert_equal(str(lang), 'el_GR') rc = lang.remove_principal_territory_code() assert_is(rc, True) assert_equal(str(lang), 'el') def test_found_3(self): # ang -> ang_GB lang = L.parse_language('ang') cc = lang.get_principal_territory_code() assert_equal(cc, 'GB') def test_remove_3(self): # ang_GB -> ang lang = L.parse_language('ang_GB') assert_equal(str(lang), 'ang_GB') rc = lang.remove_principal_territory_code() assert_is(rc, True) assert_equal(str(lang), 'ang') def test_no_principal_territory_code(self): # en -/-> en_US lang = L.parse_language('en') cc = lang.get_principal_territory_code() assert_is_none(cc) def test_no_remove_principal_territory_code(self): # en_US -/-> en lang = L.parse_language('en_US') assert_equal(str(lang), 'en_US') rc = lang.remove_principal_territory_code() assert_is_none(rc) assert_equal(str(lang), 'en_US') def test_not_found(self): lang = L.parse_language('ry') cc = lang.get_principal_territory_code() assert_equal(cc, None) class test_unrepresentable_characters: def test_ll_bad(self): lang = L.parse_language('pl') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_not_equal(result, []) def test_ll_ok(self): lang = L.parse_language('pl') result = lang.get_unrepresentable_characters('ISO-8859-2') assert_equal(result, []) def test_ll_cc_bad(self): lang = L.parse_language('pl_PL') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_not_equal(result, []) def test_ll_cc_ok(self): lang = L.parse_language('pl_PL') result = lang.get_unrepresentable_characters('ISO-8859-2') assert_equal(result, []) def test_ll_mod_bad(self): lang = L.parse_language('en@quot') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_not_equal(result, []) def test_ll_mod_ok(self): lang = L.parse_language('en@quot') result = lang.get_unrepresentable_characters('UTF-8') assert_equal(result, []) def test_ll_cc_mod_bad(self): lang = L.parse_language('en_US@quot') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_not_equal(result, []) def test_ll_cc_mod_ok(self): lang = L.parse_language('en_US@quot') result = lang.get_unrepresentable_characters('UTF-8') assert_equal(result, []) def test_ll_optional(self): # U+0178 (LATIN CAPITAL LETTER Y WITH DIAERESIS) is not representable # in ISO-8859-1, but we normally turn a blind eye to this. lang = L.parse_language('fr') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_equal(result, []) result = lang.get_unrepresentable_characters('ISO-8859-1', strict=True) assert_not_equal(result, []) def test_ll_not_found(self): lang = L.parse_language('ry') result = lang.get_unrepresentable_characters('ISO-8859-1') assert_is_none(result) @tools.fork_isolation def test_extra_encoding(self): encoding = 'GEORGIAN-PS' lang = L.parse_language('pl') with assert_raises(LookupError): ''.encode(encoding) E.install_extra_encodings() result = lang.get_unrepresentable_characters(encoding) assert_not_equal(result, []) def test_glibc_supported(): def t(l): lang = L.parse_language(l) try: lang.fix_codes() except L.FixingLanguageCodesFailed: # FIXME: some ISO-639-3 codes are not recognized yet if len(l.split('_')[0]) == 3: raise nose.SkipTest('expected failure') reason = locales_to_skip.get(l) if reason is not None: raise nose.SkipTest(reason) raise assert_equal(str(lang), l) try: file = open('/usr/share/i18n/SUPPORTED', encoding='ASCII') except IOError as exc: raise nose.SkipTest(exc) locales = set() with file: for line in file: if line[:1] in {'#', '\n'}: continue locale, *rest = line.split() del rest if (locale + '.').startswith('iw_IL.'): # iw_IL is obsolete continue locales.add(locale) misnamed_locales = { # glibc 2.21 had two misnamed locales: 'bh_IN.UTF-8', # should be bhb_IN 'tu_IN.UTF-8', # should be tcy_IN } locales_to_skip = {} if locales & misnamed_locales == misnamed_locales: for l in misnamed_locales: locales_to_skip[l] = 'https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=032c510db06c' for l in sorted(locales): yield t, l def test_poedit(): # https://github.com/vslavik/poedit/blob/v1.8.1-oss/src/language_impl_legacy.h # There won't be any new names in this table, # so it's safe to hardcode them all here. def t(name, poedit_ll): poedit_ll = L.parse_language(poedit_ll) ll = L.get_language_for_name(name) assert_equal(ll, poedit_ll) def x(name, poedit_ll): poedit_ll = L.parse_language(poedit_ll) with assert_raises(LookupError): L.get_language_for_name(name) raise nose.SkipTest('expected failure') yield t, 'Abkhazian', 'ab' yield t, 'Afar', 'aa' yield t, 'Afrikaans', 'af' yield t, 'Albanian', 'sq' yield t, 'Amharic', 'am' yield t, 'Arabic', 'ar' yield t, 'Armenian', 'hy' yield t, 'Assamese', 'as' yield t, 'Avestan', 'ae' yield t, 'Aymara', 'ay' yield t, 'Azerbaijani', 'az' yield t, 'Bashkir', 'ba' yield t, 'Basque', 'eu' yield t, 'Belarusian', 'be' yield t, 'Bengali', 'bn' yield t, 'Bislama', 'bi' yield t, 'Bosnian', 'bs' yield t, 'Breton', 'br' yield t, 'Bulgarian', 'bg' yield t, 'Burmese', 'my' yield t, 'Catalan', 'ca' yield t, 'Chamorro', 'ch' yield t, 'Chechen', 'ce' yield t, 'Chichewa; Nyanja', 'ny' yield t, 'Chinese', 'zh' yield t, 'Church Slavic', 'cu' yield t, 'Chuvash', 'cv' yield t, 'Cornish', 'kw' yield t, 'Corsican', 'co' yield t, 'Croatian', 'hr' yield t, 'Czech', 'cs' yield t, 'Danish', 'da' yield t, 'Dutch', 'nl' yield t, 'Dzongkha', 'dz' yield t, 'English', 'en' yield t, 'Esperanto', 'eo' yield t, 'Estonian', 'et' yield t, 'Faroese', 'fo' yield t, 'Fijian', 'fj' yield t, 'Finnish', 'fi' yield t, 'French', 'fr' yield t, 'Frisian', 'fy' yield t, 'Friulian', 'fur' yield t, 'Gaelic', 'gd' yield t, 'Galician', 'gl' yield t, 'Georgian', 'ka' yield t, 'German', 'de' yield t, 'Greek', 'el' yield t, 'Guarani', 'gn' yield t, 'Gujarati', 'gu' yield t, 'Hausa', 'ha' yield t, 'Hebrew', 'he' yield t, 'Herero', 'hz' yield t, 'Hindi', 'hi' yield t, 'Hiri Motu', 'ho' yield t, 'Hungarian', 'hu' yield t, 'Icelandic', 'is' yield t, 'Indonesian', 'id' yield t, 'Interlingua', 'ia' yield t, 'Interlingue', 'ie' yield t, 'Inuktitut', 'iu' yield t, 'Inupiaq', 'ik' yield t, 'Irish', 'ga' yield t, 'Italian', 'it' yield t, 'Japanese', 'ja' yield t, 'Javanese', 'jv' # https://github.com/vslavik/poedit/pull/193 yield t, 'Kalaallisut', 'kl' yield t, 'Kannada', 'kn' yield t, 'Kashmiri', 'ks' yield t, 'Kazakh', 'kk' yield t, 'Khmer', 'km' yield t, 'Kikuyu', 'ki' yield t, 'Kinyarwanda', 'rw' yield t, 'Komi', 'kv' yield t, 'Korean', 'ko' yield t, 'Kuanyama', 'kj' yield t, 'Kurdish', 'ku' yield t, 'Kyrgyz', 'ky' yield t, 'Lao', 'lo' yield t, 'Latin', 'la' yield t, 'Latvian', 'lv' yield t, 'Letzeburgesch', 'lb' yield t, 'Lingala', 'ln' yield t, 'Lithuanian', 'lt' yield t, 'Macedonian', 'mk' yield t, 'Malagasy', 'mg' yield t, 'Malay', 'ms' yield t, 'Malayalam', 'ml' yield t, 'Maltese', 'mt' yield t, 'Maori', 'mi' yield t, 'Marathi', 'mr' yield t, 'Marshall', 'mh' yield t, 'Moldavian', 'ro_MD' # XXX poedit uses deprecated "mo" yield t, 'Mongolian', 'mn' yield t, 'Nauru', 'na' yield t, 'Navajo', 'nv' yield t, 'Ndebele, South', 'nr' yield t, 'Ndonga', 'ng' yield t, 'Nepali', 'ne' yield t, 'Northern Sami', 'se' yield t, 'Norwegian Bokmal', 'nb' yield t, 'Norwegian Nynorsk', 'nn' yield t, 'Occitan', 'oc' yield t, 'Oriya', 'or' yield t, 'Ossetian; Ossetic', 'os' yield t, 'Pali', 'pi' yield t, 'Panjabi', 'pa' yield t, 'Pashto, Pushto', 'ps' yield t, 'Persian', 'fa' yield t, 'Polish', 'pl' yield t, 'Portuguese', 'pt' yield t, 'Quechua', 'qu' yield t, 'Rhaeto-Romance', 'rm' yield t, 'Romanian', 'ro' yield t, 'Rundi', 'rn' yield t, 'Russian', 'ru' yield t, 'Samoan', 'sm' yield t, 'Sangro', 'sg' yield t, 'Sanskrit', 'sa' yield t, 'Sardinian', 'sc' yield t, 'Serbian', 'sr' yield t, 'Sesotho', 'st' yield t, 'Setswana', 'tn' yield t, 'Shona', 'sn' yield t, 'Sindhi', 'sd' yield t, 'Sinhalese', 'si' yield t, 'Siswati', 'ss' yield t, 'Slovak', 'sk' yield t, 'Slovenian', 'sl' yield t, 'Somali', 'so' yield t, 'Spanish', 'es' yield t, 'Sundanese', 'su' yield t, 'Swahili', 'sw' yield t, 'Swedish', 'sv' yield t, 'Tagalog', 'tl' yield t, 'Tahitian', 'ty' yield t, 'Tajik', 'tg' yield t, 'Tamil', 'ta' yield t, 'Tatar', 'tt' yield t, 'Telugu', 'te' yield t, 'Thai', 'th' yield t, 'Tibetan', 'bo' yield t, 'Tigrinya', 'ti' yield t, 'Tonga', 'to' yield t, 'Tsonga', 'ts' yield t, 'Turkish', 'tr' yield t, 'Turkmen', 'tk' yield t, 'Twi', 'tw' yield t, 'Ukrainian', 'uk' yield t, 'Urdu', 'ur' yield t, 'Uyghur', 'ug' yield t, 'Uzbek', 'uz' yield t, 'Vietnamese', 'vi' yield t, 'Volapuk', 'vo' yield t, 'Walloon', 'wa' yield t, 'Welsh', 'cy' yield t, 'Wolof', 'wo' yield t, 'Xhosa', 'xh' yield t, 'Yiddish', 'yi' yield t, 'Yoruba', 'yo' yield t, 'Zhuang', 'za' yield t, 'Zulu', 'zu' # TODO: yield x, '(Afan) Oromo', 'om' yield x, 'Bihari', 'bh' # "bh" is marked as collective in ISO-639-2 yield x, 'Serbian (Latin)', 'sr_RS@latin' yield x, 'Serbo-Croatian', 'sh' # "sh" is deprecated in favor of "sr", "hr", "bs" # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_iconv.py0000644000000000000000000000340013147102065016035 0ustar0000000000000000# Copyright © 2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from nose.tools import ( assert_equal, ) import lib.iconv as M class _test: u = None b = None e = None def test_encode(self): b = M.encode(self.u, self.e) assert_equal(b, self.b) def test_decode(self): u = M.decode(self.b, self.e) assert_equal(u, self.u) class test_iso2(_test): u = 'Żrą łódź? Część miń!' b = b'\xAFr\xB1 \xB3\xF3d\xBC? Cz\xEA\xB6\xE6 mi\xF1!' e = 'ISO-8859-2' class test_tcvn(_test): u = 'Do bạch kim rất quý, sẽ để lắp vô xương' b = b'Do b\xB9ch kim r\xCAt qu\xFD, s\xCF \xAE\xD3 l\xBEp v\xAB x\xAD\xACng' e = 'TCVN-5712' # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_gettext.py0000644000000000000000000005427613147102065016424 0ustar0000000000000000# Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import datetime from nose.tools import ( assert_equal, assert_false, assert_is_instance, assert_is_none, assert_is_not_none, assert_less, assert_raises, assert_true, ) import lib.gettext as M class test_header_fields: def test_nonempty(self): # XXX Update this number after editing data/header-fields: expected = 12 assert_equal(len(M.header_fields), expected) def test_no_x(self): for field in M.header_fields: assert_false(field.startswith('X-')) def test_valid(self): for field in M.header_fields: assert_true(M.is_valid_field_name(field)) class test_header_parser: def t(self, message, expected): parsed = list(M.parse_header(message)) assert_equal(parsed, expected) def test_ok(self): self.t( 'Menu: spam\nVikings: yes\n', [{'Menu': 'spam'}, {'Vikings': 'yes'}], ) def test_no_trailing_nl(self): self.t( 'Menu: spam\nVikings: yes', [{'Menu': 'spam'}, {'Vikings': 'yes'}], ) def test_invalid_field_name(self): self.t( 'Menu :spam\nVikings: yes\n', ['Menu :spam', {'Vikings': 'yes'}], ) def test_no_field(self): self.t( 'Spam\nVikings: yes\n', ['Spam', {'Vikings': 'yes'}], ) def test_continuation(self): self.t( 'Menu: spam,\n eggs\nVikings: yes\n', [{'Menu': 'spam,'}, ' eggs', {'Vikings': 'yes'}], ) class test_plural_exp: error = M.PluralFormsSyntaxError def t(self, s, n=None, fn=None): f = M.parse_plural_expression(s) if n is not None: assert_is_not_none(fn) assert_equal(f(n), fn) def test_const(self): n = 42 self.t(str(n), 0, n) def test_const_overflow(self): m = (1 << 32) - 1 self.t(str(m), m, m) with assert_raises(OverflowError): self.t(str(m + 1), m + 1, False) self.t(str(m + 1), m + 42, False) def test_var(self): n = 42 self.t('n', n, n) def test_var_overflow(self): m = (1 << 32) - 1 self.t('n', m, m) with assert_raises(OverflowError): self.t('n', m + 1, False) self.t('42', m + 1, 42) def test_add(self): self.t('17 + n', 6, 23) def test_add_overflow(self): m = (1 << 32) - 1 self.t('n + 42', m - 42, m) with assert_raises(OverflowError): self.t('n + 42', m - 41, False) self.t('n + 42', m - 23, False) def test_sub(self): self.t('n - 23', 37, 14) def test_sub_overflow(self): with assert_raises(OverflowError): self.t('n - 23', 6, False) def test_mul(self): self.t('6 * n', 7, 42) def test_mul_overflow(self): m = (1 << 32) - 1 assert m % 17 == 0 self.t('n * 17', m / 17, m) with assert_raises(OverflowError): self.t('n * 17', (m / 17) + 1, False) self.t('n * 2', (m + 1) / 2, False) def test_div(self): self.t('105 / n', 17, 6) def test_div_by_0(self): with assert_raises(ZeroDivisionError): self.t('105 / n', 0, False) def test_mod(self): self.t('105 % n', 17, 3) def test_mod_by_0(self): with assert_raises(ZeroDivisionError): self.t('105 % n', 0, False) def test_and(self): self.t('n && 6', 7, 1) self.t('n && 6', 0, 0) self.t('n && (6 / 0)', 0, 0) # no ZeroDivisionError self.t('n && 0', 7, 0) self.t('n && 0', 0, 0) def test_or(self): self.t('n || 6', 7, 1) self.t('n || (6 / 0)', 7, 1) # no ZeroDivisionError self.t('n || 6', 0, 1) self.t('n || 0', 7, 1) self.t('n || 0', 0, 0) def test_gt(self): self.t('n > 37', 23, 0) self.t('n > 37', 37, 0) self.t('n > 37', 42, 1) def test_ge(self): self.t('n >= 37', 23, 0) self.t('n >= 37', 37, 1) self.t('n >= 37', 42, 1) def test_lt(self): self.t('n < 37', 23, 1) self.t('n < 37', 37, 0) self.t('n < 37', 42, 0) def test_le(self): self.t('n <= 37', 23, 1) self.t('n <= 37', 37, 1) self.t('n <= 37', 42, 0) def test_eq(self): self.t('n == 37', 23, 0) self.t('n == 37', 37, 1) self.t('n == 37', 42, 0) def test_ne(self): self.t('n != 37', 23, 1) self.t('n != 37', 37, 0) self.t('n != 37', 42, 1) def test_multi_compare(self): self.t('1 < n == 3 <= 4', 1, 0) # False in Python self.t('1 < n == 3 <= 4', 2, 1) # False in Python self.t('1 < n == 3 <= 4', 3, 1) # True in Python self.t('1 < n == 3 <= 4', 4, 1) # False in Python self.t('2 == 2 == n', 2, 0) # True in Python self.t('2 == 2 == n', 1, 1) # False in Python def test_neg(self): self.t('! n', 0, 1) self.t('! n', 1, 0) self.t('! n', 69, 0) def test_neg_precedence(self): self.t('! 6 + 7', 0, 7) self.t('0 + ! 0') def test_conditional(self): s = 'n ? 3 : 7' self.t(s, 0, 7) self.t(s, 1, 3) def test_nested_conditional(self): self.t('(2 ? 3 : 7) ? 23 : 37') def test_badly_nested_conditional(self): with assert_raises(self.error): self.t('2 ? (3 : 7 ? ) : 23') def test_unary_minus(self): with assert_raises(self.error): self.t('-37') with assert_raises(self.error): self.t('23 + (-37)') def test_unary_plus(self): with assert_raises(self.error): self.t('+42') with assert_raises(self.error): self.t('23 + (+37)') def test_func_call(self): with assert_raises(self.error): self.t('n(42)') with assert_raises(self.error): self.t('42(n)') def test_unbalanced_parentheses(self): with assert_raises(self.error): self.t('(6 * 7') with assert_raises(self.error): self.t('6 * 7)') with assert_raises(self.error): self.t('6) * (7') def test_dangling_binop(self): with assert_raises(self.error): self.t('6 +') def test_junk_token(self): with assert_raises(self.error): self.t('6 # 7') def test_shift(self): with assert_raises(self.error): self.t('6 << 7') with assert_raises(self.error): self.t('6 >> 7') def test_pow(self): with assert_raises(self.error): self.t('6 ** 7') def test_floor_div(self): with assert_raises(self.error): self.t('6 // 7') def test_tuple(self): with assert_raises(self.error): self.t('()') with assert_raises(self.error): self.t('(6, 7)') def test_starred(self): with assert_raises(self.error): self.t('*42') def test_exotic_whitespace(self): with assert_raises(self.error): self.t('6 *\xA07') def test_empty(self): with assert_raises(self.error): self.t('') with assert_raises(self.error): self.t(' ') class test_codomain: def t(self, s, min_, max_=None): if max_ is None: max_ = min_ f = M.parse_plural_expression(s) cd = f.codomain() if min_ is None: assert max_ is None assert_is_none(cd) else: assert_equal(cd, (min_, max_)) def test_num(self): self.t('0', 0, 0) self.t('42', 42, 42) m = (1 << 32) - 1 self.t(str(m), m, m) # no overflow self.t(str(m + 1), None) # overflow self.t(str(m + 23), None) # overflow def test_zero_div(self): self.t('n / 0', None) self.t('(n / 0) + 23', None) self.t('23 + (n / 0)', None) self.t('! (n / 0)', None) self.t('0 < n/0', None) self.t('n/0 < 0', None) self.t('0 < n/0 < 0', None) def test_mod(self): self.t('n % 42', 0, 41) def test_mod_mod(self): self.t('(23 + n%15) % 42', 23, 37) def test_mod_0(self): self.t('n % 0', None) def test_add(self): self.t( '(6 + n%37) + (7 + n%23)', (6 + 7), 6 + 7 + 36 + 22 ) def test_add_max_overflow(self): m = (1 << 32) - 1 self.t( '(37 + n%4242424242) + (23 + n%4242424242)', 37 + 23, m ) def test_add_min_overflow(self): self.t( '(4242424242 + n%37) + (4242424242 + n%23)', None ) def test_sub(self): self.t( '(6 + n%37) - (7 + n%23)', 0, 6 + 36 - 7 ) self.t( '(37 + n%6) - (23 + n%7)', 37 - 23 - 6, 37 + 5 - 23 ) def test_sub_overflow(self): self.t( '(23 - n%6) - (23 + n%6)', # no overflow for n=0 0, 0 ) self.t( '(23 + n%6) - (37 + n%7)', # always overflows None ) def test_mul(self): self.t( '(6 + n%37) * (7 + n%23)', 6 * 7, (6 + 37 - 1) * (7 + 23 - 1) ) def test_mul_max_overflow(self): m = (1 << 32) - 1 self.t('(n + 6) * 7', 42, m) def test_mul_min_overflow(self): m = (1 << 32) - 1 assert m % 17 == 0 self.t( str(m // 17) + ' * (n + 17)', m, m ) self.t( str(m // 17) + ' * (n + 18)', None ) self.t( str((m + 1) // 2) + ' * (n + 2)', None ) def test_div(self): self.t( '(42 + n%63) / (6 + n%7)', 42 // (6 + 7), (42 + 63 - 1) // 6, ) def test_not(self): self.t('! (n % 7)', 0, 1) self.t('! (6 + n % 7)', 0, 0) self.t('! 0', 1, 1) def r(self, x, y, *, var='n'): if x == y: s = str(x) else: w = y - x + 1 assert w >= 2 s = '{x} + ({var})%{w}'.format(x=x, w=w, var=var) self.t(s, x, y) return s def t_cmp(self, ccmp, pycmp): sl = '1 + n%3' for x in range(4): for y in range(x, 5): sr = self.r(x, y, var='n/3') s = '{l} {cmp} {r}'.format(l=sl, cmp=ccmp, r=sr) vals = { int(pycmp(i, j)) for i in range(1, 4) for j in range(x, y + 1) } self.t(s, min(vals), max(vals)) n = 42 s = '{l} {cmp} {r}'.format(l=n, cmp=ccmp, r=n) self.t(s, pycmp(n, n), pycmp(n, n)) def test_lt(self): self.t_cmp('<', int.__lt__) def test_le(self): self.t_cmp('<=', int.__le__) def test_gt(self): self.t_cmp('>', int.__gt__) def test_ge(self): self.t_cmp('>=', int.__ge__) def test_eq(self): self.t_cmp('==', int.__eq__) def test_ne(self): self.t_cmp('!=', int.__ne__) def t_bool(self, cop, pyop): ranges = [ (x, y) for x in range(0, 3) for y in range(x, 3) ] for lx, ly in ranges: sl = self.r(lx, ly, var='n%3') for rx, ry in ranges: sr = self.r(rx, ry, var='n/3') s = '{l} {op} {r}'.format(l=sl, op=cop, r=sr) vals = { int(pyop(i, j)) for i in range(lx, ly + 1) for j in range(rx, ry + 1) } self.t(s, min(vals), max(vals)) def test_and(self): def op_and(x, y): return bool(x and y) self.t_bool('&&', op_and) def test_and_error(self): self.t('n && (n / 0) && 0', 0, 0) # doesn't raise exception for n==0 self.t('1 && (n / 0) && 0', None) # always raises exception def test_or(self): def op_or(x, y): return bool(x or y) self.t_bool('||', op_or) def test_or_error(self): self.t('n || (n / 0) || 1', 1, 1) # doesn't raise exception for n>0 self.t('0 || (n / 0) || 1', None) # always raises exception def test_cond_error(self): self.t('(n / 0) ? 37 : 42', None) def test_cond_always_true(self): self.t('1 ? 37 : n', 37, 37) def test_cond_always_false(self): self.t('0 ? n : 37', 37, 37) def test_cond_true_branch_error(self): self.t('n ? (n / 0) : 37', 37, 37) def test_cond_false_branch_error(self): self.t('n ? 37 : (n / 0)', 37, 37) def test_cond_both_branches_error(self): self.t('n ? (n / 0) : (n / 0)', None) def test_cond_both_branches_ok(self): self.t('n ? 37 : 42', 37, 42) self.t( 'n ? (6 + n%23) : (7 + n%37)', 6, 37 + 7 - 1 ) class test_period: def t(self, s, offset, period=None): f = M.parse_plural_expression(s) op = f.period() if offset is None: assert period is None assert_is_none(op) else: assert_equal(op, (offset, period)) def test_num(self): self.t('42', 0, 1) def test_const_mod(self): self.t('n % 42', 0, 42) self.t('n % 0', None) def test_binop(self): self.t('n + (n % 37)', None) self.t('(n % 37) + n', None) self.t('(n % 6) + (n % 14)', 0, 42) self.t('(n % 641) * (n % 6700417)', None) # overflow def test_unaryop(self): self.t('!n', None) self.t('!(n % 37)', 0, 37) def _cmp_shift(self, op): def e(n, op, m): return eval(str(n) + op + str(m)) # pylint: disable=eval-used return e(0, op, 0) != e(1, op, 0) def test_const_cmp(self): for op in {'!=', '==', '<', '<=', '>', '>='}: shift = self._cmp_shift(op) self.t('n {op} {i}'.format(op=op, i=37), 37 + shift, 1) def test_const_cmp_overflow(self): ops = {'!=', '==', '<', '<=', '>', '>='} m = (1 << 32) - 1 for op in ops: shift = self._cmp_shift(op) self.t('n {op} {m}'.format(op=op, m=(m - 1)), m - 1 + shift, 1) if shift: self.t('n {op} {m}'.format(op=op, m=m), None) else: self.t('n {op} {m}'.format(op=op, m=m), m, 1) self.t('n {op} {m}'.format(op=op, m=(m + 1)), None) self.t('n {op} {m}'.format(op=op, m=(m + 42)), None) def test_compare(self): self.t('n < (n % 37)', None) self.t('(n % 37) < n', None) self.t('(n % 6) < (n % 14)', 0, 42) self.t('(n % 641) < (n % 6700417)', None) # overflow def test_boolop(self): self.t('n && (n % 37)', None) self.t('(n % 37) && n', None) self.t('(n % 6) && (n % 14)', 0, 42) self.t('(n % 641) && (n % 6700417)', None) # overflow def test_ifexp(self): self.t('n ? (n % 3) : (n % 7)', None) self.t('(n % 2) ? n : (n % 7)', None) self.t('(n % 2) ? (n % 3) : n', None) self.t('(n % 2) ? (n % 3) : (n % 7)', 0, 42) self.t('(n % 2) ? (n % 3) : (n % 715827883)', None) # overflow def test_num_overflow(self): m = (1 << 32) - 1 self.t(str(m), 0, 1) self.t(str(m + 1), None) self.t(str(m + 42), None) def test_real_world(self): self.t('0', 0, 1) self.t('n != 1', 2, 1) self.t('n > 1', 2, 1) self.t('n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3', 0, 100) self.t('n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2', 1, 100) self.t('n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2', 0, 100) self.t('n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2', 0, 100) self.t('n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2', 2, 100) self.t('n==1 ? 0 : (n>=2 && n<=4) ? 1 : 2', 5, 1) self.t('n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2', 2, 100) self.t('n==1 ? 0 : n==2 ? 1 : 2', 3, 1) self.t('n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2', 2, 100) class test_plural_forms: error = M.PluralFormsSyntaxError def t(self, s, *, n, ljunk='', rjunk=''): if ljunk or rjunk: with assert_raises(self.error): M.parse_plural_forms(s) else: (n0, expr0) = M.parse_plural_forms(s) del expr0 assert_equal(n0, n) (n1, expr1, ljunk1, rjunk1) = M.parse_plural_forms(s, strict=False) del expr1 assert_equal(n1, n) assert_equal(ljunk1, ljunk) assert_equal(rjunk1, rjunk) def test_nplurals_0(self): with assert_raises(self.error): self.t('nplurals=0; plural=0;', n=0) def test_nplurals_positive(self): for n in 1, 2, 10, 42: self.t('nplurals={}; plural=0;'.format(n), n=n) def test_missing_trailing_semicolon(self): self.t('nplurals=1; plural=0', n=1) def test_junk(self): self.t('eggsnplurals=1; plural=0;', n=1, ljunk='eggs') self.t('nplurals=1; plural=0;ham', n=1, rjunk='ham') self.t('baconnplurals=1; plural=0;spam', n=1, ljunk='bacon', rjunk='spam') class test_fix_date_format: def t(self, old, expected): if expected is None: with assert_raises(M.DateSyntaxError): M.fix_date_format(old) else: new = M.fix_date_format(old) assert_is_not_none(new) assert_equal(new, expected) def tbp(self, old): with assert_raises(M.BoilerplateDate): M.fix_date_format(old) def test_boilerplate(self): self.tbp('YEAR-MO-DA HO:MI+ZONE') self.tbp('YEAR-MO-DA HO:MI +ZONE') def test_partial_boilerplate(self): self.tbp('2000-05-15 22:MI+0200') self.tbp('2002-10-15 HO:MI+ZONE') self.tbp('2003-07-DA 11:31+0100') self.tbp('2004-MO-DA HO:MI+ZONE') self.tbp('2006-10-24 18:00+ZONE') self.tbp('2010-11-01 HO:MI+0000') def test_okay(self): d = '2010-10-13 01:27+0200' self.t(d, d) def test_double_space(self): d = '2011-11-08 16:49+0200' self.t(d, d.replace(' ', ' ')) def test_space_before_tz(self): self.t( '2010-05-12 18:36 -0400', '2010-05-12 18:36-0400', ) def test_seconds(self): self.t( '2010-03-27 12:44:19+0100', '2010-03-27 12:44+0100', ) def test_colon_in_tz(self): self.t( '2001-06-25 18:55+02:00', '2001-06-25 18:55+0200', ) def test_t_separator(self): self.t( '2003-04-01T09:08+0500', '2003-04-01 09:08+0500', ) def test_missing_tz(self): self.t('2002-01-01 03:05', None) def test_tz_hint(self): assert_equal( M.fix_date_format('2002-01-01 03:05', tz_hint='+0900'), '2002-01-01 03:05+0900', ) def test_gmt_before_tz(self): self.t( '2001-07-28 11:19GMT+0200', '2001-07-28 11:19+0200', ) self.t( '2001-12-20 17:22UTC+0100', '2001-12-20 17:22+0100', ) def test_abbrev(self): # OK: self.t( '2004-04-20 13:24+CEST', '2004-04-20 13:24+0200', ) self.t( '2010-02-17 13:11 PST', '2010-02-17 13:11-0800', ) self.t( '2001-01-06 12:12GMT', '2001-01-06 12:12+0000', ) def test_abbrev_ambiguous(self): self.t('2004-04-14 21:35+CDT', None) self.t('2000-06-14 23:23+EST', None) # XXX In tzdata 2014f, EST stands only for (US) Eastern Time Zone, i.e. # -0500. But in the previous version of tzdata it could also stand for # (Australian) Eastern Standard/Summer Time. # https://mm.icann.org/pipermail/tz/2014-June/021089.html def test_abbrev_nonexistent(self): self.t('2005-12-20 10:33+JEST', None) def test_only_date(self): self.t('2008-01-09', None) def test_nonexistent(self): self.t('2010-02-29 19:49+0200', None) class test_parse_date: t = staticmethod(M.parse_date) def test_nonexistent(self): with assert_raises(M.DateSyntaxError): self.t('2010-02-29 19:49+0200') def test_existent(self): d = self.t('2003-09-08 21:26+0200') assert_equal(d.second, 0) assert_is_instance(d, datetime.datetime) assert_equal(str(d), '2003-09-08 21:26:00+02:00') def test_epoch(self): d = self.t('2008-04-03 16:06+0300') assert_less(M.epoch, d) class test_string_formats: def test_nonempty(self): # XXX Update this number after editing data/string-formats: expected = 28 assert_equal(len(M.string_formats), expected) def test_lowercase(self): for s in M.string_formats: assert_is_instance(s, str) assert_true(s) assert_equal(s, s.lower()) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_encodings.py0000644000000000000000000002046313147102065016700 0ustar0000000000000000# Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import curses.ascii import sys import lib.encodings as E import nose from nose.tools import ( assert_equal, assert_false, assert_is_none, assert_not_in, assert_raises, assert_true, ) from . import tools class test_is_portable_encoding: def test_found(self): assert_true(E.is_portable_encoding('ISO-8859-2')) def test_found_(self): assert_true(E.is_portable_encoding('ISO_8859-2')) def test_found_nonpython(self): assert_false(E.is_portable_encoding('KOI8-T')) assert_true(E.is_portable_encoding('KOI8-T', python=False)) def test_notfound(self): assert_false(E.is_portable_encoding('ISO-8859-16')) assert_false(E.is_portable_encoding('ISO-8859-16', python=False)) class test_propose_portable_encoding: def test_identity(self): encoding = 'ISO-8859-2' portable_encoding = E.propose_portable_encoding(encoding) assert_equal(portable_encoding, encoding) def test_found(self): def t(encoding, expected_portable_encoding): portable_encoding = E.propose_portable_encoding(encoding) assert_equal(portable_encoding, expected_portable_encoding) yield t, 'ISO8859-2', 'ISO-8859-2' yield t, 'ISO_8859-2', 'ISO-8859-2' yield t, 'Windows-1250', 'CP1250' def test_notfound(self): portable_encoding = E.propose_portable_encoding('ISO-8859-16') assert_is_none(portable_encoding) class test_ascii_compatibility: def test_portable(self): def t(encoding): assert_true(E.is_ascii_compatible_encoding(encoding)) assert_true(E.is_ascii_compatible_encoding(encoding, missing_ok=False)) for encoding in E.get_portable_encodings(): yield t, encoding def test_incompatible(self): def t(encoding): assert_false(E.is_ascii_compatible_encoding(encoding)) assert_false(E.is_ascii_compatible_encoding(encoding, missing_ok=False)) yield t, 'UTF-7' yield t, 'UTF-16' def _test_missing(self, encoding): assert_false(E.is_ascii_compatible_encoding(encoding)) with assert_raises(E.EncodingLookupError): E.is_ascii_compatible_encoding(encoding, missing_ok=False) def test_non_text(self): t = self._test_missing yield t, 'base64_codec' yield t, 'bz2_codec' yield t, 'hex_codec' yield t, 'quopri_codec' yield t, 'rot_13' yield t, 'uu_codec' yield t, 'zlib_codec' def test_missing(self): self._test_missing('eggs') class test_get_character_name: def test_latin(self): for i in range(ord('a'), ord('z')): u = chr(i) name = E.get_character_name(u) assert_equal(name, 'LATIN SMALL LETTER ' + u.upper()) u = chr(i).upper() name = E.get_character_name(u) assert_equal(name, 'LATIN CAPITAL LETTER ' + u) def test_c0(self): for i, curses_name in zip(range(0, 0x20), curses.ascii.controlnames): u = chr(i) name = E.get_character_name(u) expected_name = 'control character ' + curses_name assert_equal(name, expected_name) def test_del(self): name = E.get_character_name('\x7F') assert_equal(name, 'control character DEL') def test_c1(self): for i in range(0x80, 0xA0): u = chr(i) name = E.get_character_name(u) assert_true(name.startswith('control character ')) def test_uniqueness(self): names = set() for i in range(0, 0x100): u = chr(i) name = E.get_character_name(u) assert_not_in(name, names) names.add(name) def test_non_character(self): name = E.get_character_name('\uFFFE') assert_equal(name, 'non-character') name = E.get_character_name('\uFFFF') assert_equal(name, 'non-character') def test_lookup_error(self): with assert_raises(ValueError): E.get_character_name('\uE000') class test_extra_encoding: @tools.fork_isolation def test_install(self): encoding = 'VISCII' def enc(): ''.encode(encoding) def dec(): b'.'.decode(encoding) try: enc() except LookupError: pass else: raise nose.SkipTest( 'python{ver[0]}.{ver[1]} supports the {enc} encoding'.format( ver=sys.version_info, enc=encoding ) ) with assert_raises(LookupError): dec() E.install_extra_encodings() enc() dec() @tools.fork_isolation def test_8859(self): E.install_extra_encodings() encoding = '8859-2' portable_encoding = E.propose_portable_encoding(encoding) assert_equal('ISO-' + encoding, portable_encoding) @tools.fork_isolation def test_not_allowed(self): encoding = 'TSCII' def enc(): ''.encode(encoding) try: enc() except LookupError: pass else: raise nose.SkipTest( 'python{ver[0]}.{ver[1]} supports the {enc} encoding'.format( ver=sys.version_info, enc=encoding ) ) E.install_extra_encodings() with assert_raises(LookupError): enc() _viscii_unicode = 'Ti\u1EBFng Vi\u1EC7t' _viscii_bytes = b'Ti\xAAng Vi\xAEt' @tools.fork_isolation def test_8b_encode(self): E.install_extra_encodings() u = self._viscii_unicode b = u.encode('VISCII') assert_equal(b, self._viscii_bytes) @tools.fork_isolation def test_8b_encode_error(self): E.install_extra_encodings() u = self._viscii_unicode with assert_raises(UnicodeEncodeError): u.encode('KOI8-RU') @tools.fork_isolation def test_8b_decode(self): E.install_extra_encodings() b = self._viscii_bytes u = b.decode('VISCII') assert_equal(u, self._viscii_unicode) @tools.fork_isolation def test_8b_decode_error(self): E.install_extra_encodings() b = self._viscii_bytes with assert_raises(UnicodeDecodeError): b.decode('KOI8-T') _euc_tw_unicode = '\u4E2D\u6587' _euc_tw_bytes = b'\xC4\xE3\xC5\xC6' @tools.fork_isolation def test_mb_encode(self): E.install_extra_encodings() u = self._euc_tw_unicode b = u.encode('EUC-TW') assert_equal(b, self._euc_tw_bytes) @tools.fork_isolation def test_mb_encode_error(self): E.install_extra_encodings() u = self._viscii_unicode with assert_raises(UnicodeEncodeError): u.encode('EUC-TW') @tools.fork_isolation def test_mb_decode(self): E.install_extra_encodings() b = self._euc_tw_bytes u = b.decode('EUC-TW') assert_equal(u, self._euc_tw_unicode) @tools.fork_isolation def test_mb_decode_error(self): E.install_extra_encodings() b = self._viscii_bytes with assert_raises(UnicodeDecodeError): b.decode('EUC-TW') # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_domains.py0000644000000000000000000000645113147102065016362 0ustar0000000000000000# Copyright © 2014-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from nose.tools import ( assert_false, assert_is, assert_raises, assert_true, ) import lib.domains as M class test_special_domains: def t(self, domain, special=True): result = M.is_special_domain(domain) if special: assert_true(result) else: assert_false(result) def test_ok(self): self.t('test.jwilk.net', False) def test_in_addr_apra(self): self.t('119.216.184.93.in-addr.arpa') def test_ip6_arpa(self): self.t('7.a.a.0.7.9.0.1.7.4.4.1.f.b.6.2.d.6.0.0.0.2.2.0.0.0.8.2.6.0.6.2.ip6.arpa') def test_test(self): self.t('test') self.t('eggs.test') def test_localhost(self): self.t('localhost') self.t('eggs.localhost') def test_invalid(self): self.t('invalid') self.t('eggs.invalid') def test_example(self): self.t('example') for tld in 'com', 'net', 'org': self.t('example.{tld}'.format(tld=tld)) self.t('eggs.example.{tld}'.format(tld=tld)) class test_special_domain_emails: def t(self, email, special=True): result = M.is_email_in_special_domain(email) if special: assert_true(result) else: assert_false(result) def test_valid(self): self.t('jwilk@test.jwilk.net', False) def test_special(self): self.t('jwilk@example.net') def test_no_at(self): with assert_raises(ValueError): self.t('jwilk%jwilk.net') class test_dotless_domains: def t(self, domain, dotless=True): result = M.is_dotless_domain(domain) assert_is(result, dotless) def test_dotless(self): self.t('net') def test_dotfull(self): self.t('jwilk.net', False) self.t('example.jwilk.net', False) class test_dotless_emails: def t(self, email, dotless=True): result = M.is_email_in_dotless_domain(email) assert_is(result, dotless) def test_dotless(self): self.t('jwilk@net') def test_dotfull(self): self.t('jwilk@example.net', False) def test_no_at(self): with assert_raises(ValueError): self.t('jwilk%jwilk.net') # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/test_changelog.py0000644000000000000000000000767313147102065016666 0ustar0000000000000000# Copyright © 2014 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import re from nose.tools import ( assert_not_equal, ) import lib.tags here = os.path.dirname(__file__) docdir = os.path.join(here, os.pardir, 'doc') summary_re = re.compile( '^ [*] Summary of tag changes:((?:\n .*)+\n)', re.MULTILINE ) summary_details_re = re.compile( r'\A\n' r'(?:' r' [+] Added:\n' r'(?P(?:' r' - [\w-]+\n' r')+))?' r'(?:' r' [+] Renamed:\n' r'(?P(?:' r' - [\w-]+ [(]from [\w-]+[)]\n' r')+))?' r'\Z' ) rename_re = re.compile( r'([\w-]+) [(]from ([\w-]+)[)]' ) def test_tags(): path = os.path.join(docdir, 'changelog') with open(path, 'rt', encoding='UTF-8') as file: changelog = file.read() summaries = summary_re.findall(changelog) changelog_tags = set() def add(info, tag): del info if tag in changelog_tags: raise AssertionError('changelog adds tag twice: ' + tag) changelog_tags.add(tag) def remove(info, tag): del info if tag not in changelog_tags: raise AssertionError('changelog removes non-existent tag: ' + tag) changelog_tags.remove(tag) def rename(info, removed_tag, added_tag): assert_not_equal(removed_tag, added_tag) remove(info, removed_tag) add(info, added_tag) def check(info, tag): del info if tag not in changelog_tags: raise AssertionError('tag not in changelog: ' + tag) if tag not in data_tags: raise AssertionError('changelog adds unknown tag: ' + tag) for summary in reversed(summaries): match = summary_details_re.match(summary) for key, lines in match.groupdict().items(): if lines is None: continue lines = [l[8:] for l in lines.splitlines()] if key == 'added': for tag in lines: yield add, 'add', tag elif key == 'renamed': for line in lines: added_tag, removed_tag = rename_re.match(line).groups() yield rename, 'rename', removed_tag, added_tag else: assert False data_tags = frozenset(tag.name for tag in lib.tags.iter_tags()) for tag in sorted(changelog_tags | data_tags): yield check, 'check', tag def test_trailing_whitespace(): path = os.path.join(docdir, 'changelog') unreleased = False with open(path, 'rt', encoding='UTF-8') as file: for n, line in enumerate(file, 1): if n == 1 and ' UNRELEASED;' in line: unreleased = True if n == 3 and unreleased and line == ' * \n': continue line = line.rstrip('\n') if line[-1:].isspace(): raise AssertionError('trailing whitespace at line {0}'.format(n)) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/run-tests0000755000000000000000000000271313147102065015206 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2013-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import sys import tempfile import nose sys.path[0] += '/..' from tests import blackbox_tests if __name__ == '__main__': with tempfile.TemporaryDirectory(prefix='i18nspector.tests.') as tmpdir: os.environ['XDG_CACHE_HOME'] = tmpdir nose.main(addplugins=[blackbox_tests.Plugin()]) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/fuzzing/0000755000000000000000000000000013147102065015005 5ustar0000000000000000i18nspector-0.25.5/tests/fuzzing/plural-forms/0000755000000000000000000000000013147102065017430 5ustar0000000000000000i18nspector-0.25.5/tests/fuzzing/plural-forms/test.py0000644000000000000000000000337013147102065020764 0ustar0000000000000000# Copyright © 2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import sys import afl sys.path[0] += '/../../..' from lib import gettext def test(s): try: (n, expr) = gettext.parse_plural_forms(s) except gettext.PluralFormsSyntaxError: return del n for i in range(200): try: expr(i) except OverflowError: return except ZeroDivisionError: return def main(): while afl.loop(max=1000): s = sys.stdin.buffer.read() # pylint: disable=no-member s = s.decode('UTF-8', 'replace') test(s) os._exit(0) # pylint: disable=protected-access if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/fuzzing/plural-forms/run0000755000000000000000000000250413147102065020163 0ustar0000000000000000#!/bin/sh # Copyright © 2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. set -e here=$(dirname "$0") input="$here/input" output="$here/output" [ -e "$output/" ] && input=- export AFL_NO_VAR_CHECK=1 exec py-afl-fuzz -i "$input" -o "$output" -T i18nspector-plural-forms -- python3 "$here/test.py" i18nspector-0.25.5/tests/fuzzing/plural-forms/input/0000755000000000000000000000000013147102065020567 5ustar0000000000000000i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p4b0000644000000000000000000000016013147102065021174 0ustar0000000000000000nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p4a0000644000000000000000000000011713147102065021175 0ustar0000000000000000nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p3g0000644000000000000000000000005413147102065021202 0ustar0000000000000000nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p3f0000644000000000000000000000012513147102065021200 0ustar0000000000000000nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p3e0000644000000000000000000000011313147102065021174 0ustar0000000000000000nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p3d0000644000000000000000000000014513147102065021200 0ustar0000000000000000nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p3c0000644000000000000000000000013213147102065021173 0ustar0000000000000000nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p3b0000644000000000000000000000007613147102065021201 0ustar0000000000000000nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p3a0000644000000000000000000000007013147102065021172 0ustar0000000000000000nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p2b0000644000000000000000000000003213147102065021170 0ustar0000000000000000nplurals=2; plural=n > 1; i18nspector-0.25.5/tests/fuzzing/plural-forms/input/p10000644000000000000000000000002613147102065021030 0ustar0000000000000000nplurals=1; plural=0; i18nspector-0.25.5/tests/fuzzing/mo-parser/0000755000000000000000000000000013147102065016712 5ustar0000000000000000i18nspector-0.25.5/tests/fuzzing/mo-parser/test.py0000644000000000000000000000336613147102065020253 0ustar0000000000000000# Copyright © 2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import sys import afl sys.path[0] += '/../../..' import tests.tools as tools import lib.moparser as M def parser_for_bytes(data): with tools.temporary_file(suffix='.mo') as file: file.write(data) file.flush() return M.Parser(file.name) def test(data): try: parser_for_bytes(data) except M.SyntaxError: return except UnicodeDecodeError: pass def main(): while afl.loop(max=1000): data = sys.stdin.buffer.read() # pylint: disable=no-member test(data) os._exit(0) # pylint: disable=protected-access if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/fuzzing/mo-parser/run0000755000000000000000000000270013147102065017443 0ustar0000000000000000#!/bin/sh # Copyright © 2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. set -e here=$(dirname "$0") output="$here/output" if [ -e "$output/" ] then input=- else input=$(mktemp -d -t i18nspector.fuzzing.XXXXXX) cp "$here/../../blackbox_tests/"*.mo "$input/" fi export AFL_NO_VAR_CHECK=1 exec py-afl-fuzz -i "$input" -o "$output" -T i18nspector-mo-parser -- python3 "$here/test.py" # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/coverage.txt0000644000000000000000000000607013147102065015650 0ustar0000000000000000Generated automatically by private/update-branch-coverage. Do not edit. Name Stmts Miss Branch BrPart Cover Missing ---------------------------------------------------------------------------- lib.py 1 0 0 0 100% lib/check.py 801 750 503 0 4% 81-85, 88-101, 109, 115-200, 203-219, 223-355, 359-503, 507-579, 583-626, 631-666, 671-715, 718-796, 799-879, 882-996, 999-1006, 1009-1025, 1030 lib/check/msgformat.py 82 69 36 0 11% 32, 36, 39, 42-152 lib/check/msgformat/c.py 67 56 36 0 11% 37-44, 47-105, 108-129 lib/check/msgformat/pybrace.py 35 26 13 0 19% 37-48, 51-75 lib/check/msgformat/python.py 77 67 47 0 8% 37-109, 112-149 lib/check/msgrepr.py 11 7 2 0 31% 28-34 lib/cli.py 156 122 44 0 17% 45-49, 58-67, 70-71, 74-76, 82-112, 115-120, 126-132, 135-143, 146-154, 160, 168-188, 191-225 lib/domains.py 15 0 0 0 100% lib/encodings.py 127 36 34 1 73% 50-68, 80-88, 187, 201-213, 217-221, 185->187 lib/gettext.py 105 0 36 0 100% lib/iconv.py 161 56 54 18 59% 41-42, 55-57, 64, 66, 68, 70, 77-78, 87-88, 101-102, 115-127, 134-135, 138-149, 155, 157, 159, 161, 170-171, 184-185, 202-217, 226-227, 230-241, 63->64, 65->66, 67->68, 69->70, 76->77, 86->87, 100->101, 109->114, 114->115, 133->134, 154->155, 156->157, 158->159, 160->161, 169->170, 183->184, 199->202, 225->226 lib/intexpr.py 406 0 126 0 100% lib/ling.py 243 2 98 3 99% 181, 281, 159->162, 179->181, 277->283 lib/misc.py 48 0 16 0 100% lib/moparser.py 140 92 58 4 29% 74, 82, 97-115, 118-186, 191-200, 203, 54->60, 62->64, 80->82, 202->203 lib/paths.py 7 2 0 0 71% 36-37 lib/polib4us.py 111 76 26 0 26% 41-42, 56, 72, 75-96, 100, 110-113, 134-146, 150, 162, 171-176, 187-195, 206, 209, 213-217, 229-236, 244-253 lib/strformat.py 0 0 0 0 100% lib/strformat/c.py 285 0 168 0 100% lib/strformat/pybrace.py 156 0 74 0 100% lib/strformat/python.py 206 0 94 0 100% lib/tags.py 132 41 40 4 67% 47-51, 54-58, 63, 66, 111, 113, 116, 135-136, 147-149, 154-156, 169, 180-187, 193-197, 207-220, 239, 245, 110->111, 112->113, 115->116, 168->169 lib/terminal.py 55 24 4 0 53% 79-106 lib/xml.py 21 0 2 0 100% ---------------------------------------------------------------------------- TOTAL 3448 1426 1511 30 55% i18nspector-0.25.5/tests/blackbox_tests/0000755000000000000000000000000013147102065016320 5ustar0000000000000000i18nspector-0.25.5/tests/blackbox_tests/zero-division-error-in-unused-plural-forms.po0000644000000000000000000000126013147102065027135 0ustar0000000000000000# W: arithmetic-error-in-unused-plural-forms f(2): division by zero msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%0<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/zero-division-error-in-plural-forms.po0000644000000000000000000000153613147102065025642 0ustar0000000000000000# E: arithmetic-error-in-plural-forms f(2): division by zero msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%0<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/zero-bytes-file.po.tags0000644000000000000000000000077313147102065022644 0ustar0000000000000000P: no-language-header-field I: unable-to-determine-language P: no-mime-version-header-field MIME-Version: 1.0 P: no-content-transfer-encoding-header-field Content-Transfer-Encoding: 8bit E: no-content-type-header-field Content-Type: text/plain; charset= W: no-date-header-field POT-Creation-Date W: no-date-header-field PO-Revision-Date W: no-project-id-version-header-field W: no-report-msgid-bugs-to-header-field W: no-last-translator-header-field P: no-language-team-header-field W: empty-file i18nspector-0.25.5/tests/blackbox_tests/zero-bytes-file.po0000644000000000000000000000000013147102065021666 0ustar0000000000000000i18nspector-0.25.5/tests/blackbox_tests/zero-bytes-file.mo.tags0000644000000000000000000000004413147102065022630 0ustar0000000000000000E: invalid-mo-file unexpected magic i18nspector-0.25.5/tests/blackbox_tests/zero-bytes-file.mo0000644000000000000000000000000013147102065021663 0ustar0000000000000000i18nspector-0.25.5/tests/blackbox_tests/xfail-partially-translated-message-2.po0000644000000000000000000000157013147102065025705 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # msgstr[2] doesn't have to be translated, because (according to the range # flag) it will never be used. #, c-format, range: 1..4 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "" i18nspector-0.25.5/tests/blackbox_tests/xfail-header-imitation.po0000644000000000000000000000153413147102065023207 0ustar0000000000000000# E: broken-encoding '<...>' cannot be decoded as ASCII # P: no-language-header-field # I: unable-to-determine-language # P: no-mime-version-header-field MIME-Version: 1.0 # P: no-content-transfer-encoding-header-field Content-Transfer-Encoding: 8bit # E: no-content-type-header-field Content-Type: text/plain; charset= # W: no-date-header-field POT-Creation-Date # W: no-date-header-field PO-Revision-Date # W: no-project-id-version-header-field # W: no-report-msgid-bugs-to-header-field # W: no-last-translator-header-field # P: no-language-team-header-field # This msgid should sort first asciibetically, # so that the entry ends up first in the MO file, too. msgid "(header imitation)" msgstr "Content-Type: text/plain; charset=UTF-8" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis" i18nspector-0.25.5/tests/blackbox_tests/valid-range-flag.po0000644000000000000000000000146013147102065021761 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/unusual-unused-plural-forms.po0000644000000000000000000000131613147102065024277 0ustar0000000000000000# W: unusual-unused-plural-forms 'nplurals=2; plural=n != 1;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.25.5/tests/blackbox_tests/unusual-number-of-plural-forms.po0000644000000000000000000000151213147102065024664 0ustar0000000000000000# E: incorrect-number-of-plural-forms 3 (Plural-Forms header field) != 2 (number of msgstr items) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." i18nspector-0.25.5/tests/blackbox_tests/unusual-character-in-plural-translation.po0000644000000000000000000000162413147102065026546 0ustar0000000000000000# E: unusual-character-in-translation msgid '%d quick brown fox jumps over the lazy dog.': U+FFFF non-character msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag￿" i18nspector-0.25.5/tests/blackbox_tests/unrepresentable-characters.po0000644000000000000000000000125613147102065024177 0ustar0000000000000000# E: unrepresentable-characters ISO-8859-1 <...> # E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+00BF INVERTED QUESTION MARK msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mny bd, chro puk twj i sze flag." i18nspector-0.25.5/tests/blackbox_tests/unrepresentable-characters-euro.po0000644000000000000000000000135713147102065025151 0ustar0000000000000000# I: language-variant-does-not-affect-translation 'pl@euro' # E: unrepresentable-characters ISO-8859-1 <...> # E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+00BF INVERTED QUESTION MARK msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl@euro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mny bd, chro puk twj i sze flag." i18nspector-0.25.5/tests/blackbox_tests/unknown-x-header-field-2.po0000644000000000000000000000104713147102065023274 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "x-generator: pygettext.py 4.2\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/unknown-x-header-field-1.po0000644000000000000000000000104713147102065023273 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: pygettext.py 4.2\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/unknown-poedit-language.po0000644000000000000000000000110413147102065023416 0ustar0000000000000000# I: unknown-poedit-language Latn msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Latn\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/unknown-message-flag.po0000644000000000000000000000114313147102065022707 0ustar0000000000000000# I: unknown-message-flag msgid 'A quick brown fox jumps over the lazy dog.': muzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, muzzy msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/unknown-header-field.po0000644000000000000000000000111213147102065022661 0ustar0000000000000000# I: unknown-header-field Generator msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generator: pygettext.py 4.2\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/unknown-header-field-no-duplicate-hint.po0000644000000000000000000000126313147102065026212 0ustar0000000000000000# I: unknown-header-field POT-Revision-Date # Don't suggest renaming a field if such rename would lead to field # duplication. msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "POT-Revision-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/unknown-format-flag.po0000644000000000000000000000116713147102065022561 0ustar0000000000000000# I: unknown-message-flag msgid 'A quick brown fox jumps over the lazy dog.': intercal-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, intercal-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/unknown-file-type.pop0000644000000000000000000000105213147102065022431 0ustar0000000000000000# I: unknown-file-type msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." # vim:ft=po i18nspector-0.25.5/tests/blackbox_tests/unknown-encoding.po0000644000000000000000000000104413147102065022142 0ustar0000000000000000# E: unknown-encoding UTF-42 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-42\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/unexpected-flag-for-header-entry.po0000644000000000000000000000107513147102065025107 0ustar0000000000000000# W: unexpected-flag-for-header-entry blurry #, blurry msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/typoed-header-field-name.po0000644000000000000000000000116113147102065023410 0ustar0000000000000000# I: unknown-header-field MIME-Wersion => MIME-Version # P: no-mime-version-header-field MIME-Version: 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Wersion: 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." i18nspector-0.25.5/tests/blackbox_tests/typoed-flag-for-header-entry.po0000644000000000000000000000110413147102065024240 0ustar0000000000000000# W: unexpected-flag-for-header-entry muzzy => fuzzy #, muzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/translation-in-template.pot0000644000000000000000000000113713147102065023621 0ustar0000000000000000# W: translation-in-template msgid 'A quick brown fox jumps over the lazy dog.' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/trailing-junk-in-plural-forms.po0000644000000000000000000000151013147102065024460 0ustar0000000000000000# E: trailing-junk-in-plural-forms > msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;>\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/trailing-comment.po0000644000000000000000000000101513147102065022126 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." # oops i18nspector-0.25.5/tests/blackbox_tests/syntax-error.po0000644000000000000000000000077013147102065021341 0ustar0000000000000000# E: syntax-error-in-po-file line 16 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/syntax-error-in-unused-plural-expression.po0000644000000000000000000000151013147102065026731 0ustar0000000000000000# E: syntax-error-in-unused-plural-forms 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20 ? 1 : 2;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20 ? 1 : 2;\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.25.5/tests/blackbox_tests/syntax-error-in-plural-expression.po0000644000000000000000000000176313147102065025442 0ustar0000000000000000# E: syntax-error-in-plural-forms 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20 ? 1 : 2;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20 ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/stray-previous-msgid.po0000644000000000000000000000121313147102065022772 0ustar0000000000000000# W: stray-previous-msgid msgid 'A quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #| msgid "The quick brown fox jumps over the lazy dog." msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/stray-header-line-3.po0000644000000000000000000000115413147102065022336 0ustar0000000000000000# E: stray-header-line 'Project-Id-Version Gizmo Enhancer 1.0' # W: no-project-id-version-header-field msgid "" msgstr "" "Project-Id-Version Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/stray-header-line-2.po0000644000000000000000000000116213147102065022334 0ustar0000000000000000# E: stray-header-line 'POT-Creation-Date 2012-11-01 14:42+0100' # W: no-date-header-field POT-Creation-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/stray-header-line-1.po0000644000000000000000000000114313147102065022332 0ustar0000000000000000# E: stray-header-line 'MIME-Version 1.0' # P: no-mime-version-header-field MIME-Version: 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/seemingly-duplicate-message-definition.po0000644000000000000000000000120313147102065026370 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." msgctxt "rot13" msgid "A quick brown fox jumps over the lazy dog." msgstr "Fvp shtvraf, qhk, mrybglcbf, dhnz Xnehf unorevf." i18nspector-0.25.5/tests/blackbox_tests/rfc2606-in-report-msgid-bugs-to.po0000644000000000000000000000110613147102065024342 0ustar0000000000000000# W: invalid-report-msgid-bugs-to 'gizmoenhancer@example.org' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@example.org\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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/rfc2606-in-last-translator.po0000644000000000000000000000110613147102065023502 0ustar0000000000000000# W: invalid-last-translator 'Jakub Wilk ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/rfc2606-in-language-team.po0000644000000000000000000000107713147102065023066 0ustar0000000000000000# W: invalid-language-team 'Latin ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/redundant-message-flag.po0000644000000000000000000000123513147102065023176 0ustar0000000000000000# P: redundant-message-flag msgid 'A quick brown fox jumps over the lazy dog.': possible-c-format (implied by c-format) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format, possible-c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/range-flag-without-plural-string.po0000644000000000000000000000107313147102065025166 0ustar0000000000000000# W: range-flag-without-plural-string msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, range: 1..5 msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/qt-plural-format-mistaken-for-c-format.po0000644000000000000000000000161613147102065026176 0ustar0000000000000000# E: qt-plural-format-mistaken-for-c-format msgid '%n quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%n quick brown fox jumps over the lazy dog." msgid_plural "%n quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %n flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %n flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %n flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-width-range-error.po0000644000000000000000000000122713147102065026333 0ustar0000000000000000# E: python-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': field width too large '%9999999999s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %9999999999s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-unknown-argument.pot0000644000000000000000000000137213147102065026477 0ustar0000000000000000# E: python-format-string-unknown-argument msgid '%(N)d quick brown fox jumps over the lazy dog.': N in msgid but not in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-unknown-argument-2.po0000644000000000000000000000211713147102065026450 0ustar0000000000000000# E: python-format-string-unknown-argument msgid '%(N)d quick brown fox jumps over the lazy dog.': O in msgstr[0] but not in msgid # E: python-format-string-unknown-argument msgid '%(N)d quick brown fox jumps over the lazy dog.': O in msgstr[2] but not in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń %(O)s twój i %(N)d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń %(O)s twój i %(N)d flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-unknown-argument-1.po0000644000000000000000000000123113147102065026443 0ustar0000000000000000# E: python-format-string-unknown-argument msgid 'A quick brown %(A)s jumps over the lazy dog.': B in msgstr but not in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %(A)s jumps over the lazy dog." msgstr "Sic fugiens, %(A)s, zelotypos, quam %(B)s haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-redundant-precision.pot0000644000000000000000000000115013147102065027127 0ustar0000000000000000# P: python-format-string-redundant-precision msgid 'A quick brown fox jumps over the lazy dog%.42c': 42 in '%.42c' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog%.42c" msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-redundant-precision.po0000644000000000000000000000122313147102065026744 0ustar0000000000000000# P: python-format-string-redundant-precision msgid 'A quick brown fox jumps over the lazy dog%.42c': 42 in '%.42c' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog%.42c" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%.42c" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-redundant-length.pot0000644000000000000000000000113213147102065026415 0ustar0000000000000000# P: python-format-string-redundant-length msgid 'A quick brown %ls jumps over the lazy dog.': l in '%ls' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %ls jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-redundant-length.po0000644000000000000000000000117713147102065026242 0ustar0000000000000000# P: python-format-string-redundant-length msgid 'A quick brown %s jumps over the lazy dog.': h in '%hs' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %hs, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-redundant-flag.pot0000644000000000000000000000113013147102065026043 0ustar0000000000000000# P: python-format-string-redundant-flag msgid 'A quick brown %0s jumps over the lazy dog.': 0 in '%0s' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %0s jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-redundant-flag.po0000644000000000000000000000117713147102065025672 0ustar0000000000000000# P: python-format-string-redundant-flag msgid 'A quick brown %s jumps over the lazy dog.': '#' in '%#s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %#s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-precision-range-error.po0000644000000000000000000000122713147102065027207 0ustar0000000000000000# E: python-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': precision too large '%.9999999999s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %.9999999999s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-plural-okay.pot0000644000000000000000000000117113147102065025415 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-plural-okay.po0000644000000000000000000000150113147102065025226 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %(N)d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)d flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-overridden-flag-2.po0000644000000000000000000000122213147102065026175 0ustar0000000000000000# P: python-format-string-redundant-flag msgid '%d%% of quick brown foxes jump over the lazy dog.': 0 in '%0.3d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "%d%% of quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %0.3d%% flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-overridden-flag-1.po0000644000000000000000000000124413147102065026200 0ustar0000000000000000# P: python-format-string-redundant-flag msgid '%d%% of quick brown foxes jump over the lazy dog.': '+' overridden by ' ' in '%+ d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "%d%% of quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %+ d%% flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-omitted-numeral.pot0000644000000000000000000000116513147102065026266 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-omitted-numeral-5.po0000644000000000000000000000304213147102065026240 0ustar0000000000000000# E: python-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.' msgctxt 'max 6': N not in msgstr[2] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # %(N)d doesn't have to be included in msgstr[2], because according to the range # flag, it applies only to n=5. #, python-format, range: 1..5 msgctxt "max 5" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." # %(N)d cannot be omitted in msgstr[2], because it applies not only to n=5 but # also n=6. #, python-format, range: 1..6 msgctxt "max 6" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-omitted-numeral-2.po0000644000000000000000000000147713147102065026247 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)d flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-omitted-numeral-1.po0000644000000000000000000000150313147102065026234 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)d flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-okay.pot0000644000000000000000000000075613147102065024130 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-okay.po0000644000000000000000000000102413147102065023731 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-obsolete-conversion.pot0000644000000000000000000000114313147102065027153 0ustar0000000000000000# P: python-format-string-obsolete-conversion msgid '%u quick brown foxes jump over the lazy dog.': '%u' => '%d' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "%u quick brown foxes jump over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-obsolete-conversion.po0000644000000000000000000000121013147102065026762 0ustar0000000000000000# P: python-format-string-obsolete-conversion msgid '%d quick brown foxes jump over the lazy dog.': '%u' => '%d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "%d quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %u flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-no-excess-arguments.po0000644000000000000000000000120713147102065026700 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, python-format msgid "once" msgid_plural "%d times" msgstr[0] "%d paз" msgstr[1] "%d paзи" msgstr[2] "%d paзiв" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-multiple-unnamed-arguments.pot0000644000000000000000000000112413147102065030436 0ustar0000000000000000# E: python-format-string-multiple-unnamed-arguments msgid 'A quick brown %s jumps over the lazy %s.' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy %s." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-msgid-error.pot0000644000000000000000000000115113147102065025405 0ustar0000000000000000# E: python-format-string-error msgid 'A quick brown fox jumps over the lazy dog%': invalid conversion specification '%' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog%" msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-msgid-error.po0000644000000000000000000000102613147102065025222 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog%" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-missing-numeral.po0000644000000000000000000000135613147102065026110 0ustar0000000000000000# E: python-format-string-missing-argument msgid once: N not in msgstr[0] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, python-format msgid "once" msgid_plural "%(N)d times" msgstr[0] "paз" msgstr[1] "%(N)d paзи" msgstr[2] "%(N)d paзiв" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-missing-non-numeral.pot0000644000000000000000000000137213147102065027062 0ustar0000000000000000# E: python-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.': N not in msgid while in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%(N)s quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-missing-non-numeral.po0000644000000000000000000000171113147102065026673 0ustar0000000000000000# E: python-format-string-missing-argument msgid '%(N)s quick brown fox jumps over the lazy dog.': N not in msgstr[0] while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%(N)s quick brown fox jumps over the lazy dog." msgid_plural "%(N)s quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)s flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)s flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-missing-argument.po0000644000000000000000000000123513147102065026263 0ustar0000000000000000# E: python-format-string-missing-argument msgid 'A quick brown %(A)s jumps over the lazy %(B)s.': A not in msgstr while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %(A)s jumps over the lazy %(B)s." msgstr "Sic fugiens, dux, zelotypos, quam %(B)s haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-forbidden-argument-key.po0000644000000000000000000000124413147102065027334 0ustar0000000000000000# E: python-format-string-error msgid '100%% of quick brown foxes jump over the lazy %(O)s.': argument key not allowed '%(P)%' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "100%% of quick brown foxes jump over the lazy %(O)s." msgstr "Mężny bądź, chroń %(O)s twój i 100%(P)% flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-error.po0000644000000000000000000000122013147102065024115 0ustar0000000000000000# E: python-format-string-error msgid 'A quick brown fox jumps over the lazy dog.': invalid conversion specification '%' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-error-argument-type-mismatch.po0000644000000000000000000000122713147102065030526 0ustar0000000000000000# E: python-format-string-error msgid 'A quick brown %(O)s jumps over the lazy %(O)s.': argument type mismatch O int, str msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %(O)s jumps over the lazy %(O)s." msgstr "Sic fugiens, %(O)s, zelotypos, quam %(O)d haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-duplicate-flag.po0000644000000000000000000000121513147102065025651 0ustar0000000000000000# P: python-format-string-redundant-flag msgid 'A quick brown %--s jumps over the lazy dog.': duplicate - in '%--s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %--s jumps over the lazy dog." msgstr "Sic fugiens, %--s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-argument-type-mismatch.pot0000644000000000000000000000221713147102065027563 0ustar0000000000000000# I: python-format-string-unnamed-plural-argument msgid '%d quick brown fox jumps over the lazy dog.' # E: python-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': int (msgid) != str (msgid_plural) # E: python-format-string-argument-type-mismatch msgid '%(N)d quick brown fox jumps over the lazy dog.': int (msgid) != str (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%s quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)s quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-argument-type-mismatch-2.po0000644000000000000000000000324313147102065027536 0ustar0000000000000000# E: python-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': str (msgstr[0]) != int (msgid) # E: python-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': object (msgstr[2]) != int (msgid_plural) # E: python-format-string-argument-type-mismatch msgid '%(N)d quick brown fox jumps over the lazy dog.': str (msgstr[0]) != int (msgid) # E: python-format-string-argument-type-mismatch msgid '%(N)d quick brown fox jumps over the lazy dog.': object (msgstr[2]) != int (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %s flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %r flag." #, python-format msgid "%(N)d quick brown fox jumps over the lazy dog." msgid_plural "%(N)d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %(N)s flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %(N)d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %(N)r flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-argument-type-mismatch-1.po0000644000000000000000000000163313147102065027536 0ustar0000000000000000# E: python-format-string-argument-type-mismatch msgid 'A quick brown %s jumps over the lazy dog.': int (msgstr) != str (msgid) # E: python-format-string-argument-type-mismatch msgid 'A quick brown %(O)s jumps over the lazy dog.': int (msgstr) != str (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %d, zelotypos, quam Karus haberis." #, python-format msgid "A quick brown %(O)s jumps over the lazy dog." msgstr "Sic fugiens, %(O)d, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-argument-number-mismatch.pot0000644000000000000000000000234213147102065030071 0ustar0000000000000000# I: python-format-string-unnamed-plural-argument msgid '%d quick brown fox jumps over the lazy dog.' # E: python-format-string-argument-number-mismatch msgid '%d quick brown fox jumps over the lazy dog.': 1 (msgid) != 0 (msgid_plural) # I: python-format-string-unnamed-plural-argument msgid 'A quick brown fox jumps over the lazy dog.' # E: python-format-string-argument-number-mismatch msgid 'A quick brown fox jumps over the lazy dog.': 0 (msgid) != 1 (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" #, python-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-format-string-argument-number-mismatch-2.po0000644000000000000000000000210513147102065030041 0ustar0000000000000000# E: python-format-string-argument-number-mismatch msgid '%d quick brown fox jumps over the lazy dog.': 0 (msgstr[0]) != 1 (msgid) # E: python-format-string-argument-number-mismatch msgid '%d quick brown fox jumps over the lazy dog.': 2 (msgstr[2]) != 1 (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %*d flag." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-argument-number-mismatch-1.po0000644000000000000000000000161113147102065030041 0ustar0000000000000000# E: python-format-string-argument-number-mismatch msgid 'A quick brown %s jumps over the lazy dog.': 2 (msgstr) != 1 (msgid) # E: python-format-string-argument-number-mismatch msgid 'A quick brown %s jumps over the lazy %s.': 1 (msgstr) != 2 (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %s, zelotypos, quam %s haberis." #, python-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, %s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-format-string-argument-mixture.po0000644000000000000000000000123613147102065026310 0ustar0000000000000000# E: python-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': mixed named and unnamed argument specifications '%(n)d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, %s, zelotypos, quam %(n)d haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-width-range-error.po0000644000000000000000000000125413147102065027405 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': invalid format specification '{:9999999999}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {:9999999999}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-valid-conversion-flag.po0000644000000000000000000000103413147102065030232 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {!s}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-unknown-argument.pot0000644000000000000000000000140213147102065027543 0ustar0000000000000000# E: python-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': N in msgid but not in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-unknown-argument-2.po0000644000000000000000000000211713147102065027522 0ustar0000000000000000# E: python-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': O in msgstr[0] but not in msgid # E: python-brace-format-string-unknown-argument msgid '{N} quick brown fox jumps over the lazy dog.': O in msgstr[2] but not in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń {O} twój i {N} flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń {O} twój i {N} flag." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-unknown-argument-1.po0000644000000000000000000000123513147102065027521 0ustar0000000000000000# E: python-brace-format-string-unknown-argument msgid 'A quick brown {A} jumps over the lazy dog.': B in msgstr but not in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {A} jumps over the lazy dog." msgstr "Sic fugiens, {A}, zelotypos, quam {B} haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-precision-range-error.po0000644000000000000000000000125613147102065030263 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': invalid format specification '{:.9999999999}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {:.9999999999}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-plural-okay.pot0000644000000000000000000000117313147102065026471 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-plural-okay.po0000644000000000000000000000147513147102065026312 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i {N} flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-omitted-numeral.pot0000644000000000000000000000117113147102065027335 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-omitted-numeral-5.po0000644000000000000000000000305013147102065027311 0ustar0000000000000000# E: python-brace-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.' msgctxt 'max 6': N not in msgstr[2] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # {N} doesn't have to be included in msgstr[2], because according to the range # flag, it applies only to n=5. #, python-brace-format, range: 1..5 msgctxt "max 5" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." # {N} cannot be omitted in msgstr[2], because it applies not only to n=5 but # also n=6. #, python-brace-format, range: 1..6 msgctxt "max 6" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-omitted-numeral-2.po0000644000000000000000000000147713147102065027321 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-omitted-numeral-1.po0000644000000000000000000000150113147102065027304 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{N} quick brown fox jumps over the lazy dog." msgid_plural "{N} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N} flag." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-okay.pot0000644000000000000000000000076413147102065025201 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-okay.po0000644000000000000000000000103213147102065025002 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-no-excess-arguments.po0000644000000000000000000000122113147102065027746 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, python-brace-format msgid "once" msgid_plural "{N} times" msgstr[0] "{N} paз" msgstr[1] "{N} paзи" msgstr[2] "{N} paзiв" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-msgid-error.pot0000644000000000000000000000117413147102065026464 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown fox jumps over the lazy dog}': invalid replacement field specification '}' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog}" msgstr "" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-msgid-error.po0000644000000000000000000000103413147102065026273 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog}" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis}" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-missing-numeral.po0000644000000000000000000000136413147102065027161 0ustar0000000000000000# E: python-brace-format-string-missing-argument msgid once: N not in msgstr[0] while in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, python-brace-format msgid "once" msgid_plural "{N} times" msgstr[0] "paз" msgstr[1] "{N} paзи" msgstr[2] "{N} paзiв" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-missing-non-numeral.pot0000644000000000000000000000140713147102065030133 0ustar0000000000000000# E: python-brace-format-string-missing-argument msgid 'A quick brown fox jumps over the lazy dog.': N not in msgid while in msgid_plural #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "{N:s} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-missing-non-numeral.po0000644000000000000000000000172513147102065027752 0ustar0000000000000000# E: python-brace-format-string-missing-argument msgid '{N:s} quick brown fox jumps over the lazy dog.': N not in msgstr[0] while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{N:s} quick brown fox jumps over the lazy dog." msgid_plural "{N:s} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {N:s} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {N:s} flag." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-missing-argument.po0000644000000000000000000000224213147102065027334 0ustar0000000000000000# E: python-brace-format-string-missing-argument msgid 'A quick brown {} jumps over the lazy {}': 1 not in msgstr while in msgid # E: python-brace-format-string-missing-argument msgid 'A quick brown {0} jumps over the lazy {1}': 0 not in msgstr while in msgid # E: python-brace-format-string-missing-argument msgid 'A quick brown {A} jumps over the lazy {B}': A not in msgstr while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy {}" msgstr "Sic fugiens, dux, zelotypos, quam {} haberis." #, python-brace-format msgid "A quick brown {0} jumps over the lazy {1}" msgstr "Sic fugiens, dux, zelotypos, quam {1} haberis." #, python-brace-format msgid "A quick brown {A} jumps over the lazy {B}" msgstr "Sic fugiens, dux, zelotypos, quam {B} haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-mismatched-conversion-flag.po0000644000000000000000000000127413147102065031257 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': type mismatch between conversion and format specifications '{!s:d}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {!s:d}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-invalid-conversion-flag.po0000644000000000000000000000122513147102065030563 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': invalid conversion flag '{!z}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {!z}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-error.po0000644000000000000000000000124313147102065025174 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown fox jumps over the lazy dog.': invalid replacement field specification '}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis}" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-error-argument-type-mismatch.po0000644000000000000000000000131513147102065031576 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown {O:s} jumps over the lazy {O:s}.': argument type mismatch 'Sic fugiens, {O:s}, zelotypos, quam {O:d} haberis.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {O:s} jumps over the lazy {O:s}." msgstr "Sic fugiens, {O:s}, zelotypos, quam {O:d} haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-argument-type-mismatch.pot0000644000000000000000000000141613147102065030635 0ustar0000000000000000# E: python-brace-format-string-argument-type-mismatch msgid '{:s} quick brown fox jumps over the lazy dog.': str (msgid) != int (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, python-brace-format msgid "{:s} quick brown fox jumps over the lazy dog." msgid_plural "{:d} quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-argument-type-mismatch.po0000644000000000000000000000124713147102065030453 0ustar0000000000000000# E: python-brace-format-string-argument-type-mismatch msgid 'A quick brown {:s} jumps over the lazy dog.': int (msgstr) != str (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {:s} jumps over the lazy dog." msgstr "Sic fugiens, {:d}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-argument-sorting.po0000644000000000000000000000102613147102065027347 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy {s}." msgstr "Sic fugiens, {}, zelotypos, quam Karus {s}." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-argument-number-mismatch-2.po0000644000000000000000000000171513147102065031121 0ustar0000000000000000# E: python-brace-format-string-unknown-argument msgid '{} quick brown fox jumps over the lazy dog.': 1 in msgstr[2] but not in msgid_plural msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, python-brace-format msgid "{} quick brown fox jumps over the lazy dog." msgid_plural "{} quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i {} flagi." msgstr[2] "Mężny bądź, chroń pułk twój i {:{}} flag." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-argument-number-mismatch-1.po0000644000000000000000000000163513147102065031121 0ustar0000000000000000# E: python-brace-format-string-unknown-argument msgid 'A quick brown {} jumps over the lazy dog.': 1 in msgstr but not in msgid # E: python-brace-format-string-missing-argument msgid 'A quick brown {} jumps over the lazy {}.': 1 not in msgstr while in msgid msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {}, zelotypos, quam {} haberis." #, python-brace-format msgid "A quick brown {} jumps over the lazy {}." msgstr "Sic fugiens, {}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-argument-mixture.po0000644000000000000000000000125413147102065027362 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy {}.': mixed numbered and unnumbered argument specifications '{1}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy {}." msgstr "Sic fugiens, {}, zelotypos, quam {1} haberis." i18nspector-0.25.5/tests/blackbox_tests/python-brace-format-string-argument-index-too-large.po0000644000000000000000000000124613147102065030664 0ustar0000000000000000# E: python-brace-format-string-error msgid 'A quick brown {} jumps over the lazy dog.': argument index too large '{9999999999}' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, python-brace-format msgid "A quick brown {} jumps over the lazy dog." msgstr "Sic fugiens, {9999999999}, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/publican-dates.po0000644000000000000000000000141613147102065021555 0ustar0000000000000000# E: invalid-content-type 'application/x-publican; charset=UTF-8' => 'text/plain; charset=UTF-8' # W: invalid-date POT-Creation-Date: '2012-11-01T13:42' => '2012-11-01 13:42-0000' # W: invalid-date PO-Revision-Date: '2012-11-01T13:42' => '2012-11-01 13:42-0000' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01T13:42\n" "PO-Revision-Date: 2012-11-01T13:42\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: application/x-publican; 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." i18nspector-0.25.5/tests/blackbox_tests/previous-msgid.po0000644000000000000000000000110613147102065021633 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, fuzzy #| msgid "The quick brown fox jumps over the lazy dog." msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/po4a-xml.po0000644000000000000000000000110513147102065020316 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Content of: msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/po4a-xml-malformed.pot0000644000000000000000000000121113147102065022444 0ustar0000000000000000# E: malformed-xml msgid 'A quick brown fox jumps over the lazy dog.': asynchronous entity: line 1, column 48 #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Content of: msgid "A quick brown fox jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/po4a-xml-malformed.po0000644000000000000000000000127213147102065022267 0ustar0000000000000000# E: malformed-xml msgid 'A quick brown fox jumps over the lazy dog.': asynchronous entity: line 1, column 54 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: Content of: msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/plural-forms-without-plural-expression.po0000644000000000000000000000151513147102065026500 0ustar0000000000000000# E: syntax-error-in-plural-forms 3 => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: 3\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/plural-forms-okay.pot0000644000000000000000000000114213147102065022426 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/plural-forms-okay.po0000644000000000000000000000144113147102065022244 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/partially-translated-message.po0000644000000000000000000000151313147102065024442 0ustar0000000000000000# E: partially-translated-message msgid '%d quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "" i18nspector-0.25.5/tests/blackbox_tests/okay.pot0000644000000000000000000000073613147102065020015 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/okay.po0000644000000000000000000000100513147102065017617 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/okay-little-endian.mo.gen0000755000000000000000000000017113147102065023121 0ustar0000000000000000#!/bin/sh set -e -u -x exec grep -v '^"POT-Creation-Date: ' "${here}/okay.po"\ | msgfmt --endian=little - -o "${target}" i18nspector-0.25.5/tests/blackbox_tests/okay-little-endian.mo0000644000000000000000000000074113147102065022351 0ustar0000000000000000,<P*Q3|0A quick brown fox jumps over the lazy dog.Project-Id-Version: Gizmo Enhancer 1.0 Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net PO-Revision-Date: 2012-11-01 14:42+0100 Last-Translator: Jakub Wilk Language-Team: Latin Language: la MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sic fugiens, dux, zelotypos, quam Karus haberis.i18nspector-0.25.5/tests/blackbox_tests/okay-big-endian.mo.gen0000755000000000000000000000016613147102065022371 0ustar0000000000000000#!/bin/sh set -e -u -x exec grep -v '^"POT-Creation-Date: ' "${here}/okay.po"\ | msgfmt --endian=big - -o "${target}" i18nspector-0.25.5/tests/blackbox_tests/okay-big-endian.mo0000644000000000000000000000074113147102065021615 0ustar0000000000000000,<P*Q3|0A quick brown fox jumps over the lazy dog.Project-Id-Version: Gizmo Enhancer 1.0 Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net PO-Revision-Date: 2012-11-01 14:42+0100 Last-Translator: Jakub Wilk Language-Team: Latin Language: la MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sic fugiens, dux, zelotypos, quam Karus haberis.i18nspector-0.25.5/tests/blackbox_tests/nonexistent-language.po0000644000000000000000000000110113147102065023010 0ustar0000000000000000# E: invalid-language ry # I: unable-to-determine-language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: ry\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." i18nspector-0.25.5/tests/blackbox_tests/non-text-encoding.po0000644000000000000000000000105413147102065022220 0ustar0000000000000000# E: unknown-encoding zlib_codec msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=zlib_codec\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/non-python-portable-encoding.po0000644000000000000000000000075513147102065024372 0ustar0000000000000000# E: non-portable-encoding GEORGIAN-PS msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Georgian \n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=GEORGIAN-PS\n" "Content-Transfer-Encoding: 8bit\n" msgid "Georgia" msgstr "" i18nspector-0.25.5/tests/blackbox_tests/non-python-encoding.po0000644000000000000000000000111313147102065022551 0ustar0000000000000000# E: non-portable-encoding KOI8-RU msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=KOI8-RU\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr " Ʀ ަ, Τ ' ." i18nspector-0.25.5/tests/blackbox_tests/non-portable-encoding.po0000644000000000000000000000106313147102065023044 0ustar0000000000000000# E: non-portable-encoding ISO-8859-16 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-16\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/non-portable-encoding-with-hint.po0000644000000000000000000000107713147102065024762 0ustar0000000000000000# E: non-portable-encoding Windows-1252 => CP1252 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=Windows-1252\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/non-ascii-project-id.po0000644000000000000000000000102213147102065022571 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Гизмо Энханцэр 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/non-ascii-compatible.po0000644000000000000000000000105713147102065022660 0ustar0000000000000000# E: non-ascii-compatible-encoding UTF-7 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-7\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/no-version-in-project-id-version.po0000644000000000000000000000107113147102065025103 0ustar0000000000000000# P: no-version-in-project-id-version 'Gizmo Enhancer' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-required-plural-forms.po0000644000000000000000000000147513147102065023542 0ustar0000000000000000# E: no-required-plural-forms-header-field 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/no-report-msgid-bugs.po0000644000000000000000000000077613147102065022656 0ustar0000000000000000# W: no-report-msgid-bugs-to-header-field msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-project-id-version.po0000644000000000000000000000100313147102065023007 0ustar0000000000000000# W: no-project-id-version-header-field msgid "" msgstr "" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-pot-creation-date.po0000644000000000000000000000100513147102065022605 0ustar0000000000000000# W: no-date-header-field POT-Creation-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-po-revision-date.po0000644000000000000000000000100513147102065022453 0ustar0000000000000000# W: no-date-header-field PO-Revision-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-plural-forms.pot0000644000000000000000000000116513147102065022104 0ustar0000000000000000# W: no-plural-forms-header-field 'nplurals=INTEGER; plural=EXPRESSION;' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/no-plural-forms.po0000644000000000000000000000125213147102065021715 0ustar0000000000000000# W: no-plural-forms-header-field 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" msgstr[2] "" i18nspector-0.25.5/tests/blackbox_tests/no-package-name-in-project-id-version.po0000644000000000000000000000104613147102065025731 0ustar0000000000000000# I: no-package-name-in-project-id-version 1.0 msgid "" msgstr "" "Project-Id-Version: 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-mime-version.po0000644000000000000000000000104413147102065021703 0ustar0000000000000000# P: no-mime-version-header-field MIME-Version: 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\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." i18nspector-0.25.5/tests/blackbox_tests/no-last-translator.po0000644000000000000000000000077113147102065022431 0ustar0000000000000000# W: no-last-translator-header-field msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-language-team.po0000644000000000000000000000100413147102065021774 0ustar0000000000000000# P: no-language-team-header-field msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \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." i18nspector-0.25.5/tests/blackbox_tests/no-language-header-field.po0000644000000000000000000000106513147102065023366 0ustar0000000000000000# P: no-language-header-field # I: unable-to-determine-language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-language-header-field-with-hint.po0000644000000000000000000000106013147102065025272 0ustar0000000000000000# --language=la # P: no-language-header-field Language: la msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/no-content-type.po0000644000000000000000000000105113147102065021720 0ustar0000000000000000# E: no-content-type-header-field Content-Type: text/plain; charset= msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/no-content-transfer-encoding.po0000644000000000000000000000106113147102065024350 0ustar0000000000000000# P: no-content-transfer-encoding-header-field Content-Transfer-Encoding: 8bit msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/next-line-control-character-in-translation.po0000644000000000000000000000122013147102065027126 0ustar0000000000000000# E: unrepresentable-characters ISO-8859-1 <...> # E: unusual-character-in-translation <...>, U+0085 control character NEL, <...> msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.25.5/tests/blackbox_tests/next-line-control-character-in-header-entry.po0000644000000000000000000000112013147102065027156 0ustar0000000000000000# E: unusual-character-in-header-entry U+0085 control character NEL msgid "" msgstr "" "Project-Id-Version: Gizmo Enhąncer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/multiple-range-flags-3.po0000644000000000000000000000167713147102065023052 0ustar0000000000000000# E: conflicting-message-flags msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..5' 'range: 37..42' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5, range: 37..42, range: 1..5 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/multiple-range-flags-2.po0000644000000000000000000000166213147102065023043 0ustar0000000000000000# E: conflicting-message-flags msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..5' 'range: 37..42' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5, range: 37..42 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/multiple-range-flags-1.po0000644000000000000000000000163713147102065023044 0ustar0000000000000000# W: duplicate-message-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..05' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5, range: 1..05 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/message-flags-splitting-2.po0000644000000000000000000000102113147102065023542 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "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" i18nspector-0.25.5/tests/blackbox_tests/message-flags-splitting-1.po0000644000000000000000000000103413147102065023545 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, no-c-format,fuzzy msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" i18nspector-0.25.5/tests/blackbox_tests/lowercase-header-field-name.po0000644000000000000000000000116113147102065024070 0ustar0000000000000000# I: unknown-header-field Mime-Version => MIME-Version # P: no-mime-version-header-field MIME-Version: 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/lexer-error-in-plural-expression.po0000644000000000000000000000176313147102065025233 0ustar0000000000000000# E: syntax-error-in-plural-forms 'nplurals=3; plural=n==1 ? 0 : n%10>=2 & n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 & n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/leading-junk-in-plural-forms.po0000644000000000000000000000154313147102065024260 0ustar0000000000000000# E: leading-junk-in-plural-forms 'Plural-Forms: ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/language-variant-does-not-affect-translation.po0000644000000000000000000000110713147102065027414 0ustar0000000000000000# I: language-variant-does-not-affect-translation 'la@euro' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la@euro\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." i18nspector-0.25.5/tests/blackbox_tests/language-variant-does-affect-translation.po0000644000000000000000000000101213147102065026611 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la@quot\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." i18nspector-0.25.5/tests/blackbox_tests/language-team-equal-to-last-translator.po0000644000000000000000000000116113147102065026243 0ustar0000000000000000# I: language-team-equal-to-last-translator 'Latin ' 'Jakub Wilk ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/language-team-equal-to-last-translator-2.po0000644000000000000000000000131713147102065026405 0ustar0000000000000000# W: duplicate-header-field-last-translator # I: language-team-equal-to-last-translator 'Latin ' 'Jakub Wilk ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/language-disparity-poedit.po0000644000000000000000000000117513147102065023737 0ustar0000000000000000# W: language-disparity la (Language header field) != el (X-Poedit-Language header field) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Greek\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/language-disparity-command-line.po0000644000000000000000000000113613147102065025013 0ustar0000000000000000# --language el # W: language-disparity el (command-line) != la (Language header field) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/invalid-report-msgid-bugs.po0000644000000000000000000000112213147102065023652 0ustar0000000000000000# W: invalid-report-msgid-bugs-to 'Gizmo Enhancer Development Team' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: Gizmo Enhancer Development Team\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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/invalid-range-flag.po0000644000000000000000000000161213147102065022307 0ustar0000000000000000# E: invalid-range-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1-5' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1-5 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/invalid-range-flag-trailing-junk.po0000644000000000000000000000161613147102065025067 0ustar0000000000000000# E: invalid-range-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..5x' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..5x msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/invalid-range-flag-empty.po0000644000000000000000000000161413147102065023445 0ustar0000000000000000# E: invalid-range-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 2..1' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 2..1 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/invalid-range-flag-1-element.po0000644000000000000000000000161413147102065024076 0ustar0000000000000000# E: invalid-range-flag msgid '%d quick brown fox jumps over the lazy dog.': 'range: 1..1' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, range: 1..1 msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/invalid-pot-creation-date.po0000644000000000000000000000105313147102065023622 0ustar0000000000000000# W: invalid-date POT-Creation-Date: 2012-11-01 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/invalid-pot-creation-date-with-hint.po0000644000000000000000000000114013147102065025530 0ustar0000000000000000# W: invalid-date POT-Creation-Date: '2012-11-01 14:42+01:00' => '2012-11-01 14:42+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+01:00\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/invalid-po-revision-date.po0000644000000000000000000000105213147102065023467 0ustar0000000000000000# W: invalid-date PO-Revision-Date: 2012-11-01 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/invalid-po-revision-date-with-hint.po0000644000000000000000000000113713147102065025404 0ustar0000000000000000# W: invalid-date PO-Revision-Date: '2012-11-01 14:42+01:00' => '2012-11-01 14:42+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+01:00\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/invalid-mo-file.mo0000644000000000000000000000107113147102065021630 0ustar0000000000000000# E: invalid-mo-file unexpected magic msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." # vim:ft=po i18nspector-0.25.5/tests/blackbox_tests/invalid-mime-version.po0000644000000000000000000000105313147102065022715 0ustar0000000000000000# P: invalid-mime-version 4.2 => 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 4.2\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." i18nspector-0.25.5/tests/blackbox_tests/invalid-last-translator.po0000644000000000000000000000103613147102065023436 0ustar0000000000000000# W: invalid-last-translator 'Jakub Wilk' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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\n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/invalid-language.po0000644000000000000000000000110113147102065022060 0ustar0000000000000000# E: invalid-language LA # I: unable-to-determine-language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/invalid-language-natural-name.po0000644000000000000000000000105313147102065024450 0ustar0000000000000000# E: invalid-language Latin => la msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: Latin\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." i18nspector-0.25.5/tests/blackbox_tests/invalid-language-corrected.po0000644000000000000000000000104713147102065024041 0ustar0000000000000000# E: invalid-language lat => la msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: lat\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." i18nspector-0.25.5/tests/blackbox_tests/invalid-content-type.po0000644000000000000000000000110213147102065022727 0ustar0000000000000000# E: invalid-content-type 'text/plain' => 'text/plain; charset=' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/invalid-content-type-with-hint.po0000644000000000000000000000114113147102065024643 0ustar0000000000000000# E: invalid-content-type 'text/enriched; charset=UTF-8' => 'text/plain; charset=UTF-8' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/enriched; 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." i18nspector-0.25.5/tests/blackbox_tests/invalid-content-transfer-encoding.po0000644000000000000000000000107413147102065025366 0ustar0000000000000000# P: invalid-content-transfer-encoding 42bit => 8bit msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 42bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/integer-overflow-in-unused-plural-forms.po0000644000000000000000000000126613147102065026511 0ustar0000000000000000# W: arithmetic-error-in-unused-plural-forms f(12): integer overflow msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%(0-100)>=20) ? 1 : 2;\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/integer-overflow-in-plural-forms.po0000644000000000000000000000154413147102065025207 0ustar0000000000000000# E: arithmetic-error-in-plural-forms f(12): integer overflow msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%(0-100)>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/incorrect-plural-forms.po0000644000000000000000000000147713147102065023302 0ustar0000000000000000# E: unusual-plural-forms 'nplurals=2; plural=n != 1;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." i18nspector-0.25.5/tests/blackbox_tests/inconsistent-trailing-newlines.pot0000644000000000000000000000127513147102065025222 0ustar0000000000000000# E: inconsistent-trailing-newlines msgid '%d quick brown fox jumps over the lazy dog.' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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] "" i18nspector-0.25.5/tests/blackbox_tests/inconsistent-trailing-newlines.po0000644000000000000000000000113713147102065025033 0ustar0000000000000000# E: inconsistent-trailing-newlines msgid 'A quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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.\n" i18nspector-0.25.5/tests/blackbox_tests/inconsistent-trailing-newlines-fuzzy.po0000644000000000000000000000102013147102065026207 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "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" i18nspector-0.25.5/tests/blackbox_tests/inconsistent-number-of-plural-forms.po0000644000000000000000000000234213147102065025712 0ustar0000000000000000# E: inconsistent-number-of-plural-forms 2 (msgid '%d quick brown fox jumps over the lazy dog.' msgctxt 'missing plural form') != 3 (msgid '%d quick brown fox jumps over the lazy dog.') msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." msgctxt "missing plural form" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." i18nspector-0.25.5/tests/blackbox_tests/inconsistent-leading-newlines.pot0000644000000000000000000000127613147102065025015 0ustar0000000000000000# E: inconsistent-leading-newlines msgid '\n%d quick brown fox jumps over the lazy dog.' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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] "" i18nspector-0.25.5/tests/blackbox_tests/inconsistent-leading-newlines.po0000644000000000000000000000114013147102065024617 0ustar0000000000000000# E: inconsistent-leading-newlines msgid '\nA quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "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." i18nspector-0.25.5/tests/blackbox_tests/inconsistent-leading-newlines-fuzzy.po0000644000000000000000000000102013147102065026001 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, fuzzy msgid "\nA quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/header-imitation.mo.gen0000755000000000000000000000116613147102065022657 0ustar0000000000000000#!/bin/sh # E: broken-encoding '<...>' cannot be decoded as ASCII # P: no-language-header-field # I: unable-to-determine-language # P: no-mime-version-header-field MIME-Version: 1.0 # P: no-content-transfer-encoding-header-field Content-Transfer-Encoding: 8bit # E: no-content-type-header-field Content-Type: text/plain; charset= # W: no-date-header-field PO-Revision-Date # W: no-project-id-version-header-field # W: no-report-msgid-bugs-to-header-field # W: no-last-translator-header-field # P: no-language-team-header-field set -e -u -x exec msgfmt --endian=little "${here}/xfail-header-imitation.po" -o "${target}" i18nspector-0.25.5/tests/blackbox_tests/header-imitation.mo0000644000000000000000000000034713147102065022104 0ustar0000000000000000,<P*c'0(header imitation)A quick brown fox jumps over the lazy dog.Content-Type: text/plain; charset=UTF-8Sic fugiens, dux, zelotypos, quam Karus haberisi18nspector-0.25.5/tests/blackbox_tests/header-entry-flags-splitting.po0000644000000000000000000000114513147102065024355 0ustar0000000000000000# P: fuzzy-header-entry # W: unexpected-flag-for-header-entry no-c-format #, no-c-format,fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/hash-only-comment.po0000644000000000000000000000101413147102065022216 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #oops msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/generated-by-field.po0000644000000000000000000000161713147102065022314 0ustar0000000000000000# The Generated-By field is not used or generated by any of the GNU # gettext tools. Nevertheless it's rather widespread, as it's used by # pygettext[0] and Babel[1]. Emitting unknown-header-field would be # counter-productive. # # [0] https://docs.python.org/3/library/gettext.html#internationalizing-your-programs-and-modules # [1] http://babel.pocoo.org/ msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: pygettext.py 4.2\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/fuzzy-header-entry.po0000644000000000000000000000104713147102065022436 0ustar0000000000000000# P: fuzzy-header-entry #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/future-pot-creation-date.po0000644000000000000000000000110713147102065023506 0ustar0000000000000000# W: date-from-future POT-Creation-Date: '2142-04-02 03:37+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2142-04-02 03:37+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/future-po-revision-date.po0000644000000000000000000000110613147102065023353 0ustar0000000000000000# W: date-from-future PO-Revision-Date: '2142-04-02 03:37+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2142-04-02 03:37+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/escape-sequences.po0000644000000000000000000000115213147102065022110 0ustar0000000000000000# E: duplicate-message-definition msgid '\x07\x07\x08\x08\x0c\x0c\t\t\x0b\x0b\r…\n' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "\a\7\b\x8\f\x0c\t\11\v\013\r\xE2\x80\246\n" msgstr "" msgid "\a\7\b\x8\f\x0c\t\11\v\013\r\342\200\xA6\n" msgstr "" i18nspector-0.25.5/tests/blackbox_tests/encoding-in-header-field.po0000644000000000000000000000107413147102065023363 0ustar0000000000000000# W: encoding-in-language-header-field la.UTF-8 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la.UTF-8\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." i18nspector-0.25.5/tests/blackbox_tests/empty-report-msgid-bugs.po0000644000000000000000000000103113147102065023361 0ustar0000000000000000# W: no-report-msgid-bugs-to-header-field msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: \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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/empty-project-id-version.po0000644000000000000000000000114313147102065023536 0ustar0000000000000000# I: no-package-name-in-project-id-version (empty string) # P: no-version-in-project-id-version (empty string) msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/empty-pot-creation-date.po0000644000000000000000000000104513147102065023333 0ustar0000000000000000# W: invalid-date POT-Creation-Date: (empty string) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: \n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/empty-po-revision-date.po0000644000000000000000000000104413147102065023200 0ustar0000000000000000# W: invalid-date PO-Revision-Date: (empty string) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: \n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/empty-msgid-message-with-source-code-references.po0000644000000000000000000000112413147102065030035 0ustar0000000000000000# E: empty-msgid-message-with-source-code-references 'gizmo.c:1' #: gizmo.c:1 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/empty-msgid-message-with-plural-forms.po0000644000000000000000000000157213147102065026140 0ustar0000000000000000# E: empty-msgid-message-with-plural-forms msgid "" msgid_plural "" msgstr[0] "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgstr[1] "" msgstr[2] "" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/empty-mime-version.po0000644000000000000000000000106313147102065022426 0ustar0000000000000000# P: invalid-mime-version (empty string) => 1.0 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: \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." i18nspector-0.25.5/tests/blackbox_tests/empty-file.pot0000644000000000000000000000066113147102065021122 0ustar0000000000000000# W: empty-file #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" i18nspector-0.25.5/tests/blackbox_tests/empty-file.po0000644000000000000000000000065113147102065020735 0ustar0000000000000000# W: empty-file msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" i18nspector-0.25.5/tests/blackbox_tests/empty-content-type.po0000644000000000000000000000107213147102065022445 0ustar0000000000000000# E: invalid-content-type (empty string) => 'text/plain; charset=' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: \n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/empty-content-transfer-encoding.po0000644000000000000000000000110013147102065025064 0ustar0000000000000000# P: invalid-content-transfer-encoding (empty string) => 8bit msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/duplicate-message-flag.po0000644000000000000000000000117613147102065023170 0ustar0000000000000000# W: duplicate-message-flag msgid 'A quick brown fox jumps over the lazy dog.': no-c-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, no-c-format, no-c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/duplicate-message-definition.po0000644000000000000000000000131113147102065024376 0ustar0000000000000000# E: duplicate-message-definition msgid 'A quick brown fox jumps over the lazy dog.' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/duplicate-message-definition-with-context.po0000644000000000000000000000136713147102065027044 0ustar0000000000000000# E: duplicate-message-definition msgid 'A quick brown fox jumps over the lazy dog.' msgctxt rot13 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgctxt "rot13" msgid "A quick brown fox jumps over the lazy dog." msgstr "Fvp shtvraf, qhk, mrybglcbf, dhnz Xnehf unorevf." msgctxt "rot13" msgid "A quick brown fox jumps over the lazy dog." msgstr "Fvp shtvraf, qhk, mrybglcbf, dhnz Xnehf unorevf." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field.po0000644000000000000000000000114313147102065023140 0ustar0000000000000000# I: duplicate-header-field Generated-By msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: VIM 7.3\n" "Generated-By: VIM 7.3\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-x-poedit-language.po0000644000000000000000000000116713147102065026456 0ustar0000000000000000# W: duplicate-header-field-x-poedit X-Poedit-Language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Latin\n" "X-Poedit-Language: Latin\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-x-poedit-country.po0000644000000000000000000000116613147102065026375 0ustar0000000000000000# W: duplicate-header-field-x-poedit X-Poedit-Country msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Country: Poland\n" "X-Poedit-Country: Poland\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-report-msgid-bugs-to.po0000644000000000000000000000115113147102065027127 0ustar0000000000000000# W: duplicate-header-field-report-msgid-bugs-to msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-project-id-version.po0000644000000000000000000000114013147102065026656 0ustar0000000000000000# W: duplicate-header-field-project-id-version msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-pot-creation-date.po0000644000000000000000000000114613147102065026460 0ustar0000000000000000# W: duplicate-header-field-date POT-Creation-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-po-revision-date.po0000644000000000000000000000114413147102065026324 0ustar0000000000000000# W: duplicate-header-field-date PO-Revision-Date msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-plural-forms.po0000644000000000000000000000166213147102065025567 0ustar0000000000000000# E: duplicate-header-field-plural-forms msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-mime-version.po0000644000000000000000000000110513147102065025546 0ustar0000000000000000# P: duplicate-header-field-mime-version msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-last-translator.po0000644000000000000000000000114413147102065026271 0ustar0000000000000000# W: duplicate-header-field-last-translator msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-language.po0000644000000000000000000000107413147102065024724 0ustar0000000000000000# E: duplicate-header-field-language msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-language-team.po0000644000000000000000000000112513147102065025645 0ustar0000000000000000# W: duplicate-header-field-language-team msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-content-type.po0000644000000000000000000000113313147102065025566 0ustar0000000000000000# E: duplicate-header-field-content-type msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-field-content-transfer-encoding.po0000644000000000000000000000114013147102065030213 0ustar0000000000000000# P: duplicate-header-field-content-transfer-encoding msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/duplicate-header-entry.po0000644000000000000000000000167213147102065023225 0ustar0000000000000000# E: duplicate-header-entry msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/duplicate-flag-for-header-entry.pot0000644000000000000000000000102113147102065025070 0ustar0000000000000000# W: duplicate-flag-for-header-entry fuzzy #, fuzzy, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/duplicate-empty-flag.po0000644000000000000000000000116413147102065022677 0ustar0000000000000000# I: unknown-message-flag msgid 'A quick brown fox jumps over the lazy dog.': (empty string) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, ,no-c-format, msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/dotless-domain-in-report-msgid-bugs-to.po0000644000000000000000000000106613147102065026201 0ustar0000000000000000# W: invalid-report-msgid-bugs-to 'gizmoenhancer@net' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/dotless-domain-in-last-translator.po0000644000000000000000000000106613147102065025341 0ustar0000000000000000# W: invalid-last-translator 'Jakub Wilk ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/dotless-domain-in-language-team.po0000644000000000000000000000105713147102065024716 0ustar0000000000000000# W: invalid-language-team 'Latin ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/distant-header-entry.po0000644000000000000000000000104013147102065022706 0ustar0000000000000000# E: distant-header-entry msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" i18nspector-0.25.5/tests/blackbox_tests/crlf.po0000644000000000000000000000102413147102065017603 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/coverage.txt0000644000000000000000000001005013147102065020650 0ustar0000000000000000Generated automatically by private/update-tag-coverage. Do not edit. [X] ancient-date [X] arithmetic-error-in-plural-forms [X] arithmetic-error-in-unused-plural-forms [X] boilerplate-in-content-type [X] boilerplate-in-date [X] boilerplate-in-initial-comments [X] boilerplate-in-language-team [X] boilerplate-in-last-translator [X] boilerplate-in-project-id-version [X] boilerplate-in-report-msgid-bugs-to [X] broken-encoding [X] c-format-string-argument-type-mismatch [X] c-format-string-error [X] c-format-string-excess-arguments [X] c-format-string-missing-arguments [X] c-format-string-non-portable-conversion [X] c-format-string-redundant-flag [X] codomain-error-in-plural-forms [X] codomain-error-in-unused-plural-forms [X] conflict-marker-in-header-entry [X] conflict-marker-in-translation [X] conflicting-message-flags [X] date-from-future [X] distant-header-entry [X] duplicate-flag-for-header-entry [X] duplicate-header-entry [X] duplicate-header-field [X] duplicate-header-field-content-transfer-encoding [X] duplicate-header-field-content-type [X] duplicate-header-field-date [X] duplicate-header-field-language [X] duplicate-header-field-language-team [X] duplicate-header-field-last-translator [X] duplicate-header-field-mime-version [X] duplicate-header-field-plural-forms [X] duplicate-header-field-project-id-version [X] duplicate-header-field-report-msgid-bugs-to [X] duplicate-header-field-x-poedit [X] duplicate-message-definition [X] duplicate-message-flag [X] empty-file [X] empty-msgid-message-with-plural-forms [X] empty-msgid-message-with-source-code-references [X] encoding-in-language-header-field [X] fuzzy-header-entry [X] inconsistent-leading-newlines [X] inconsistent-number-of-plural-forms [X] inconsistent-trailing-newlines [X] incorrect-number-of-plural-forms [X] invalid-content-transfer-encoding [X] invalid-content-type [X] invalid-date [X] invalid-language [X] invalid-language-team [X] invalid-last-translator [X] invalid-mime-version [X] invalid-mo-file [X] invalid-range-flag [X] invalid-report-msgid-bugs-to [X] language-disparity [X] language-team-equal-to-last-translator [X] language-variant-does-not-affect-translation [X] leading-junk-in-plural-forms [X] malformed-xml [X] no-content-transfer-encoding-header-field [X] no-content-type-header-field [X] no-date-header-field [X] no-language-header-field [X] no-language-team-header-field [X] no-last-translator-header-field [X] no-mime-version-header-field [X] no-package-name-in-project-id-version [X] no-plural-forms-header-field [X] no-project-id-version-header-field [X] no-report-msgid-bugs-to-header-field [X] no-required-plural-forms-header-field [X] no-version-in-project-id-version [X] non-ascii-compatible-encoding [X] non-portable-encoding [X] os-error [X] partially-translated-message [X] python-brace-format-string-argument-type-mismatch [X] python-brace-format-string-error [X] python-brace-format-string-missing-argument [X] python-brace-format-string-unknown-argument [X] python-format-string-argument-number-mismatch [X] python-format-string-argument-type-mismatch [X] python-format-string-error [X] python-format-string-missing-argument [X] python-format-string-multiple-unnamed-arguments [X] python-format-string-obsolete-conversion [X] python-format-string-redundant-flag [X] python-format-string-redundant-length [X] python-format-string-redundant-precision [X] python-format-string-unknown-argument [X] python-format-string-unnamed-plural-argument [X] qt-plural-format-mistaken-for-c-format [X] range-flag-without-plural-string [X] redundant-message-flag [X] stray-header-line [X] stray-previous-msgid [X] syntax-error-in-plural-forms [X] syntax-error-in-po-file [X] syntax-error-in-unused-plural-forms [X] trailing-junk-in-plural-forms [X] translation-in-template [X] unable-to-determine-language [X] unexpected-flag-for-header-entry [X] unknown-encoding [X] unknown-file-type [X] unknown-header-field [X] unknown-message-flag [X] unknown-poedit-language [X] unrepresentable-characters [X] unusual-character-in-header-entry [X] unusual-character-in-translation [X] unusual-plural-forms [X] unusual-unused-plural-forms i18nspector-0.25.5/tests/blackbox_tests/conflicting-message-flags.po0000644000000000000000000000116713147102065023700 0ustar0000000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': wrap no-wrap msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, wrap, no-wrap msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/conflicting-format-flags-4.po0000644000000000000000000000125113147102065023677 0ustar0000000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': possible-c-format impossible-c-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, possible-c-format, impossible-c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/conflicting-format-flags-3.po0000644000000000000000000000122713147102065023701 0ustar0000000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': c-format impossible-c-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, impossible-c-format, c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/conflicting-format-flags-2.po0000644000000000000000000000120713147102065023676 0ustar0000000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': c-format no-c-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, no-c-format, c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/conflicting-format-flags-1.po0000644000000000000000000000120713147102065023675 0ustar0000000000000000# E: conflicting-message-flags msgid 'A quick brown fox jumps over the lazy dog.': c-format lisp-format msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format, lisp-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/conflict-marker-in-translation.po0000644000000000000000000000146413147102065024705 0ustar0000000000000000# E: conflict-marker-in-translation msgid 'A quick brown fox jumps over the lazy dog.' '#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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 "" "#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" "#-#-#-#-# pl.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.25.5/tests/blackbox_tests/conflict-marker-in-header-entry-2.po0000644000000000000000000000122313147102065025066 0ustar0000000000000000# E: conflict-marker-in-header-entry '#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#' msgid "" msgstr "" "#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/conflict-marker-in-header-entry-1.po0000644000000000000000000000122313147102065025065 0ustar0000000000000000# E: conflict-marker-in-header-entry '#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/conflict-marker-in-fuzzy-translation.po0000644000000000000000000000143313147102065026066 0ustar0000000000000000# conflict-marker-in-translation should not trigger for fuzzy entries. # https://bugs.debian.org/753924 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, fuzzy msgid "A quick brown fox jumps over the lazy dog." msgstr "" "#-#-#-#-# la.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Sic fugiens, dux, zelotypos, quam Karus haberis.\n" "#-#-#-#-# pl.po (Gizmo Enhancer 1.0) #-#-#-#-#\n" "Mężny bądź, chroń pułk twój i sześć flag." i18nspector-0.25.5/tests/blackbox_tests/codomain-error-in-unused-plural-forms.po0000644000000000000000000000134113147102065026125 0ustar0000000000000000# W: codomain-error-in-unused-plural-forms f(x) != 0, 1, 2, ..., 41 # W: codomain-error-in-unused-plural-forms f(x) != 43, 44, 45, ..., 999999999999999999999 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1000000000000000000000; plural=42\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/codomain-error-in-plural-forms-2.po0000644000000000000000000000152413147102065024766 0ustar0000000000000000# E: codomain-error-in-plural-forms f(2) = 7 >= 3 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 7 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/codomain-error-in-plural-forms-1a.po0000644000000000000000000000237113147102065025127 0ustar0000000000000000# E: unusual-plural-forms 'nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' # E: codomain-error-in-plural-forms f(x) != 3 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." msgstr[3] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/codomain-error-in-plural-forms-1.po0000644000000000000000000000230013147102065024756 0ustar0000000000000000# E: unusual-plural-forms 'nplurals=5; plural=n==1 ? 1 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' => 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;' # E: codomain-error-in-plural-forms f(x) != 0 # E: codomain-error-in-plural-forms f(x) != 3, 4 msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=5; plural=n==1 ? 1 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." msgstr[3] "Mężny bądź, chroń pułk twój i %d flag." msgstr[4] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/c1-control-characters.po0000644000000000000000000000120413147102065022753 0ustar0000000000000000# E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+0080 control character PAD msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis…" i18nspector-0.25.5/tests/blackbox_tests/c0-control-characters.po0000644000000000000000000000120113147102065022747 0ustar0000000000000000# E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+0019 control character EM msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-1\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-width-range-error.po0000644000000000000000000000121513147102065025231 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': field width too large '%9999999999s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %9999999999s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-width-error.po0000644000000000000000000000117613147102065024145 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.%n': unexpected width '%24n' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog.%n" msgstr "Sic fugiens, %s, zelotypos, quam Karus haberis.%24n" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-precision-range-error.po0000644000000000000000000000121513147102065026105 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': precision too large '%.9999999999s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %.9999999999s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-precision-error.po0000644000000000000000000000121213147102065025010 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown fox jumps over the lazy dog%.42s': unexpected precision '%.42c' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown fox jumps over the lazy dog%.42s" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%.42c" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-plural-okay.pot0000644000000000000000000000115613147102065024321 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-plural-okay.po0000644000000000000000000000145513147102065024137 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-overridden-flag-2.po0000644000000000000000000000121013147102065025073 0ustar0000000000000000# P: c-format-string-redundant-flag msgid '%d%% of quick brown foxes jump over the lazy dog.': 0 in '%0.3d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "%d%% of quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %0.3d%% flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-overridden-flag-1.po0000644000000000000000000000123213147102065025076 0ustar0000000000000000# P: c-format-string-redundant-flag msgid '%d%% of quick brown foxes jump over the lazy dog.': '+' overridden by ' ' in '%+ d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "%d%% of quick brown foxes jump over the lazy dog." msgstr "Mężny bądź, chroń pułk twój i %+ d%% flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-omitted-numeral.pot0000644000000000000000000000115513147102065025166 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, c-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-omitted-numeral-5.po0000644000000000000000000000277213147102065025152 0ustar0000000000000000# E: c-format-string-missing-arguments msgid 'A quick brown fox jumps over the lazy dog.' msgctxt 'max 6': 0 (msgstr[2]) < 1 (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" # %d doesn't have to be included in msgstr[2], because according to the range # flag, it applies only to n=5. #, c-format, range: 1..5 msgctxt "max 5" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." # %d cannot be omitted in msgstr[2], because it applies not only to n=5 but # also n=6. #, c-format, range: 1..6 msgctxt "max 6" msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i pięć flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-omitted-numeral-2.po0000644000000000000000000000146113147102065025141 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-omitted-numeral-1.po0000644000000000000000000000146213147102065025141 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %d flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-okay.pot0000644000000000000000000000075113147102065023024 0ustar0000000000000000#, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-okay.po0000644000000000000000000000101713147102065022634 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-non-portable-conversion.pot0000644000000000000000000000152713147102065026646 0ustar0000000000000000# P: c-format-string-non-portable-conversion msgid '%Ld quick brown fox jumps over the lazy dog.': '%Ld' => '%lld' # P: c-format-string-non-portable-conversion msgid '%Ld quick brown fox jumps over the lazy dog.': '%qd' => '%lld' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, c-format msgid "%Ld quick brown fox jumps over the lazy dog." msgid_plural "%qd quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-non-portable-conversion.po0000644000000000000000000000143313147102065026456 0ustar0000000000000000# P: c-format-string-non-portable-conversion msgid '%zd%% of quick brown foxes jump over the lazy %S.': '%S' => '%ls' in '%2$S' # P: c-format-string-non-portable-conversion msgid '%zd%% of quick brown foxes jump over the lazy %S.': '%Zd' => '%zd' in '%1$Zd' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "%zd%% of quick brown foxes jump over the lazy %S." msgstr "Mężny bądź, chroń %2$S twój i %1$Zd flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-no-excess-arguments.po0000644000000000000000000000120213147102065025574 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, c-format msgid "once" msgid_plural "%d times" msgstr[0] "%d paз" msgstr[1] "%d paзи" msgstr[2] "%d paзiв" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-msgid-error.pot0000644000000000000000000000113713147102065024312 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown fox jumps over the lazy dog%': invalid conversion specification '%' #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown fox jumps over the lazy dog%" msgstr "" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-msgid-error.po0000644000000000000000000000102113147102065024116 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown fox jumps over the lazy dog%" msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-missing-numeral.po0000644000000000000000000000132413147102065025004 0ustar0000000000000000# E: c-format-string-missing-arguments msgid once: 0 (msgstr[0]) < 1 (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2\n" #, c-format msgid "once" msgid_plural "%d times" msgstr[0] "paз" msgstr[1] "%d paзи" msgstr[2] "%d paзiв" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-missing-non-numeral.pot0000644000000000000000000000134613147102065025764 0ustar0000000000000000# E: c-format-string-missing-arguments msgid 'A quick brown fox jumps over the lazy dog.': 0 (msgid) < 1 (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, c-format msgid "A quick brown fox jumps over the lazy dog." msgid_plural "%s quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-missing-non-numeral.po0000644000000000000000000000165113147102065025577 0ustar0000000000000000# E: c-format-string-missing-arguments msgid '%s quick brown fox jumps over the lazy dog.': 0 (msgstr[0]) < 1 (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%s quick brown fox jumps over the lazy dog." msgid_plural "%s quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i jedną flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %s flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %s flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-missing-argument.po0000644000000000000000000000116013147102065025161 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': missing argument 1$ msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, dux, zelotypos, quam %2$s haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-length-error.po0000644000000000000000000000117513147102065024306 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': invalid length modifier '%hs' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %hs, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-forbidden-argument-index.po0000644000000000000000000000122313147102065026551 0ustar0000000000000000# E: c-format-string-error msgid '100%% of quick brown foxes jump over the lazy %s.': argument index not allowed '%1$%' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "100%% of quick brown foxes jump over the lazy %s." msgstr "Mężny bądź, chroń %2$s twój i 100%1$% flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-flag-error.po0000644000000000000000000000121513147102065023731 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy dog.': unexpected format flag character '#' in '%#s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %#s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-excess-arguments.pot0000644000000000000000000000134413147102065025355 0ustar0000000000000000# E: c-format-string-excess-arguments msgid '%d quick brown fox jumps over the lazy dog.': 1 (msgid) > 0 (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "Quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-excess-arguments-2.po0000644000000000000000000000204313147102065025325 0ustar0000000000000000# E: c-format-string-excess-arguments msgid '%d quick brown fox jumps over the lazy dog.': 2 (msgstr[0]) > 1 (msgid) # E: c-format-string-excess-arguments msgid '%d quick brown fox jumps over the lazy dog.': 2 (msgstr[2]) > 1 (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń %2$s twój i %1$d flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %1$d flagi." msgstr[2] "Mężny bądź, chroń %2$s twój i %1$d flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-excess-arguments-1.po0000644000000000000000000000117513147102065025331 0ustar0000000000000000# E: c-format-string-excess-arguments msgid 'A quick brown %s jumps over the lazy dog.': 2 (msgstr) > 1 (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %s, zelotypos, quam %s haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-error.po0000644000000000000000000000120613147102065023022 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown fox jumps over the lazy dog.': invalid conversion specification '%' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown fox jumps over the lazy dog." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis%" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-error-missing-argument.po0000644000000000000000000000116013147102065026310 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': missing argument 1$ msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, dux, zelotypos, quam %2$s haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-error-argument-type-mismatch.po0000644000000000000000000000122113147102065027421 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %1$s jumps over the lazy %1$s.': argument type mismatch 1$ const char *, int msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %1$s jumps over the lazy %1$s." msgstr "Sic fugiens, %1$s, zelotypos, quam %1$d haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-duplicate-flag.po0000644000000000000000000000120313147102065024547 0ustar0000000000000000# P: c-format-string-redundant-flag msgid 'A quick brown %--s jumps over the lazy dog.': duplicate - in '%--s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %--s jumps over the lazy dog." msgstr "Sic fugiens, %--s, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-argument-type-mismatch.pot0000644000000000000000000000137013147102065026463 0ustar0000000000000000# E: c-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': int (msgid) != long int (msgid_plural) #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%ld quick brown foxes jump over the lazy dog." msgstr[0] "" msgstr[1] "" i18nspector-0.25.5/tests/blackbox_tests/c-format-string-argument-type-mismatch-2.po0000644000000000000000000000210213147102065026430 0ustar0000000000000000# E: c-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': short int (msgstr[0]) != int (msgid) # E: c-format-string-argument-type-mismatch msgid '%d quick brown fox jumps over the lazy dog.': long int (msgstr[2]) != int (msgid_plural) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" #, c-format msgid "%d quick brown fox jumps over the lazy dog." msgid_plural "%d quick brown foxes jump over the lazy dog." msgstr[0] "Mężny bądź, chroń pułk twój i %hd flagę." msgstr[1] "Mężny bądź, chroń pułk twój i %d flagi." msgstr[2] "Mężny bądź, chroń pułk twój i %ld flag." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-argument-type-mismatch-1.po0000644000000000000000000000122413147102065026433 0ustar0000000000000000# E: c-format-string-argument-type-mismatch msgid 'A quick brown %s jumps over the lazy dog.': int (msgstr) != const char * (msgid) msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy dog." msgstr "Sic fugiens, %d, zelotypos, quam Karus haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-argument-range-error.po0000644000000000000000000000121213147102065025731 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': argument index too small or too large '%0$s' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, %0$s, zelotypos, quam %1$d haberis." i18nspector-0.25.5/tests/blackbox_tests/c-format-string-argument-mixture.po0000644000000000000000000000123013147102065025203 0ustar0000000000000000# E: c-format-string-error msgid 'A quick brown %s jumps over the lazy %s.': mixed numbered and unnumbered argument specifications '%1$d' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #, c-format msgid "A quick brown %s jumps over the lazy %s." msgstr "Sic fugiens, %s, zelotypos, quam %1$d haberis." i18nspector-0.25.5/tests/blackbox_tests/broken-encoding.po0000644000000000000000000000112413147102065021722 0ustar0000000000000000# E: broken-encoding '<...>\xe2\x80\xa6"\n' cannot be decoded as ASCII msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=US-ASCII\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog..." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis…" i18nspector-0.25.5/tests/blackbox_tests/broken-encoding-due-to-missing-content-type.po0000644000000000000000000000116413147102065027217 0ustar0000000000000000# E: broken-encoding '<...>\xe2\x80\xa6"\n' cannot be decoded as ASCII # E: no-content-type-header-field Content-Type: text/plain; charset= msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog..." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis…" i18nspector-0.25.5/tests/blackbox_tests/broken-encoding-and-syntax-error.po0000644000000000000000000000120013147102065025130 0ustar0000000000000000# E: syntax-error-in-po-file line 20 # E: broken-encoding '<...>\xe2\x80\xa6"<...>' cannot be decoded as ASCII msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ASCII\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog..." msgstr "Sic fugiens, dux, zelotypos, quam Karus haberis…" msgid i18nspector-0.25.5/tests/blackbox_tests/bom-in-translation.po0000644000000000000000000000120413147102065022372 0ustar0000000000000000# E: unusual-character-in-translation msgid 'A quick brown fox jumps over the lazy dog.': U+FEFF ZERO WIDTH NO-BREAK SPACE msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-report-msgid-bugs.po.tags0000644000000000000000000000010313147102065026065 0ustar0000000000000000W: boilerplate-in-report-msgid-bugs-to 'FULL NAME ' i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-report-msgid-bugs.po0000644000000000000000000000100713147102065025134 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: FULL NAME \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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-project-id-version-2.po0000644000000000000000000000107413147102065025450 0ustar0000000000000000# W: boilerplate-in-project-id-version 'PROJECT VERSION' msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-project-id-version-1.po0000644000000000000000000000107413147102065025447 0ustar0000000000000000# W: boilerplate-in-project-id-version 'PACKAGE VERSION' msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-pot-creation-date.po0000644000000000000000000000111213147102065025076 0ustar0000000000000000# W: boilerplate-in-date POT-Creation-Date: 'YEAR-MO-DA HO:MI+ZONE' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-po-revision-date.po0000644000000000000000000000111113147102065024743 0ustar0000000000000000# W: boilerplate-in-date PO-Revision-Date: 'YEAR-MO-DA HO:MI+ZONE' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-last-translator.po.tags0000644000000000000000000000007613147102065025656 0ustar0000000000000000W: boilerplate-in-last-translator 'FULL NAME ' i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-last-translator.po0000644000000000000000000000100213147102065024707 0ustar0000000000000000msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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: FULL NAME \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-language-team.po0000644000000000000000000000110213147102065024265 0ustar0000000000000000# W: boilerplate-in-language-team 'LANGUAGE ' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-initial-comments.pot.tags0000644000000000000000000000030413147102065026156 0ustar0000000000000000I: boilerplate-in-initial-comments "Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER" I: boilerplate-in-initial-comments 'This file is distributed under the same license as the PACKAGE package.' i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-initial-comments.pot0000644000000000000000000000123613147102065025226 0ustar0000000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" msgid "A quick brown fox jumps over the lazy dog." msgstr "" i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-initial-comments.po.tags0000644000000000000000000000042113147102065025772 0ustar0000000000000000I: boilerplate-in-initial-comments 'Polish translations for PACKAGE package' I: boilerplate-in-initial-comments "Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER" I: boilerplate-in-initial-comments 'This file is distributed under the same license as the PACKAGE package.' i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-initial-comments.po0000644000000000000000000000140113147102065025034 0ustar0000000000000000# Polish translations for PACKAGE package # Polskie tłumaczenia dla pakietu PACKAGE. # Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Jakub Wilk , 2015. # msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/boilerplate-in-content-type.po0000644000000000000000000000110713147102065024214 0ustar0000000000000000# E: boilerplate-in-content-type 'text/plain; charset=CHARSET' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@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 \n" "Language-Team: Latin \n" "Language: la\n" "MIME-Version: 1.0\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." i18nspector-0.25.5/tests/blackbox_tests/ancient-pot-creation-date.po0000644000000000000000000000110313147102065023611 0ustar0000000000000000# W: ancient-date POT-Creation-Date: '1942-04-02 03:37+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 1942-04-02 03:37+0100\n" "PO-Revision-Date: 2012-11-01 14:42+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/ancient-po-revision-date.po0000644000000000000000000000110213147102065023456 0ustar0000000000000000# W: ancient-date PO-Revision-Date: '1942-04-02 03:37+0100' msgid "" msgstr "" "Project-Id-Version: Gizmo Enhancer 1.0\n" "Report-Msgid-Bugs-To: gizmoenhancer@jwilk.net\n" "POT-Creation-Date: 2012-11-01 14:42+0100\n" "PO-Revision-Date: 1942-04-02 03:37+0100\n" "Last-Translator: Jakub Wilk \n" "Language-Team: Latin \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." i18nspector-0.25.5/tests/blackbox_tests/__init__.py0000644000000000000000000003023513147102065020434 0ustar0000000000000000# Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import difflib import errno import inspect import io import multiprocessing as mp import os import re import shlex import signal import subprocess as ipc import sys import traceback import unittest import nose import nose.plugins from .. import tools here = os.path.dirname(__file__) # ---------------------------------------- def this(): ''' Return function that called this function. (Hopefully!) ''' return globals()[inspect.stack()[1][0].f_code.co_name] # ---------------------------------------- _parse_etag = re.compile(r'([A-Z]): (([\w-]+).*)').match def parse_etag(contents, path): match = _parse_etag(contents) if match is None: return t = ETag(match.group(1), path, match.group(2)) return t def etags_from_tagstring(obj, path): try: docstring = obj.tagstring except AttributeError: return for line in docstring.splitlines(): line = line.lstrip() t = parse_etag(line, path) if t is not None: yield t def tagstring(s): def update(x): x.tagstring = s return x return update # ---------------------------------------- class ETag(object): _ellipsis = '<...>' _split = re.compile('({})'.format(re.escape(_ellipsis))).split def __init__(self, code, path, rest): self._s = s = '{code}: {path}: {rest}'.format( code=code, path=path, rest=rest, ) self.tag = rest.split(None, 1)[0] regexp = ''.join( '.*' if chunk == self._ellipsis else re.escape(chunk) for chunk in self._split(s) ) self._regexp = re.compile('^{}$'.format(regexp)) def __eq__(self, other): if isinstance(other, str): return self._regexp.match(other) else: return NotImplemented def __str__(self): return self._s def __repr__(self): return repr(self._s) # ---------------------------------------- def _get_signal_names(): data = dict( (name, getattr(signal, name)) for name in dir(signal) if re.compile('^SIG[A-Z0-9]*$').match(name) ) try: if data['SIGABRT'] == data['SIGIOT']: del data['SIGIOT'] except KeyError: pass try: if data['SIGCHLD'] == data['SIGCLD']: del data['SIGCLD'] except KeyError: pass for name, n in data.items(): yield n, name _signal_names = dict(_get_signal_names()) def get_signal_name(n): try: return _signal_names[n] except KeyError: return str(n) # ---------------------------------------- test_file_extensions = ('.mo', '.po', '.pot', '.pop') # .pop is a special extension to trigger unknown-file-type class Plugin(nose.plugins.Plugin): name = 'po-plugin' enabled = True def options(self, parser, env): pass def wantFile(self, path): if path.endswith(test_file_extensions): if path.startswith(os.path.join(os.path.abspath(here), '')): return True def loadTestsFromFile(self, path): if self.wantFile(path): yield TestCase(path) def wantFunction(self, func): if getattr(func, 'redundant', False): return False class TestCase(unittest.TestCase): def __init__(self, path): super().__init__('_test') self.path = os.path.relpath(path) def _test(self): _test_file(self.path, basedir=None) def __str__(self): return self.path class SubprocessError(Exception): pass def queue_get(queue, process): ''' Remove and return an item from the queue. Block until the process terminates. ''' while True: try: return queue.get(timeout=1) # This semi-active waiting is ugly, but there doesn't seem be any # obvious better way. except mp.queues.Empty: if process.exitcode is None: continue else: raise def run_i18nspector(options, path): commandline = os.environ.get('I18NSPECTOR_COMMANDLINE') if commandline is None: # We cheat here a bit, because exec(3)ing is very expensive. # Let's load the needed Python modules, and use multiprocessing to # “emulate” the command execution. import lib.cli assert lib.cli # make pyflakes happy prog = os.path.join(here, os.pardir, os.pardir, 'i18nspector') commandline = [sys.executable, prog] queue = mp.Queue() child = mp.Process( target=_mp_run_i18nspector, args=(prog, options, path, queue) ) child.start() [stdout, stderr] = ( s.splitlines() for s in queue_get(queue, child) ) child.join() rc = child.exitcode else: commandline = shlex.split(commandline) commandline += options commandline += [path] fixed_env = dict(os.environ, PYTHONIOENCODING='UTF-8') child = ipc.Popen(commandline, stdout=ipc.PIPE, stderr=ipc.PIPE, env=fixed_env) stdout, stderr = ( s.decode('UTF-8').splitlines() for s in child.communicate() ) rc = child.poll() assert isinstance(rc, int) if rc == 0: return stdout if rc < 0: message = ['command was interrupted by signal {sig}'.format(sig=get_signal_name(-rc))] # pylint: disable=invalid-unary-operand-type else: message = ['command exited with status {rc}'.format(rc=rc)] message += [''] if stdout: message += ['stdout:'] message += ['| ' + s for s in stdout] + [''] else: message += ['stdout: (empty)'] if stderr: message += ['stderr:'] message += ['| ' + s for s in stderr] else: message += ['stderr: (empty)'] raise SubprocessError('\n'.join(message)) def _mp_run_i18nspector(prog, options, path, queue): with open(prog, 'rt', encoding='UTF-8') as file: code = file.read() sys.argv = [prog] + list(options) + [path] orig_stdout = sys.stdout orig_stderr = sys.stderr code = compile(code, prog, 'exec') io_stdout = io.StringIO() io_stderr = io.StringIO() gvars = dict( __file__=prog, ) (sys.stdout, sys.stderr) = (io_stdout, io_stderr) try: try: exec(code, gvars) # pylint: disable=exec-used finally: (sys.stdout, sys.stderr) = (orig_stdout, orig_stderr) stdout = io_stdout.getvalue() stderr = io_stderr.getvalue() except SystemExit: queue.put([stdout, stderr]) raise except: # pylint: disable=bare-except exctp, exc, tb = sys.exc_info() stderr += ''.join( traceback.format_exception(exctp, exc, tb) ) queue.put([stdout, stderr]) sys.exit(1) raise # hi, pydiatra! else: queue.put([stdout, stderr]) sys.exit(0) def assert_emit_tags(path, etags, *, options=()): etags = list(etags) stdout = run_i18nspector(options, path) expected_failure = os.path.basename(path).startswith('xfail-') if stdout != etags: if expected_failure: raise nose.SkipTest('expected failure') str_etags = [str(x) for x in etags] message = ['Tags differ:', ''] diff = list( difflib.unified_diff(str_etags, stdout, n=9999) ) message += diff[3:] raise AssertionError('\n'.join(message)) elif expected_failure: raise AssertionError('unexpected success') class TestFileSyntaxError(Exception): pass def _parse_test_header_file(file, path, *, comments_only): etags = [] options = [] for n, line in enumerate(file): orig_line = line if comments_only: if n == 0 and line.startswith('#!'): continue if line.startswith('# '): line = line[2:] else: break if line.startswith('--'): options += shlex.split(line) else: etag = parse_etag(line, path) if etag is None: if comments_only: break else: raise TestFileSyntaxError(orig_line) etags += [etag] return etags, options def _parse_test_headers(path): # .tags: try: file = open(path + '.tags', encoding='UTF-8') except IOError as exc: if exc.errno != errno.ENOENT: raise else: with file: return _parse_test_header_file(file, path, comments_only=False) # .gen: try: file = open(path + '.gen', encoding='UTF-8', errors='ignore') except IOError as exc: if exc.errno != errno.ENOENT: raise else: with file: return _parse_test_header_file(file, path, comments_only=True) # : with open(path, 'rt', encoding='UTF-8', errors='ignore') as file: return _parse_test_header_file(file, path, comments_only=True) def _test_file(path, basedir=here): if basedir is not None: path = os.path.relpath(os.path.join(basedir, path), start=os.getcwd()) options = [] etags, options = _parse_test_headers(path) assert_emit_tags(path, etags, options=options) def get_coverage_for_file(path): etags, options = _parse_test_headers(path) del options return (t.tag for t in etags) def get_coverage_for_function(fn): for etag in etags_from_tagstring(fn, ''): yield etag.tag def _get_test_filenames(): for root, dirnames, filenames in os.walk(here): del dirnames for filename in filenames: if not filename.endswith(test_file_extensions): continue yield os.path.join(root, filename) def test_file(): for filename in _get_test_filenames(): path = os.path.relpath(filename, start=here) yield _test_file, path test_file.redundant = True # not needed if the plugin is enabled @tagstring(''' E: os-error No such file or directory ''') def test_os_error_no_such_file(): with tools.temporary_directory() as tmpdir: path = os.path.join(tmpdir, 'nonexistent.po') expected = etags_from_tagstring(this(), path) assert_emit_tags(path, expected) @tagstring(''' E: os-error Permission denied ''') def test_os_error_permission_denied(): if os.getuid() == 0: raise nose.SkipTest('this test must not be run as root') with tools.temporary_directory() as tmpdir: path = os.path.join(tmpdir, 'denied.po') with open(path, 'wb'): pass os.chmod(path, 0) expected = etags_from_tagstring(this(), path) assert_emit_tags(path, expected) # ---------------------------------------- def get_coverage(): coverage = set() for filename in _get_test_filenames(): for tag in get_coverage_for_file(filename): coverage.add(tag) for objname, obj in globals().items(): if not objname.startswith('test_'): continue for tag in get_coverage_for_function(obj): coverage.add(tag) return coverage # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/tests/__init__.py0000644000000000000000000000010513147102065015416 0ustar0000000000000000# pylint: disable=pointless-statement ... # Python >= 3 is required i18nspector-0.25.5/private/0000755000000000000000000000000013147102074013621 5ustar0000000000000000i18nspector-0.25.5/private/update-version0000755000000000000000000000035313147102065016515 0ustar0000000000000000#!/bin/sh version=${1:?"no version number provided"} set -e -x dch -m -v "$version" -u low -c doc/changelog sed -i -E -e "s/(__version__) = '\S+'/\1 = '$version'/" lib/*.py sed -i -E -e "s/^(:version: \S+) \S+$/\1 $version/" doc/*.txt i18nspector-0.25.5/private/update-timezones0000755000000000000000000000633113147102065017047 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2013-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import collections import datetime import os import subprocess as ipc import sys import pytz # pylint: disable=wrong-import-position sys.path[0] += '/..' basedir = sys.path[0] import lib.gettext as gettext def get_tzdata_version(): version = pytz.OLSON_VERSION if os.path.exists('/etc/debian_version'): # On Debian systems, pytz uses the system timezone database, # so pytz.OLSON_VERSION is not reliable. version = ipc.check_output(['dpkg-query', '-Wf', '${Version}', 'tzdata']) version = version.decode('ASCII') version, revision = version.rsplit('-', 1) del revision return version def main(): minyear = gettext.epoch.year maxyear = datetime.date.today().year + 1 tzdata = collections.defaultdict(set) for tzname in pytz.all_timezones: if tzname.startswith('Etc/'): continue tz = pytz.timezone(tzname) try: timestamps = list(tz._utc_transition_times) # pylint: disable=protected-access except AttributeError: timestamps = [] timestamps += [datetime.datetime(minyear, 1, 1)] for timestamp in timestamps: if not (minyear <= timestamp.year <= maxyear): continue timestamp = tz.fromutc(timestamp) code, offset = timestamp.strftime('%Z %z').split() assert 3 <= len(code) <= 6 tzdata[code].add(offset) path = os.path.join(basedir, 'data', 'timezones') sys.stdout = open(path + '.tmp', 'wt', encoding='ASCII') print('''\ # This file has been generated automatically by private/update-timezones. # Do not edit. # Timezone database version: {version} # Last update: {today} '''.format( version=get_tzdata_version(), today=datetime.date.today(), )) print('[timezones]') for code, offsets in sorted(tzdata.items()): print('{code} = {offsets}'.format(code=code, offsets=' '.join(sorted(offsets)))) print() print('# vi''m:ft=dosini') sys.stdout.close() os.rename(path + '.tmp', path) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/update-tag-coverage0000755000000000000000000000400113147102065017366 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import sys sys.path[0] += '/..' from lib import tags from tests import blackbox_tests def main(): coverage = blackbox_tests.get_coverage() path = os.path.join( os.path.dirname(blackbox_tests.__file__), 'coverage.txt' ) sys.stdout = open(path + '.tmp', 'wt', encoding='ASCII') print('Generated automatically by private/update-tag-coverage. ' 'Do not edit.\n') for tag in tags.iter_tags(): check = 'X' if tag.name in coverage else ' ' print('[{check}] {tag}'.format(check=check, tag=tag.name)) sys.stdout.close() os.rename(path + '.tmp', path) rc = 0 for tag in sorted(set(coverage) - set(t.name for t in tags.iter_tags())): print('update-coverage: error: unknown tag {tag}'.format(tag=tag), file=sys.stderr) rc = 1 sys.exit(rc) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/update-iso-codes0000755000000000000000000001163113147102065016716 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import datetime import functools import os import subprocess as ipc import sys import json class Panic(ValueError): pass @functools.lru_cache() def get_iso_codes_version(): version = ipc.check_output(['pkg-config', 'iso-codes', '--modversion']) version = version.decode('ASCII').strip() return version @functools.lru_cache() def get_iso_codes_dir(): prefix = ipc.check_output(['pkg-config', 'iso-codes', '--variable=prefix']) prefix = prefix.decode('ASCII').strip() return '{prefix}/share/iso-codes/json'.format(prefix=prefix) def main(): basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) path = os.path.join(basedir, 'data', 'iso-codes') sys.stdout = open(path + '.tmp', 'wt', encoding='UTF-8') print('''\ # This file has been generated automatically by private/update-iso-codes. # Do not edit. # iso-codes version: {version} # Last update: {today} '''.format(version=get_iso_codes_version(), today=datetime.date.today())) generate_iso_639() generate_iso_3166() sys.stdout.close() os.rename(path + '.tmp', path) def load_json(path): with open(path, 'rt', encoding='UTF-8') as file: return json.load(file) def generate_iso_639(): # ======================= # ISO 639: language codes # ======================= l2t_to_2b = {} iso_639 = {} data = load_json(get_iso_codes_dir() + '/iso_639-2.json') for item in data['639-2']: l2t = item['alpha_3'] l2b = item.get('bibliographic', l2t) if l2b == l2t == 'qaa-qtz': continue for l in l2b, l2t: if len(l) != 3: raise Panic('len({!r}) != 3'.format(l)) if l2b != l2t: l2t_to_2b[l2t] = l2b iso_639 = {} data = load_json(get_iso_codes_dir() + '/iso_639-3.json') for item in data['639-3']: code = item['alpha_3'] if len(code) != 3: raise Panic('len({!r}) != 3'.format(code)) code1 = item.get('alpha_2') code2 = item.get('terminology') if code2 is None: # We're not interested in languages that are not in 639-2 (yet?). continue if code2 != code: raise Panic('{!r} != {!r}'.format(code, code2)) scope = item['scope'] if scope == 'S': # Not a real language, ignore. continue elif scope in {'M', 'I'}: pass else: raise Panic('unknown scope: {!r}'.format(scope)) reference_name = item['name'] if reference_name in iso_639: raise Panic('duplicate reference name: {!r}'.format(reference_name)) if code1 is not None: if len(code1) == 2: codelist = [code1, code] else: raise Panic('len({!r}) != 2'.format(code1)) else: codelist = [code] try: codelist += [l2t_to_2b[code]] except KeyError: pass iso_639[reference_name] = codelist print('[language-codes]') iso_639_rev = {} for code, *aliases in iso_639.values(): for alias in aliases: iso_639_rev[alias] = code if not aliases: iso_639_rev[code] = '' for alias, code in sorted(iso_639_rev.items()): print('{} = {}'.format(alias, code).rstrip()) print() def generate_iso_3166(): # ========================= # ISO 3166: territory codes # ========================= iso_3166 = set() data = load_json(get_iso_codes_dir() + '/iso_3166-1.json') for item in data['3166-1']: cc = item['alpha_2'] iso_3166.add(cc) print('[territory-codes]') for cc in sorted(iso_3166): print('{} ='.format(cc)) print() print('# vi''m:ft=dosini') if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/update-header-fields0000755000000000000000000000517513147102065017533 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import subprocess as ipc import tempfile xgettexts = {'xgettext', 'pygettext'} def main(): os.environ['LC_ALL'] = 'C' xgettext_versions = { ipc.check_output([xgettext, '--version']).splitlines()[0].decode('ASCII', 'replace') for xgettext in xgettexts } with tempfile.TemporaryDirectory(prefix='i18nspector.private.') as tmpdir: path = os.path.join(tmpdir, 'dummy.c') with open(path, 'wt', encoding='ASCII') as file: file.write('ngettext("1", "2");') pos = { ipc.check_output([xgettext, '-o', '-', path]) for xgettext in xgettexts } headers = set() for po in pos: po = po.decode('ASCII').splitlines() for line in po: if line.startswith('"'): header = line[1:].split(':', 1)[0] headers.add(header) basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) path = os.path.join(basedir, 'data', 'header-fields') with open(path, 'wt', encoding='ASCII') as file: print('''\ # This file has been generated automatically by # private/update-header-fields. Do not edit. # # The following string extraction tools have been used:\ ''', file=file) for xgettext_version in sorted(xgettext_versions): print('# *', xgettext_version, file=file) print(file=file) for header in sorted(headers): print(header, file=file) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/update-charmaps0000755000000000000000000000447313147102065016635 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2013-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import sys # pylint: disable=wrong-import-position sys.path[0] += '/..' basedir = sys.path[0] from lib import encodings from lib import iconv def generate_charmap(encoding): encoding = encoding.upper() print(encoding, '...', end=' ') sys.stdout.flush() path = '{base}/data/charmaps/{enc}'.format(base=basedir, enc=encoding) n = 0 us = [] for b in range(0x100): b = bytes([b]) try: u = iconv.decode(b, encoding) except UnicodeDecodeError: u = '\uFFFE' else: n += 1 assert len(u) == 1 us += [u] if n <= 128: print('SKIP (not 8-bit)') return assert len(us) == 0x100 with open(path, 'wb') as file: us = ''.join(us) assert len(us) == 0x100 file.write(us.encode('UTF-8')) print('ok') def main(): # pylint: disable=protected-access for encoding, codec in encodings._portable_encodings.items(): if codec is None: generate_charmap(encoding) for encoding in encodings._extra_encodings: generate_charmap(encoding) # pylint: enable=protected-access if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/update-branch-coverage0000755000000000000000000000443413147102065020062 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2014-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import glob import io import os import sys import nose import nose.plugins.cover class Coverage(nose.plugins.cover.Coverage): stream = None def report(self, stream): return super().report(self.stream) basedir = os.path.join( os.path.dirname(__file__), os.pardir, ) def main(): os.chdir(basedir) module_glob = os.path.join('tests', 'test_*.py') modules = glob.glob(module_glob) argv = [ sys.argv[0], '--with-coverage', '--cover-package=lib', '--cover-erase', ] + modules path = os.path.join( 'tests', 'coverage.txt' ) plugin = Coverage() report_stream = plugin.stream = io.StringIO() print('Generated automatically by private/update-branch-coverage. ' 'Do not edit.\n', file=report_stream) ok = nose.run(argv=argv, plugins=[plugin]) if not ok: sys.exit(1) report_stream.seek(0) with open(path + '.tmp', 'wt', encoding='ASCII') as file: for line in report_stream: line = line.rstrip() print(line, file=file) os.rename(path + '.tmp', path) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/update-blackbox-tests0000755000000000000000000000325513147102065017761 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import os import subprocess as ipc def main(): test_dir = '{here}/../tests/blackbox_tests/'.format( here=os.path.dirname(__file__), ) os.chdir(test_dir) for generator in os.listdir('.'): if not generator.endswith('.gen'): continue target = generator[:-4] tmp_target = target + '.tmp' env = dict(os.environ, here='.', target=tmp_target) ipc.check_call(os.path.join('.', generator), env=env) os.rename(tmp_target, target) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/tags-as-rst0000755000000000000000000000423113147102065015714 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import io import re import sys sys.path[0] += '/..' from lib import tags as tagmod def output_tags_rst(tags): print('''\ .. This file has been generated automatically by private/tags-as-rst. Do not edit. ''') for tag in tags: tagname = tag.name print(tagname) print('~' * len(tagname)) print(tag.description) print() if tag.references: print('References:', end='\n\n') for ref in tag.references: match = re.match(r'\A(?P[\w-]+)[(](?P
[0-9])[)]\Z', ref) if match is not None: ref = r'**{name}**\ ({section})'.format(**match.groupdict()) print(' |', ref) print() print('Severity, certainty:', end='\n\n') print(' {}, {}'.format(tag.severity, tag.certainty)) print() def main(): sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='UTF-8') output_tags_rst(tagmod.iter_tags()) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/run-pylint0000755000000000000000000000414613147102065015675 0ustar0000000000000000#!/bin/sh # Copyright © 2015-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. PYTHON=${PYTHON:-python3} "$PYTHON" -m pylint --version >/dev/null || exit 1 if [ $# -eq 0 ] then pyscripts=$(grep -l -r '^#!.*python' .) set -- lib tests tests/fuzzing/*/*.py $pyscripts fi whitelist= ignored= for ext in afl apt_pkg do if "$PYTHON" -c "import $ext" 2>/dev/null then whitelist="$whitelist,$ext" else ignored="$ignored,$ext" fi done if [ -z "${ignored%%*apt*}" ] then ignored="$ignored,apt" fi set -- --extension-pkg-whitelist="${whitelist#,}" --ignored-modules="${ignored#,}" "$@" log=$(mktemp -t pylint.XXXXXX) "$PYTHON" -m pylint "$@" > "$log" || [ $? != 1 ] ! grep '^\w:' "$log" \ | grep -v ': missing-docstring \[\w' \ | grep -v -P '^\w: (?!lib/).+: missing-docstring ' \ | grep -v ": redefined-builtin \\[.*\\] Redefining built-in 'input'" \ | grep -v -P "^\w: tests/.+: wrong-import-order \\[.*\\] external import \"import lib[.].+\" comes before \"from . import tools\"" \ | LC_ALL=C sort -k2 \ | grep '.' || exit 1 rm "$log" # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/run-pyflakes0000755000000000000000000000247613147102065016200 0ustar0000000000000000#!/bin/sh # Copyright © 2015-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. PYTHON=${PYTHON:-python3} if [ $# -eq 0 ] then set -- \ $(grep -l -r --exclude='*.swp' '^#!.*python' .) \ $(find . -name '*.py') fi exec "$PYTHON" -m pyflakes "$@" # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/run-pydiatra0000755000000000000000000000245313147102065016172 0ustar0000000000000000#!/bin/sh # Copyright © 2016-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. PYTHON=${PYTHON:-python3} if [ $# -eq 0 ] then set -- \ $(grep -l -r '^#!.*python' .) \ $(find . -name '*.py') fi exec "$PYTHON" -m pydiatra "$@" # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/online-check-gettext-data0000755000000000000000000001361213147102065020502 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import re import sys import urllib.request sys.path[0] += '/..' from lib import gettext from lib import ling def strip_plural_forms(s): # Remove superfluous parentheses around the plural formula: return re.sub(r'\bplural=\((.*?)\);$', r'plural=\1;', s) def urlopen(url): return urllib.request.urlopen(url, cadefault=True) def do_plurals(): regexp = re.compile(r'\s+{\s*"([a-zA-Z_]+)".*"(nplurals.*?)"') url = 'http://git.savannah.gnu.org/cgit/gettext.git/plain/gettext-tools/src/plural-table.c' okay = set() with urlopen(url) as file: for line in file: line = line.decode('ASCII').rstrip() match = regexp.match(line) if match is None: continue language, gettext_plural_forms = match.groups() language = ling.parse_language(language) gettext_plural_forms = strip_plural_forms(gettext_plural_forms) our_plural_forms = language.get_plural_forms() or [] if gettext_plural_forms not in our_plural_forms: print('[{}]'.format(language)) if our_plural_forms: if len(our_plural_forms) == 1: print('# plural-forms =', *our_plural_forms) else: print('# plural-forms =') for pf in our_plural_forms: print('# ', pf) print('plural-forms =', gettext_plural_forms) print() else: okay.add(str(language)) n_okay = len(okay) print('# No plural-forms changes required for {} languages'.format(n_okay)) print() blacklist = { # https://lists.gnu.org/archive/html/bug-gettext/2015-06/msg00057.html ('pap', 'AN'), } def do_languages(): url = 'http://git.savannah.gnu.org/cgit/gettext.git/plain/gettext-tools/src/msginit.c' okay = set() with urlopen(url) as file: contents = file.read() match = re.compile(br'locales_with_principal_territory\s*\[\]\s*=\s*[{](.*?)[}]', re.DOTALL).search(contents) if match is None: raise ValueError contents = match.group(1) contents = re.compile(br'/[*].*?[*]/', re.DOTALL).sub(b'', contents) contents = contents.decode('ASCII') data = {} primary_languages = set(ling.get_primary_languages()) for item in re.findall(r'"(\w+)"', contents): language, gettext_cc = item.split('_') if language not in primary_languages: continue data[language] = gettext_cc our_cc = ling.parse_language(language).get_principal_territory_code() if our_cc != gettext_cc: if (language, gettext_cc) in blacklist: if our_cc is not None: okay.add(language) continue print('[{}]'.format(language)) if our_cc is not None: print('# WAS: principal-territory =', our_cc) if ling.lookup_territory_code(gettext_cc) is None: print('# BAD: principal-territory =', gettext_cc) else: print('principal-territory =', gettext_cc) print() else: okay.add(language) for language in sorted(primary_languages): if '_' in language: continue cc = ling.parse_language(language).get_principal_territory_code() if cc is None: continue if language not in data: print('# WAS: [{}]'.format(language)) print('# WAS: principal-territory =', cc) print() n_okay = len(okay) print('# No principal-territory changes required for {} languages'.format(n_okay)) print() def do_string_formats(): url = 'http://git.savannah.gnu.org/cgit/gettext.git/plain/gettext-tools/src/message.c' with urlopen(url) as file: contents = file.read() match = re.compile(br'\sformat_language\s*\[NFORMATS\]\s*=\s*[{](.*?)[}]', re.DOTALL).search(contents) if match is None: raise ValueError contents = match.group(1) contents = re.compile(br'/[*].*?[*]/', re.DOTALL).sub(b'', contents) contents = contents.decode('ASCII') their_formats = frozenset( re.findall(r'"([\w-]+)"', contents) ) our_formats = frozenset( gettext.string_formats.keys() ) difference = their_formats ^ our_formats print('[formats]') for fmt in difference: if fmt in our_formats: print('# MISSING: {fmt} = ...'.format(fmt=fmt)) else: print('{fmt} = # TODO'.format(fmt=fmt)) n_okay = len(our_formats - difference) print('# No changes required for {} string formats'.format(n_okay)) print() def main(): do_plurals() do_languages() do_string_formats() if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/online-build-po-corpus0000755000000000000000000001713113147102065020060 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import contextlib import gzip import os import re import subprocess import sys import tarfile import tempfile import urllib.parse import apt import apt_pkg def is_po_path(path): return path.endswith(('.po', '.pot')) class Fetcher(object): def __init__(self, urlbase): self._urlbase = urlbase self._progress = apt.progress.text.AcquireProgress() self._acquire = apt_pkg.Acquire(self._progress) self._files = [] self._tmpdir = tempfile.TemporaryDirectory(prefix='i18nspector.private.') def add(self, url, name): url = urllib.parse.urljoin(self._urlbase, url) self._files += [apt_pkg.AcquireFile( self._acquire, uri=url, descr=url, destfile=os.path.join(self._tmpdir.name, name) )] def run(self): acq = self._acquire rc = acq.run() if rc != acq.RESULT_CONTINUE: raise RuntimeError('fetching failed') for acqfile in self._files: if acqfile.status != acqfile.STAT_DONE: raise RuntimeError('fetching failed') yield acqfile.destfile def __enter__(self): return self def __exit__(self, exc, value, tb): self.close() def close(self): self._tmpdir.cleanup() _package_name_re = re.compile(r'\A[a-z0-9][a-z0-9.+-]+\Z') def validate_package_name(pkg): if _package_name_re.match(pkg): pass else: raise RuntimeError('invalid package name: {pkg!r}'.format(pkg=pkg)) @contextlib.contextmanager def chdir(new_cwd): orig_cwd = os.getcwd() try: os.chdir(new_cwd) yield finally: os.chdir(orig_cwd) default_mirror = 'http://deb.debian.org/debian' default_dist = 'stable' default_areas = 'main' def main(): ap = argparse.ArgumentParser() ap.add_argument('--mirror', metavar='URL', default=default_mirror, help='Debian mirror to use (default: {mirror})'.format(mirror=default_mirror) ) ap.add_argument('--distribution', metavar='DIST', default=default_dist, help='Debian distribution to use (default: {dist})'.format(dist=default_dist) ) ap.add_argument('--areas', metavar='AREA[,AREA...]', default=default_areas, help='archive areas to use (default: {areas})'.format(areas=default_areas) ) ap.add_argument('--output', metavar='TARFILE', required=True, help='output tar file' ) options = ap.parse_args() output = options.output tarmode = 'w|' for ext in 'gz', 'bz2', 'xz': if options.output.endswith('.' + ext): tarmode += ext break tar = tarfile.open(output, mode=tarmode) mirror = options.mirror dist = options.distribution areas = options.areas.split(',') def tarfilter(tarinfo): tarinfo.uid = tarinfo.gid = 0 tarinfo.uname = tarinfo.gname = 'root' tarinfo.mode &= 0o700 tarinfo.mode |= 0o644 if tarinfo.mode & 0o100: tarinfo.mode |= 0o111 tarinfo.name = 'po-corpus-{dist}/{name}'.format(dist=dist, name=tarinfo.name) return tarinfo subprocess.check_call(['dpkg-source', '--version'], stdout=subprocess.DEVNULL) for area in areas: urlbase = '{mirror}/dists/{dist}/{area}/'.format(mirror=mirror, dist=dist, area=area) with Fetcher(urlbase=urlbase) as fetcher: fetcher.add('Contents-source.gz', 'Contents.gz') fetcher.add('source/Sources.xz', 'Sources.xz') [contents_path, sources_path] = fetcher.run() interesting_packages = set() with gzip.open(contents_path, 'rt', encoding='UTF-8', newline='\n') as file: for line in file: try: path, packages = line.rsplit('\t', 1) except ValueError: raise RuntimeError('malfomed line: {!r}'.format(line)) if is_po_path(path): packages = packages.rstrip('\n').split(',') for pkg in packages: validate_package_name(pkg) interesting_packages.update(packages) for para in apt_pkg.TagFile(sources_path): pkg = para['Package'] if pkg not in interesting_packages: continue fileinfo = para['Files'].splitlines() dscname = None names = set() for line in fileinfo: _, name = line.rsplit(' ', 1) ok = ( name.startswith(pkg + '_') and '/' not in name and name not in names ) if not ok: raise RuntimeError('Package {pkg}: bad Files line: {line!r}'.format(pkg=pkg, line=line)) names.add(name) if name.endswith('.dsc'): if dscname is not None: raise RuntimeError('Package {pkg}: duplicate .dsc file'.format(pkg=pkg)) dscname = name if dscname is None: raise RuntimeError('Package {pkg}: missing .dsc file'.format(pkg=pkg)) names = list(names) names.sort(key=dscname.__eq__) pkgdir = para['Directory'] pkgurlbase = '{mirror}/{dir}/'.format(mirror=mirror, dir=pkgdir) with Fetcher(urlbase=pkgurlbase) as pkgfetcher: for name in names: pkgfetcher.add(name, name) for path in pkgfetcher.run(): pass dscpath = path unpacked = dscpath[:-4] subprocess.check_call(['dpkg-source', '-x', dscpath, unpacked], stdout=sys.stderr) with chdir(os.path.dirname(unpacked)): for unp_root, unp_dirs, unp_files in os.walk(os.path.basename(unpacked)): try: unp_dirs.remove('.pc') except ValueError: pass for unp_file in unp_files: if is_po_path(unp_file): unp_path = os.path.join(unp_root, unp_file) tar.add(unp_path, filter=tarfilter) tar.close() if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/collect-metadata0000755000000000000000000001136013147102065016753 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import collections import itertools import os import re import sys import polib def init_polib(): # Happily decode any file, even when encoding declaration is broken or # missing. polib.default_encoding = 'ISO-8859-1' is_sane_field_name = re.compile('^[a-zA-Z-]+$').match _extract_address = re.compile(r'''^(?: .*< ( [^<>]+@[^<>]+ ) >\s* | ( \S+@\S+ ) | .*< ( https?://[^<>]+ ) >\s* | .*[(] ( https?://[^()]+ ) [)]\s* | \s* (https?://\S+) \s* )$''', re.VERBOSE).match def extract_address(s): match = _extract_address(s) if match is None: return [result] = filter(None, match.groups()) return result def main(): init_polib() ap = argparse.ArgumentParser() ap.add_argument('files', metavar='', nargs='*') ap.add_argument('-F', '--field', help='only this field') ap.add_argument('--insane', action='store_true', help='allow insane field names') ap.add_argument('--extract-addresses', action='store_true') ap.add_argument('--all-test-cases', action='store_true') ap.add_argument('--plural-only', action='store_true', help='consider only translations with plural forms') ap.add_argument('--stdin', action='store_true', help='read filenames from stdin') options = ap.parse_args() metadata = collections.defaultdict(collections.Counter) if options.all_test_cases: test_cases = collections.defaultdict(set) else: test_cases = {} files = options.files if options.stdin: files = itertools.chain( files, (l.rstrip() for l in sys.stdin) ) for path in files: print(path, end=' ... ', file=sys.stderr) sys.stderr.flush() try: extension = os.path.splitext(path)[-1] if extension == '.po': constructor = polib.pofile elif extension in ('.mo', '.gmo'): constructor = polib.mofile else: raise NotImplementedError(repr(extension)) file = constructor(path) if options.plural_only: for msg in file.translated_entries(): if msg.msgstr_plural: break else: print('skip', file=sys.stderr) sys.stderr.flush() continue for k, v in file.metadata.items(): if (not is_sane_field_name(k)) and (not options.insane): continue if not (options.field is None or k == options.field): continue if options.extract_addresses: v = extract_address(v) metadata[k][v] += 1 if options.all_test_cases: test_cases[k, v].add(path) else: test_cases[k, v] = path file = None except Exception as exc: # pylint: disable=broad-except print('error:', exc, file=sys.stderr) else: print('ok', file=sys.stderr) sys.stderr.flush() for key, values in sorted(metadata.items()): print('{key!r}:'.format(key=key)) for value, n in values.most_common(): if options.all_test_cases: print(' {n:6} {value!r}'.format(n=n, value=value)) for path in sorted(test_cases[key, value]): print(' + {path!r}'.format(path=path)) else: path = test_cases[key, value] print(' {n:6} {value!r}; test-case: {path!r}'.format(n=n, value=value, path=path)) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/collect-characters0000755000000000000000000000621513147102065017315 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import collections import itertools import os import sys import polib def init_polib(): # don't assume UTF-8 encoding polib.default_encoding = 'ASCII' def main(): init_polib() ap = argparse.ArgumentParser() ap.add_argument('files', metavar='', nargs='*') ap.add_argument('--skip-ascii', action='store_true', help='skip ASCII characters') ap.add_argument('--stdin', action='store_true', help='read filenames from stdin') options = ap.parse_args() files = options.files if options.stdin: files = itertools.chain( files, (l.rstrip() for l in sys.stdin) ) char_counter = collections.Counter() char_files = collections.defaultdict(set) n_files = 0 for path in files: print(path, end=' ... ', file=sys.stderr) sys.stderr.flush() try: extension = os.path.splitext(path)[-1] if extension == '.po': constructor = polib.pofile elif extension in ('.mo', '.gmo'): constructor = polib.mofile else: raise NotImplementedError(repr(extension)) file = constructor(path) for message in file.translated_entries(): for text in itertools.chain([message.msgstr], message.msgstr_plural.values()): for ch in text: char_counter[ch] += 1 char_files[ch].add(path) file = None except Exception as exc: # pylint: disable=broad-except print('error:', exc, file=sys.stderr) else: print('ok', file=sys.stderr) sys.stderr.flush() n_files += 1 for n, ch in sorted(((n, ch) for ch, n in char_counter.items()), reverse=True): if options.skip_ascii and ord(ch) < 0x80: continue filecov = len(char_files[ch]) / n_files print('{n:6} [{fc:6.1%}] {ch!r}'.format(n=n, fc=filecov, ch=ch)) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/check-rst0000755000000000000000000000273013147102065015434 0ustar0000000000000000#!/bin/sh # Copyright © 2016-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. here=$(dirname "$0") rst2xml=$(command -v rst2xml) \ || rst2xml=$(command -v rst2xml.py) \ || { printf 'rst2xml not found\n' >&2; exit 1; } options='--input-encoding=UTF-8 --output-encoding=UTF-8 --strict' if [ $# -eq 0 ] then grep -rwl 'ft=rst' doc/ else printf '%s\n' "$@" fi | xargs -L1 -t -I{} "$rst2xml" $options {} /dev/null # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/private/add-languages0000755000000000000000000000547313147102065016254 0ustar0000000000000000#!/usr/bin/env python3 # Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse import functools import subprocess as ipc import sys import json @functools.lru_cache() def get_iso_codes_dir(): prefix = ipc.check_output(['pkg-config', 'iso-codes', '--variable=prefix']) prefix = prefix.decode('ASCII').strip() return '{prefix}/share/iso-codes/json'.format(prefix=prefix) def main(): ap = argparse.ArgumentParser() ap.add_argument('languages', metavar='', nargs='+') options = ap.parse_args() languages = set(options.languages) path = get_iso_codes_dir() + '/iso_639-2.json' with open(path, 'rt', encoding='UTF-8') as file: data = json.load(file) for item in data['639-2']: ll = item.get('alpha_2') lll_t = item.get('alpha_3') lll_b = item.get('bibliographic') requested = None for lang in ll, lll_b, lll_t: if lang in languages: assert lang is not None requested = lang languages.remove(lang) if requested is None: continue lang = ll or lll_t if lang is None: raise ValueError names = [ s.strip() for s in item.get('name').split(';') ] print('[{}]'.format(requested)) if lang != requested: print('# XXX mapping {} => {}'.format(requested, lang)) if len(names) == 1: print('names =', *names) else: print('names =') for name in names: print('', name) print() for lang in sorted(languages): print('# Unknown language code: {}'.format(lang)) sys.exit(len(languages) > 0) if __name__ == '__main__': main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/0000755000000000000000000000000013147102076012717 5ustar0000000000000000i18nspector-0.25.5/lib/xml.py0000644000000000000000000000462513147102065014076 0ustar0000000000000000# Copyright © 2014 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' XML support ''' import random import string import xml.parsers.expat SyntaxError = xml.parsers.expat.ExpatError # pylint: disable=redefined-builtin _xe = ( 'i18nspector.' + ''.join(random.choice(string.ascii_lowercase) for x in range(12)) ) _source = '''\ ]> &{xe}; '''.format(xe=_xe).encode('ASCII') def check_fragment(s): ''' check if the string could be a well-formed XML fragment ''' def ee_handler(context, base, systemid, publicid): assert base is None assert systemid == _xe assert publicid is None eparser = parser.ExternalEntityParserCreate(context) eparser.Parse(s.encode('UTF-8'), True) return 1 parser = xml.parsers.expat.ParserCreate('UTF-8') parser.ExternalEntityRefHandler = ee_handler parser.Parse(_source, True) # https://www.w3.org/TR/REC-xml/#NT-NameStartChar # pylint: disable=line-too-long _start_char = ':A-Z_a-z\xC0-\xD6\xD8-\xF6\xF8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\U00010000-\U000EFFFF' _next_char = _start_char + '.0-9\xB7\u0300-\u036F\u203F\u2040-' name_re = '[{0}][{1}]*'.format(_start_char, _next_char) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/terminal.py0000644000000000000000000000606213147102065015106 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' color terminal support ''' import functools import re class _dummy_curses: @staticmethod def tigetstr(*args, **kwargs): del args, kwargs return b'' @staticmethod def tparm(*args, **kwargs): del args, kwargs return b'' _curses = _dummy_curses class colors: black = NotImplemented red = NotImplemented green = NotImplemented yellow = NotImplemented blue = NotImplemented magenta = NotImplemented cyan = NotImplemented white = NotImplemented _strip_delay = functools.partial( re.compile(b'[$]<([0-9]*[.])?[0-9]+([/*]|[*][/])?>').sub, b'' ) def attr_fg(i): ''' returns a string that changes the foreground color ''' s = _curses.tigetstr('setaf') or b'' s = _strip_delay(s) s = _curses.tparm(s, i) return s.decode() def attr_reset(): ''' returns a string that resets all attributes ''' s = _curses.tigetstr('sgr0') or b'' s = _strip_delay(s) return s.decode() def initialize(): ''' initialize the terminal ''' global _curses # pylint: disable=global-statement try: import curses as _curses # pylint: disable=redefined-outer-name except ImportError: return try: _curses.setupterm() except _curses.error: _curses = _dummy_curses return try: _curses.tparm(b'x') except TypeError: # curses.tparm() is broken in early versions of Python 3.2: # https://bugs.python.org/issue10570 _curses = _dummy_curses return try: _curses.tigetstr('x') except TypeError: # curses.tigetstr() is broken in PyPy 3: # https://bitbucket.org/pypy/pypy/issues/1997 _curses = _dummy_curses return for key, value in vars(_curses).items(): if key.startswith('COLOR_'): key = key[6:].lower() getattr(colors, key) setattr(colors, key, value) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/tags.py0000644000000000000000000001513013147102065014225 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' tag support ''' import configparser import functools import os import re from lib import misc from lib import paths from lib import terminal @functools.total_ordering class OrderedObject(object): _parent = None def __init__(self, name, value): assert self._parent is not None self._name = name self._value = value # pylint: disable=protected-access def __lt__(self, other): if not isinstance(other, OrderedObject): return NotImplemented if self._parent is not other._parent: return NotImplemented return self._value < other._value def __eq__(self, other): if not isinstance(other, OrderedObject): return NotImplemented if self._parent is not other._parent: return NotImplemented return self._value == other._value # pylint: enable=protected-access def __hash__(self): return hash(self._value) def __str__(self): return str(self._name) class OrderedGroup(object): def __init__(self, name, *items): self._child_type = ct = type(name, (OrderedObject,), dict(_parent=self)) self._objects = dict( (name, ct(name, value)) for value, name in enumerate(items) ) def __getitem__(self, name): return self._objects[name] severities = OrderedGroup('Severity', 'pedantic', 'wishlist', 'minor', 'normal', 'important', 'serious' ) certainties = OrderedGroup('Certainty', 'wild-guess', 'possible', 'certain', ) class InvalidSeverity(misc.DataIntegrityError): pass class InvalidCertainty(misc.DataIntegrityError): pass class UnknownField(misc.DataIntegrityError): pass _is_safe = re.compile(r'\A[A-Za-z0-9_.!<>=-]+\Z').match class safestr(str): pass def _escape(s): if isinstance(s, safestr): return s if isinstance(s, bytes): return repr(s)[1:] s = str(s) if s == '': return '(empty string)' elif _is_safe(s): return s else: return repr(s) def safe_format(template, *args, **kwargs): args = [_escape(s) for s in args] kwargs = {k: _escape(v) for k, v in kwargs.items()} return safestr(template.format(*args, **kwargs)) class Tag(object): def __init__(self, **kwargs): self.description = None self.references = [] for k, v in kwargs.items(): try: getattr(self, '_set_' + k)(v) except AttributeError: raise UnknownField(k) self.name, self.severity, self.certainty # pylint: disable=pointless-statement # pylint: disable=attribute-defined-outside-init def _set_name(self, value): self.name = value def _set_severity(self, value): try: self.severity = severities[value] except KeyError as exc: [key] = exc.args raise InvalidSeverity(key) def _set_certainty(self, value): try: self.certainty = certainties[value] except KeyError as exc: [key] = exc.args raise InvalidCertainty(key) # pylint: enable=attribute-defined-outside-init _strip_leading_dot = functools.partial( re.compile('^[.]', re.MULTILINE).sub, '' ) @classmethod def _parse_multiline(cls, value): for s in value.splitlines(): if not s or s.isspace(): continue yield cls._strip_leading_dot(s) def _set_description(self, value): value = '\n'.join(self._parse_multiline(value)) self.description = value def _set_references(self, value): self.references += self._parse_multiline(value) def get_colors(self): prio = self.get_priority() n = dict( P=terminal.colors.green, I=terminal.colors.cyan, W=terminal.colors.yellow, E=terminal.colors.red, )[prio] return ( terminal.attr_fg(n), terminal.attr_reset() ) def get_priority(self): s = self.severity S = severities c = self.certainty C = certainties return { S['pedantic']: 'P', S['wishlist']: 'I', S['minor']: 'IW'[c >= C['certain']], S['normal']: 'IW'[c >= C['possible']], S['important']: 'WE'[c >= C['possible']], S['serious']: 'E', }[s] def format(self, target, *extra, color=False): if color: color_on, color_off = self.get_colors() else: color_on = color_off = '' s = '{prio}: {target}: {on}{tag}{off}'.format( prio=self.get_priority(), target=target, tag=self.name, on=color_on, off=color_off, ) if extra: s += ' ' + ' '.join(map(_escape, extra)) return s def _read_tags(): path = os.path.join(paths.datadir, 'tags') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') misc.check_sorted(cp) tags = {} for tagname, section in cp.items(): if not tagname: continue kwargs = dict(section.items()) kwargs['name'] = tagname tags[tagname] = Tag(**kwargs) return tags _tags = _read_tags() def tag_exists(tagname): return tagname in _tags def iter_tags(): return (tag for _, tag in sorted(_tags.items())) def get_tag(tagname): return _tags[tagname] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/strformat/0000755000000000000000000000000013147102065014736 5ustar0000000000000000i18nspector-0.25.5/lib/strformat/python.py0000644000000000000000000002325413147102065016637 0ustar0000000000000000# Copyright © 2015-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string format checks: Python's %-formatting ''' import collections import io class _info: flags = '#0- +' lengths = 'hlL' oct_cvt = 'o' hex_cvt = 'xX' int_cvt = oct_cvt + hex_cvt + 'diu' float_cvt = 'eEfFgG' other_cvt = 'csra' all_cvt = int_cvt + float_cvt + other_cvt + '%' SSIZE_MAX = (1 << 31) - 1 # on 32-bit architectures # -------------------------------------------------------------------------- class Error(Exception): message = 'invalid conversion specification' class ObsoleteConversion(Error): message = 'obsolete conversion specifier' # errors in argument indexing: class ForbiddenArgumentKey(Error): message = 'argument key not allowed' class ArgumentIndexingMixture(Error): message = 'mixed named and unnamed argument specifications' class ArgumentTypeMismatch(Error): message = 'argument type mismatch' # errors is flags: class RedundantFlag(Error): message = 'redundant flag character' # errors in field width: class WidthRangeError(Error): message = 'field width too large' # errors in precision: class RedundantPrecision(Error): message = 'redundant precision' class PrecisionRangeError(Error): message = 'precision too large' # errors in length modifiers: class RedundantLength(Error): message = 'redundant length modifier' # -------------------------------------------------------------------------- class VariableWidth(object): type = 'int' def __init__(self, parent): self.parent = parent class VariablePrecision(object): type = 'int' def __init__(self, parent): self.parent = parent # -------------------------------------------------------------------------- class FormatString(object): def __init__(self, s): self._items = items = [] self._seq_arguments = [] self._map_arguments = collections.defaultdict(list) self.warnings = [] text = io.StringIO() si = enumerate(s) i = 0 def next_si(): try: return next(si) except StopIteration: raise Error(s[i:]) while True: try: i, ch = next(si) except StopIteration: if text.tell(): items += [text.getvalue()] break if ch != '%': text.write(ch) continue j, ch = next_si() key = None if ch == '(': # XXX Python skips over balanced parentheses, but this is not documented. pcount = 1 while True: j, ch = next_si() if ch == '(': pcount += 1 elif ch == ')': pcount -= 1 if pcount == 0: j, ch = next_si() break key = s[i+2:j-1] flags = collections.Counter() while ch in _info.flags: flags[ch] += 1 j, ch = next_si() width = None var_width = False if ch == '*': var_width = True j, ch = next_si() else: width = 0 while ch >= '0' and ch <= '9': width *= 10 width += int(ch) j, ch = next_si() prec = None var_prec = False if ch == '.': j, ch = next_si() if ch == '*': var_prec = True j, ch = next_si() else: prec = 0 while ch >= '0' and ch <= '9': prec *= 10 prec += int(ch) j, ch = next_si() length = None if ch in _info.lengths: length = ch j, ch = next_si() if ch in _info.all_cvt: conv = ch else: raise Error(s[i:]) if text.tell(): items += [text.getvalue()] text.seek(0) text.truncate() items += [Conversion(self, s[i:j+1], key=key, flags=flags, width=width, var_width=var_width, prec=prec, var_prec=var_prec, length=length, conv=conv, )] self.seq_arguments = self._seq_arguments self.seq_conversions = [ arg for arg in self._seq_arguments if isinstance(arg, Conversion) ] for key, args in self._map_arguments.items(): types = frozenset(a.type for a in args) if len(types) > 1: raise ArgumentTypeMismatch(s, key, types) self.map_arguments = self._map_arguments self._map_arguments = self._seq_arguments = None def add_argument(self, key, arg): if self._map_arguments is None: raise RuntimeError('arguments already initialized') # Python accepts mixed named and unnamed arguments # in some corner cases: # https://bugs.python.org/issue1467929 # We follow the documentation and reject such mixtures. if key is None: if self._map_arguments: raise IndexError self._seq_arguments += [arg] else: if self._seq_arguments: raise IndexError self._map_arguments[key] += [arg] def warn(self, exc_type, *args, **kwargs): self.warnings += [exc_type(*args, **kwargs)] def __iter__(self): return iter(self._items) def __len__(self): return len(self._items) # -------------------------------------------------------------------------- class Conversion(object): def __init__(self, parent, s, *, key, flags, width, var_width, prec, var_prec, length, conv): assert s[-1] == conv, '{0} != {1}'.format(s[-1], conv) i = _info for flag, count in flags.items(): if count != 1: parent.warn(RedundantFlag, s, flag, flag) if flag == '#': if conv not in i.oct_cvt + i.hex_cvt + i.float_cvt: parent.warn(RedundantFlag, s, flag) elif flag == '-': pass else: assert flag in '0 +' if conv not in i.int_cvt + i.float_cvt: parent.warn(RedundantFlag, s, flag) for f1, f2 in [('-', '0'), ('+', ' ')]: if (f1 in flags) and (f2 in flags): parent.warn(RedundantFlag, s, f1, f2) if var_width: assert width is None try: parent.add_argument(None, VariableWidth(self)) except IndexError: raise ArgumentIndexingMixture(s) width = ... else: if width > SSIZE_MAX: # The limit is INT_MAX in Python 2.X and SSIZE_MAX in Python 3.X; # but INT_MAX == SSIZE_MAX on mainstream 32-bit architectures. raise WidthRangeError(s, width) if var_prec: assert prec is None try: parent.add_argument(None, VariablePrecision(self)) except IndexError: raise ArgumentIndexingMixture(s) prec = ... elif prec is not None: if prec > SSIZE_MAX: raise PrecisionRangeError(s, width) if prec is not None: if (conv in i.int_cvt) and ('0' in flags): parent.warn(RedundantFlag, s, '0') if conv in 'c%': parent.warn(RedundantPrecision, s, prec) if length is not None: parent.warn(RedundantLength, s, length) if conv in i.int_cvt: tp = 'int' if conv == 'u': parent.warn(ObsoleteConversion, s, '%u', '%d') elif conv in i.float_cvt: tp = 'float' elif conv == 'c': tp = 'chr' elif conv == 's': tp = 'str' elif conv in 'ra': tp = 'object' elif conv == '%': tp = 'None' else: assert False # no coverage self.type = tp if tp == 'None': if key is not None: raise ForbiddenArgumentKey(s) else: try: parent.add_argument(key, self) except IndexError: raise ArgumentIndexingMixture(s) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/strformat/pybrace.py0000644000000000000000000002151713147102065016743 0ustar0000000000000000# Copyright © 2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string format checks: Python's str.format() ''' import collections import functools import re _field_name_pattern = r''' (?: \d+ | [^\W\d]\w* ) (?: [.] [^\W\d]\w* | [[] [^]]+ []] )* ''' _simple_field_pattern = '[{] (?:' + _field_name_pattern + ') ? [}]' _simple_field_re = re.compile(_simple_field_pattern, re.VERBOSE) _field_re = re.compile(r''' (?P (?: [^{}] | [{]{2} | [}]{2} )+ ) | ( [{] (?: (?P''' + _field_name_pattern + r''') ? (?P ! \w+ ) ? (?P : (?: [^{}]* | ''' + _simple_field_pattern + ''' )* ) ? ) [}] ) ''', re.VERBOSE) _format_spec_re = re.compile( # (this regex doesn't take nested fields into account) r''' \A (?: (?P [^}] ) ? (?P [<>=^] ) ) ? (?P [ +-] ) ? (?P [#] ) ? (?P [0] ) ? (?P [0-9]+ ) ? (?P [,] ) ? (?: [.] (?P \d+) ) ? (?P [\w%]) ? \Z ''', re.VERBOSE) def _printable_prefix(s, r=re.compile('[ -\x7e]+')): return r.match(s).group() # -------------------------------------------------------------------------- SSIZE_MAX = (1 << 31) - 1 # on 32-bit architectures # -------------------------------------------------------------------------- class Error(Exception): message = 'invalid replacement field specification' class ConversionError(Error): message = 'invalid conversion flag' class FormatError(Error): message = 'invalid format specification' class FormatTypeMismatch(Error): message = 'type mismatch between conversion and format specifications' # errors in argument indexing: class ArgumentNumberingMixture(Error): message = 'mixed numbered and unnumbered argument specifications' class ArgumentRangeError(Error): message = 'argument index too large' class ArgumentTypeMismatch(Error): message = 'argument type mismatch' # -------------------------------------------------------------------------- class FormatString(object): def __init__(self, s): self._argument_map = collections.defaultdict(list) self._next_arg_index = 0 self._items = items = [] last_pos = 0 for match in _field_re.finditer(s): if match.start() != last_pos: raise Error( _printable_prefix(s[last_pos:]) ) last_pos = match.end() literal = match.group('literal') if literal is not None: items += [literal] else: items += [Field(self, match)] if last_pos != len(s): raise Error( _printable_prefix(s[last_pos:]) ) for name, args in self._argument_map.items(): common_types = functools.reduce( frozenset.__and__, (a.types for a in args) ) if not common_types: raise ArgumentTypeMismatch(s, name) for arg in args: arg.types = common_types self.argument_map = dict(self._argument_map) self._argument_map = None def add_argument(self, name, field): if self._argument_map is None: raise RuntimeError('arguments already initialized') if name is None: if self._next_arg_index is None: raise IndexError n = self._next_arg_index if n > SSIZE_MAX: raise OverflowError(n) self._next_arg_index += 1 self._argument_map[n] += [field] elif name.isdigit(): n = int(name) if n > SSIZE_MAX: raise OverflowError(n) if self._next_arg_index is None: pass elif self._next_arg_index == 0: self._next_arg_index = None else: raise IndexError self._argument_map[n] += [field] else: self._argument_map[name] += [field] def __iter__(self): return iter(self._items) def __len__(self): return len(self._items) # -------------------------------------------------------------------------- class Field(object): def __init__(self, parent, match): s = match.string[slice(*match.span())] name = match.group('name') try: parent.add_argument(name, self) except IndexError: raise ArgumentNumberingMixture(s) except OverflowError: raise ArgumentRangeError(s) fmt = match.group('format') tp = {'str', 'int', 'float'} if fmt is None: pass elif '{' in fmt: # Nested replacement fields are nasty. They make virtually # impossible to do any type checking. For example: # # >>> '{:{}{}}'.format('m', 'o<2', 3) # 'moooooooooooooooooooooo' # >>> '{:{}{}}'.format(23, '+', 'x') # '+17' # for subfield in _simple_field_re.findall(fmt): assert subfield[0] == '{' assert subfield[-1] == '}' subfield_name = subfield[1:-1] or None subfield = NestedField(self) try: parent.add_argument(subfield_name, subfield) except IndexError: raise ArgumentNumberingMixture(subfield) except OverflowError: raise ArgumentRangeError(s) else: assert fmt[0] == ':' fmatch = _format_spec_re.match(fmt[1:]) if fmatch is None: raise FormatError(s) comma = fmatch.group('comma') ftype = fmatch.group('type') if ftype is None: pass elif ftype == 's': tp = {'str'} elif ftype in 'bcdoxX': tp = {'int'} elif ftype in 'eEfFgG%': tp = {'float'} elif ftype == 'n': if comma: raise FormatError(s) tp = {'int', 'float'} else: raise Error(s) alt = fmatch.group('alt') sign = fmatch.group('sign') if alt or sign or comma: tp &= {'int', 'float'} if not tp: raise FormatError(s) align = fmatch.group('align') zero = fmatch.group('zero') if (align is None) and (zero is not None): align = '=' if align == '=': tp &= {'int', 'float'} if not tp: raise FormatError(s) width = fmatch.group('width') if width is not None: width = int(width) if width > SSIZE_MAX: raise FormatError(s) precision = fmatch.group('precision') if precision is not None: tp &= {'float', 'str'} if not tp: raise FormatError(s) precision = int(precision) if precision > SSIZE_MAX: raise FormatError(s) conversion = match.group('conversion') if conversion is None: pass elif conversion in {'!s', '!r', '!a'}: if 'str' not in tp: raise FormatTypeMismatch(s) else: raise ConversionError(s) self.types = frozenset(tp) class NestedField(object): types = frozenset({'str', 'int', 'float'}) def __init__(self, parent): self.parent = parent # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/strformat/c.py0000644000000000000000000004006713147102065015541 0ustar0000000000000000# Copyright © 2014-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string format checks: C ''' import collections import re _directive_re = re.compile(''' (?P [^%]+ ) | ( % (?P [0-9]+[$] )? (?P [#0 +'I-]* ) (?: (?P [1-9][0-9]* ) | (?P [*] ) (?P [0-9]+[$] )? )? (?: [.] (?: (?P [0-9]* ) | (?P [*] ) (?P [0-9]+[$] )? ) )? (?: (?P hh? | ll? | [qjzZt] | L )? (?P [diouxXeEfFgGaAcsCSpnm%] ) | < (?: PRI (?P[diouxX]) (?P (?:LEAST|FAST)?(?:8|16|32|64)|MAX|PTR) ) > ) ) ''', re.VERBOSE) def _printable_prefix(s, r=re.compile('[ -\x7e]+')): return r.match(s).group() class _info: oct_cvt = 'o' hex_cvt = 'xXaA' dec_cvt = 'diufFgG' float_cvt = 'aAeEfFgG' uint_cvt = 'ouxX' int_cvt = 'di' + uint_cvt str_cvt = 'sS' int_types = ''' hh = signed char | unsigned char h = short int | unsigned short int l = long int | unsigned long int ll = long long int | unsigned long long int j = intmax_t | uintmax_t z = ssize_t | size_t t = ptrdiff_t | [unsigned ptrdiff_t] = int | unsigned int ''' int_types = dict( (key, tuple(str.strip(v) for v in values.split('|'))) for line in int_types.strip().splitlines() for key, values in [map(str.strip, line.split('='))] ) # FIXME: The printf(3) manpage says that the type for signed integer with # “z“ size is ssize_t. # But SUSv3 says it's a signed integer type corresponding to size_t, # which is not necessarily the same thing as ssize_t. # https://www.gnu.org/software/libc/manual/html_node/Integer-Conversions.html portable_int_lengths = dict( L='ll', # The use of “L” with integer conversions is not documented # in the printf(3) manpage. https://bugs.debian.org/757151 q='ll', Z='z', ) INT_MAX = (1 << 31) - 1 # on most architectures NL_ARGMAX = 4096 # on GNU/Linux class Error(Exception): message = 'invalid conversion specification' class NonPortableConversion(Error): message = 'non-portable conversion specifier or length modifier' # errors in argument indexing: class ForbiddenArgumentIndex(Error): message = 'argument index not allowed' class ArgumentRangeError(Error): message = 'argument index too small or too large' class MissingArgument(Error): message = 'missing argument' class ArgumentTypeMismatch(Error): message = 'argument type mismatch' class ArgumentNumberingMixture(Error): message = 'mixed numbered and unnumbered argument specifications' # errors in length modifiers: class LengthError(Error): message = 'invalid length modifier' # errors in flag characters: class FlagError(Error): message = 'unexpected format flag character' class RedundantFlag(Error): message = 'redundant flag character' # errors in field width: class WidthError(Error): message = 'unexpected width' class WidthRangeError(Error): message = 'field width too large' # errors in precision: class PrecisionError(Error): message = 'unexpected precision' class PrecisionRangeError(Error): message = 'precision too large' class VariableWidth(object): type = 'int' def __init__(self, parent): self.parent = parent class VariablePrecision(object): type = 'int' def __init__(self, parent): self.parent = parent class FormatString(object): def __init__(self, s): self._items = items = [] self._argument_map = collections.defaultdict(list) self._next_arg_index = 1 self.warnings = [] last_pos = 0 for match in _directive_re.finditer(s): if match.start() != last_pos: raise Error( _printable_prefix(s[last_pos:]) ) last_pos = match.end() literal = match.group('literal') if literal is not None: items += [literal] else: items += [Conversion(self, match)] if last_pos != len(s): raise Error( _printable_prefix(s[last_pos:]) ) self.arguments = [] for i in range(1, NL_ARGMAX + 1): if not self._argument_map: break try: args = self._argument_map.pop(i) except KeyError: raise MissingArgument(s, i) self.arguments += [args] assert not self._argument_map self._argument_map = None for i, args in enumerate(self.arguments, start=1): types = frozenset(a.type for a in args) if len(types) > 1: raise ArgumentTypeMismatch(s, i, types) def add_argument(self, n, value): if self._argument_map is None: raise RuntimeError('arguments already initialized') if n is None: if self._next_arg_index is None: raise IndexError else: n = self._next_arg_index self._next_arg_index += 1 else: if self._next_arg_index is None: pass elif self._next_arg_index == 1: assert not self._argument_map self._next_arg_index = None else: raise IndexError if n > NL_ARGMAX: raise OverflowError(n) self._argument_map[n] += [value] def warn(self, exc_type, *args, **kwargs): self.warnings += [exc_type(*args, **kwargs)] def get_last_integer_conversion(self, *, n): ''' return the integer conversion that consumes the last n arguments, or None ''' if n > len(self.arguments): raise IndexError if n <= 0: raise IndexError conv = vconv = None for i in range(len(self.arguments) - n, len(self.arguments)): assert i >= 0 for arg in self.arguments[i]: if isinstance(arg, (VariableWidth, VariablePrecision)): if vconv is None: vconv = arg.parent if vconv is not arg.parent: return elif isinstance(arg, Conversion): if vconv is None: vconv = arg if (conv is None) and (vconv is arg): conv = arg if conv is not arg: return else: assert False, 'type(arg) == {!r}'.format(type(arg)) # no coverage if conv is None: return if not conv.integer: return return conv def __iter__(self): return iter(self._items) def __len__(self): return len(self._items) class Conversion(object): type = None integer = None def __init__(self, parent, match): i = _info self._s = s = match.string[slice(*match.span())] # length and conversion: c99conversion = match.group('c99conv') c99length = match.group('c99len') length = match.group('length') conversion = match.group('conversion') tp = None self.integer = False if c99conversion is not None: assert c99length is not None if c99conversion in 'di': tp = 'int' elif c99conversion in 'ouxX': tp = 'uint' else: # should not happen assert False # no coverage conversion = c99conversion if c99length.startswith(('LEAST', 'FAST')): tp += '_' + c99length.lower() else: tp += c99length.lower() tp += '_t' self.integer = True elif conversion in i.int_cvt + 'n': plength = i.portable_int_lengths.get(length, length) if plength != length: parent.warn(NonPortableConversion, s, '%' + length + conversion, '%' + plength + conversion ) tp = i.int_types.get(plength or '') assert tp is not None tp = tp[conversion in i.uint_cvt] if conversion == 'n': tp += ' *' else: self.integer = True elif conversion in i.float_cvt: if length is None: tp = 'double' elif length == 'l': # XXX C99 says that the “l” length is no-op for floating-point # conversions, but this is not documented in the printf(3) # manpage. parent.warn(NonPortableConversion, s, '%l' + conversion, '%' + conversion ) tp = 'double' elif length == 'L': tp = 'long double' elif conversion == 'c': if length is None: tp = 'char' # C99 says it's an int, which is then converted to unsigned char. # We don't want “int” here, so that %c and %d have distinct types. # Mere “char” is not very precise, but it should be good enough. elif length == 'l': tp = 'wint_t' elif conversion == 'C': if length is None: parent.warn(NonPortableConversion, s, '%C', '%lc') tp = 'wint_t' elif conversion == 's': if length is None: tp = 'const char *' elif length == 'l': tp = 'const wchar_t *' elif conversion == 'S': if length is None: parent.warn(NonPortableConversion, s, '%S', '%ls') tp = 'const wchar_t *' elif conversion == 'p': if length is None: tp = 'void *' elif conversion in {'m', '%'}: if length is None: tp = 'void' else: # should not happen assert False # no coverage if tp is None: assert length is not None raise LengthError(s, length) self.type = tp # flags: flags = collections.Counter(match.group('flags')) for flag, count in flags.items(): if count != 1: parent.warn(RedundantFlag, s, flag, flag) if conversion == 'n': # C99 says that the “n” conversion cannot include any flags, # but this is not documented in the printf(3) manpage. # https://bugs.debian.org/756602 raise FlagError(s, flag) if flag == '#': if conversion not in i.oct_cvt + i.hex_cvt + i.float_cvt: raise FlagError(s, flag) elif flag == '0': if conversion not in i.int_cvt + i.float_cvt: raise FlagError(s, flag) elif flag == "'": if conversion not in i.dec_cvt: raise FlagError(s, flag) else: if conversion == '%': raise FlagError(s, flag) assert flag in {'-', ' ', '+', 'I'} for f1, f2 in [('-', '0'), ('+', ' ')]: if (f1 in flags) and (f2 in flags): parent.warn(RedundantFlag, s, f1, f2) # width: width = match.group('width') if width is not None: width = int(width) if width > INT_MAX: raise WidthRangeError(s, width) elif match.group('varwidth'): varwidth_index = match.group('varwidth_index') if varwidth_index is not None: varwidth_index = int(varwidth_index.rstrip('$')) if not (0 < varwidth_index <= NL_ARGMAX): raise ArgumentRangeError(s, varwidth_index) try: parent.add_argument(varwidth_index, VariableWidth(self)) except IndexError: raise ArgumentNumberingMixture(s) except OverflowError as exc: raise ArgumentRangeError(s, '{}$'.format(exc)) width = ... if width is not None: if conversion in '%n': # C99 says that the “n” conversion cannot include a field width, # but this is not documented in the printf(3) manpage. # https://bugs.debian.org/756602 raise WidthError(s) # precision: precision = match.group('precision') if precision is not None: precision = int(precision or '0') if precision > INT_MAX: raise PrecisionRangeError(s) elif match.group('varprec'): varprec_index = match.group('varprec_index') if varprec_index is not None: varprec_index = int(varprec_index.rstrip('$')) if not (0 < varprec_index <= NL_ARGMAX): raise ArgumentRangeError(s, varprec_index) try: parent.add_argument(varprec_index, VariablePrecision(self)) except IndexError: raise ArgumentNumberingMixture(s) except OverflowError as exc: raise ArgumentRangeError(s, '{}$'.format(exc)) precision = ... if precision is not None: if conversion in i.int_cvt + i.float_cvt + i.str_cvt: pass else: # XXX C99 says that precision for the other conversion is # undefined behavior, but this is not documented in the # printf(3) manpage. raise PrecisionError(s) if (conversion in i.int_cvt) and ('0' in flags): parent.warn(RedundantFlag, s, '0') # index: index = match.group('index') if index is not None: index = int(index.rstrip('$')) if not (0 < index <= NL_ARGMAX): raise ArgumentRangeError(s, index) if tp == 'void': if index is not None: if conversion == '%': raise ForbiddenArgumentIndex(s) else: # Although not specifically forbidden, having an argument index # for %m (which doesn't consume any argument) doesn't make any # sense. TODO: Emit a warning. pass # XXX The printf(3) manpage says that numbered arguments can be # mixed only with %%. But practically, mixing them with %m (which # also doesn't consume any argument) must be also allowed. else: try: parent.add_argument(index, self) except IndexError: raise ArgumentNumberingMixture(s) except OverflowError as exc: raise ArgumentRangeError(s, '{}$'.format(exc)) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/strformat/__init__.py0000644000000000000000000000000013147102065017035 0ustar0000000000000000i18nspector-0.25.5/lib/polib4us.py0000644000000000000000000001666113147102065015042 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' polib monkey-patching ''' import ast import codecs import contextlib import inspect import re import polib from lib import encodings from lib import moparser # pylint: disable=protected-access patches = [] def install_patches(): for patch in patches: patch() __all__ = ['install_patches'] def register_patch(patch): patches.append(contextlib.contextmanager(patch)) # polib.default_encoding # ====================== # Do not allow broken/missing encoding declarations, unless the file is # ASCII-only. @register_patch def default_encoding_patch(): polib.default_encoding = 'ASCII' # polib.codecs # ============ # Work around a few PO parsing bugs: # - newline decoding: https://bugs.debian.org/692283 # - trailing comment parsing: https://bitbucket.org/izi/polib/issues/51 # - atypical comment parsing # - parsing of empty files: https://bitbucket.org/izi/polib/issues/59 class Codecs(object): _iterlines = re.compile(r'[^\n]*(?:\n|\Z)').findall _atypical_comment = re.compile(r'#[^ .:,|~]').match def __getattr__(self, attr): return getattr(codecs, attr) def open(self, path, mode, encoding): if mode not in {'rU', 'rt'}: raise NotImplementedError if not encodings.is_ascii_compatible_encoding(encoding): encoding = 'ASCII' with open(path, 'rb') as file: contents = file.read() contents = contents.decode(encoding) pending_comments = [] empty = True for line in self._iterlines(contents): if self._atypical_comment(line): line = '# ' + line[1:] if line[:2] in {'', '# '} or line.isspace(): pending_comments += [line] else: for comment_line in pending_comments: yield comment_line pending_comments = [] yield line empty = False if empty: yield '# ' @register_patch def codecs_patch(): polib.codecs = polib.io = Codecs() # polib.POFile.find() # =================== # Make POFile.find() always return None. # That way the parser won't find the header entry, allowing us to parse it # ourselves. @register_patch def pofile_find_patch(): def pofile_find(self, *args, **kwargs): del self, args, kwargs return polib.POFile.find = pofile_find # polib.unescape() # ================ # Work around an escape sequence decoding bug. # https://bitbucket.org/izi/polib/issues/31 _escapes_re = re.compile(r''' ( \\ (?: [ntbrfva] | \\ | " | [0-9]{1,3} | x[0-9a-fA-F]{1,2} ))+ ''', re.VERBOSE) _short_x_escape_re = re.compile(r''' \\x ([0-9a-fA-F]) (?= \\ | $ ) ''', re.VERBOSE) def polib_unescape(s): def unescape(match): s = match.group() s = _short_x_escape_re.sub(r'\\x0\1', s) result = ast.literal_eval("b'{}'".format(s)) try: return result.decode('ASCII') # pylint: disable=no-member except UnicodeDecodeError: # an ugly hack to discover encoding of the PO file: parser_stack_frame = inspect.stack()[2][0] parser = parser_stack_frame.f_locals['self'] encoding = parser.instance.encoding return result.decode(encoding) # pylint: disable=no-member return _escapes_re.sub(unescape, s) @register_patch def unescape_patch(): polib.unescape = polib_unescape # polib._MOFileParser # =================== # Use a custom MO file parser implementation. # https://bitbucket.org/izi/polib/issues/36 # https://bitbucket.org/izi/polib/issues/44 # https://bitbucket.org/izi/polib/issues/45 # https://bitbucket.org/izi/polib/issues/47 @register_patch def mo_parser_patch(): polib._MOFileParser = moparser.Parser # polib.detect_encoding() # ======================= # Don't use polib's detect_encoding() for MO files, as i18nspector's own MO # file parser has built-in encoding detection. @register_patch def detect_encoding_patch(): def detect_encoding(path, binary_mode=False): if binary_mode: return return original(path) original = polib.detect_encoding polib.detect_encoding = detect_encoding # polib.POEntry.flags # =================== # Fix flag splitting. # polib (<< 1.0.4) incorrectly requires that the flag-splitting comma is # followed by a space. # https://bitbucket.org/izi/polib/issues/46 @register_patch def poentry_flags_patch(): def get_flags(self): return self._i18nspector_flags def set_flags(self, flags): self._i18nspector_flags = [ flag.strip(' \t\r\f\v') for subflags in flags for flag in subflags.split(',') ] polib.POEntry.flags = property(get_flags, set_flags) # polib.POEntry.msgstr_plural # =========================== # Force msgstr_plural keys to be integers. # polib (<< 1.0.4) uses strings there instead. # https://bitbucket.org/izi/polib/issues/49 class IntDict(dict): def __setitem__(self, key, value): super().__setitem__(int(key), value) def __getitem__(self, key): return super().__getitem__(int(key)) @register_patch def poentry_msgstr_plural_patch(): def get_msgstr_plural(self): return self._i18nspector_msgstr_plural def set_msgstr_plural(self, d): self._i18nspector_msgstr_plural = IntDict(d) polib.POEntry.msgstr_plural = property( get_msgstr_plural, set_msgstr_plural, ) # polib._BaseEntry.__init__() # =========================== # Distinguish between empty and non-existent msgid_plural. # Distinguish between empty and non-existent msgstr. @register_patch def base_entry_init_patch(): def init(self, *args, **kwargs): original(self, *args, **kwargs) if 'msgid_plural' not in kwargs: self.msgid_plural = None if 'msgstr' not in kwargs: self.msgstr = None original = polib._BaseEntry.__init__ polib._BaseEntry.__init__ = init # polib.POEntry.translated() # ========================== # Consider the message translated if any msgstr[N] is non-empty. @register_patch def poentry_translated_patch(): def translated(self): if self.obsolete: return False if 'fuzzy' in self.flags: return False return ( self.msgstr or any(self.msgstr_plural.values()) ) polib.POEntry.translated = translated # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/paths.py0000644000000000000000000000255413147102065014414 0ustar0000000000000000# Copyright © 2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' paths to code and data ''' import os basedir = os.path.normpath(os.path.join( os.path.dirname(__file__), os.path.pardir, '', )) datadir = os.path.join(basedir, 'data', '') def check(): os.stat(basedir) os.stat(datadir) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/moparser.py0000644000000000000000000001761513147102065015131 0ustar0000000000000000# Copyright © 2013-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' MO file parser ''' # MO file format documentation: # * http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/gmo.h?id=v0.18.3 # * http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/read-mo.c?id=v0.18.3 # * https://www.gnu.org/software/gettext/manual/html_node/MO-Files.html import re import struct import sys import polib from lib import encodings little_endian_magic = b'\xDE\x12\x04\x95' big_endian_magic = little_endian_magic[::-1] class SyntaxError(Exception): # pylint: disable=redefined-builtin pass class Parser(object): def __init__(self, path, *, encoding=None, check_for_duplicates=False, klass=None): self._encoding = encoding if check_for_duplicates: raise NotImplementedError with open(path, 'rb') as file: contents = file.read() view = memoryview(contents) if len(view) > 0: if sys.version_info >= (3, 3): # https://docs.python.org/3.3/whatsnew/3.3.html#pep-3118-new-memoryview-implementation-and-buffer-protocol-documentation # “Accessing a memoryview element with format ‘B’ (unsigned bytes) # now returns an integer […]. For returning a bytes object the view # must be cast to ‘c’ first.” view = view.cast('c') assert isinstance(view[0], bytes) self._view = view if klass is None: klass = polib.MOFile try: self.instance = klass( fpath=path, check_for_duplicates=False, ) self._parse() finally: del self._view def parse(self): return self.instance def _read_ints(self, at, n=1): begin = at end = at + 4 * n view = self._view if end > len(view): raise SyntaxError('truncated file') return struct.unpack( self._endian + 'I' * n, view[begin:end], ) def _parse(self): view = self._view magic = view[:4].tobytes() if magic == little_endian_magic: self._endian = '<' elif magic == big_endian_magic: self._endian = '>' else: raise SyntaxError('unexpected magic') [revision] = self._read_ints(at=4) major_revision, minor_revision = divmod(revision, 1 << 16) if major_revision > 1: raise SyntaxError('unexpected major revision number: {n}'.format(n=major_revision)) [n_strings] = self._read_ints(at=8) possible_hidden_strings = False if minor_revision > 1: # “an unexpected minor revision number means that the file can be # read but will not reveal its full contents” possible_hidden_strings = True elif minor_revision == 1: [n_sysdep_strings] = self._read_ints(at=36) if n_sysdep_strings > 0: possible_hidden_strings = True self.instance.possible_hidden_strings = possible_hidden_strings [msgid_offset, msgstr_offset] = self._read_ints(at=12, n=2) self._last_msgid = None for i in range(n_strings): entry = self._parse_entry(i, msgid_offset + 8 * i, msgstr_offset + 8 * i) self.instance.append(entry) def _parse_entry(self, i, msgid_offset, msgstr_offset): view = self._view [length, offset] = self._read_ints(at=msgid_offset, n=2) msgid = view[offset:offset+length].tobytes() try: if view[offset + length] != b'\0': raise SyntaxError('msgid is not null-terminated') except IndexError: raise SyntaxError('truncated file') msgids = msgid.split(b'\0', 2) msgid = msgids[0] if len(msgids) > 2: raise SyntaxError('unexpected null byte in msgid') [length, offset] = self._read_ints(at=msgstr_offset, n=2) msgstr = view[offset:offset+length].tobytes() try: if view[offset + length] != b'\0': raise SyntaxError('msgstr is not null-terminated') except IndexError: raise SyntaxError('truncated file') msgstrs = msgstr.split(b'\0') if len(msgids) == 1 and len(msgstrs) > 1: raise SyntaxError('unexpected null byte in msgstr') encoding = self._encoding if i == 0: if encoding is None and msgid == b'': # http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/dcigettext.c?id=v0.18.3#n1106 match = re.search(b'charset=([^ \t\n]+)', msgstr) if match is not None: try: encoding = match.group(1).decode('ASCII') except UnicodeError: pass if encoding is None: encoding = 'ASCII' else: if not encodings.is_ascii_compatible_encoding(encoding): encoding = 'ASCII' self._encoding = encoding else: if msgids == self._last_msgid: raise SyntaxError('duplicate message definition') elif msgid < self._last_msgid: raise SyntaxError('messages are not sorted') self._last_msgid = msgid # pylint: disable=attribute-defined-outside-init assert encoding is not None msgid, *msgctxt = msgid.split(b'\x04', 1) kwargs = dict(msgid=msgid.decode(encoding)) if msgctxt: [msgctxt] = msgctxt kwargs.update(msgctxt=msgctxt.decode(encoding)) if len(msgids) == 1: assert [msgstr] == msgstrs kwargs.update(msgstr=msgstr.decode(encoding)) else: assert len(msgids) == 2 assert len(msgstrs) >= 1 kwargs.update(msgid_plural=msgids[1].decode(encoding)) kwargs.update(msgstr_plural= {i: s.decode(encoding) for i, s in enumerate(msgstrs)} ) entry = polib.MOEntry(**kwargs) entry.comment = None entry.occurrences = () entry.flags = () # https://bitbucket.org/izi/polib/issues/47 entry.translated = lambda: True entry.previous_msgctxt = None entry.previous_msgid = None entry.previous_msgid_plural = None return entry __all__ = ['Parser', 'SyntaxError'] def main(): import argparse ap = argparse.ArgumentParser(description='msgunfmt(1) replacement') ap.add_argument('files', metavar='', nargs='+') options = ap.parse_args() for path in options.files: escaped_path = ascii(path)[1:-1] print('# ' + escaped_path, end='\n\n') parser = Parser(path) for entry in parser.parse(): print(entry) if __name__ == '__main__': main() else: del main # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/misc.py0000644000000000000000000000616113147102065014226 0ustar0000000000000000# Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' miscellanea ''' import contextlib import datetime import sys import tempfile import types def unsorted(iterable): ''' if the iterable is sorted, return None; otherwise return first (x, y) such that x > y ''' iterable = iter(iterable) for x in iterable: break for y in iterable: if x > y: # pylint: disable=undefined-loop-variable return (x, y) # pylint: disable=undefined-loop-variable x = y class DataIntegrityError(Exception): pass def check_sorted(iterable, exception=DataIntegrityError): ''' raise exception if the iterable is not sorted ''' cx = unsorted(iterable) if cx is not None: raise exception('{0!r} > {1!r}'.format(*cx)) def sorted_vk(d): ''' iterate over d.values() in the key order ''' for k, v in sorted(d.items()): del k yield v def utc_now(): ''' timezone-aware variant of datetime.now() ''' return datetime.datetime.now( datetime.timezone.utc ) def format_range(rng, *, max): # pylint: disable=redefined-builtin last = rng[-1] result = [] if max < 4: raise ValueError('max must be >= 4') for i in rng: if len(result) < max: result += [i] else: result[-2:] = ['...', str(last)] break return ', '.join(map(str, result)) class Namespace(object): ''' simple attribute-based namespace ''' def __init__(self, **kwargs): super().__init__() self.__dict__.update(kwargs) Namespace() # make pyflakes and coverage.py happy if sys.version_info >= (3, 3): # no coverage Namespace = types.SimpleNamespace @contextlib.contextmanager def throwaway_tempdir(context): with tempfile.TemporaryDirectory(prefix='i18nspector.{}.'.format(context)) as new_tempdir: original_tempdir = tempfile.tempdir try: tempfile.tempdir = new_tempdir yield finally: tempfile.tempdir = original_tempdir # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/ling.py0000644000000000000000000002637013147102065014230 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' language information registry ''' import configparser import os import re import unicodedata from lib import misc from lib import paths def _munch_language_name(s): # Normalize whitespace: s = ' '.join(s.split()) # Normalize capitalization: s = s.lower() # Strip accent marks etc.: s = unicodedata.normalize('NFD', s).encode('ASCII', 'ignore').decode() return s class LanguageError(ValueError): pass class LanguageSyntaxError(LanguageError): pass class FixingLanguageCodesFailed(LanguageError): pass class FixingLanguageEncodingFailed(LanguageError): pass class Language(object): def __init__(self, language_code, territory_code=None, encoding=None, modifier=None): self.language_code = language_code if language_code is None: raise TypeError('language_code must not be None') # no coverage self.territory_code = territory_code self.encoding = None if encoding is not None: self.encoding = encoding.upper() self.modifier = modifier def _get_tuple(self): return ( self.language_code, self.territory_code, self.encoding, self.modifier ) def clone(self): return Language(*self._get_tuple()) def __eq__(self, other): if not isinstance(other, Language): return NotImplemented return self._get_tuple() == other._get_tuple() # pylint: disable=protected-access def __ne__(self, other): return not self == other def is_almost_equal(self, other): if not isinstance(other, Language): raise TypeError self_clone = self.clone() self_clone.remove_principal_territory_code() other_clone = other.clone() other_clone.remove_principal_territory_code() return self_clone == other_clone def fix_codes(self): fixed = None ll = self.language_code ll = _lookup_language_code(ll) if ll is None: # TODO: Try to guess correct language code. raise FixingLanguageCodesFailed() elif ll != self.language_code: fixed = True cc = self.territory_code if cc is not None: cc = lookup_territory_code(cc) if cc is None: # TODO: Try to guess correct territory code. raise FixingLanguageCodesFailed() elif cc != self.territory_code: # This shouldn't really happen, but better safe than sorry. raise ValueError # no coverage # TODO: ll_CC could be still incorrect, even when both ll and CC are # correct. self.language_code = ll self.territory_code = cc return fixed def get_principal_territory_code(self): ll = self.language_code assert ll is not None return _get_principal_territory_code(ll) def remove_principal_territory_code(self): cc = self.territory_code if cc is None: return default_cc = self.get_principal_territory_code() if cc == default_cc: self.territory_code = None return True def remove_encoding(self): if self.encoding is None: return self.encoding = None return True def remove_nonlinguistic_modifier(self): if self.modifier == 'euro': self.modifier = None return True return def get_plural_forms(self): result = None if self.territory_code is not None: code = self._simple_format() result = _get_plural_forms(code) if result is None: code = self._simple_format(territory=False) result = _get_plural_forms(code) return result def get_unrepresentable_characters(self, encoding, strict=False): characters = None if self.territory_code is not None: code = self._simple_format() characters = _get_characters(code, self.modifier, strict=strict) if characters is None: code = self._simple_format(territory=False) characters = _get_characters(code, self.modifier, strict=strict) if characters is None: return result = [] try: # If iconv(1) is used to implement an encoding, there's a huge # overhead per encode() call. To reduce number of such calls, # optimize the common case of all characters being representable. ''.join(characters).encode(encoding) except UnicodeEncodeError: pass else: return result for character in characters: try: character.encode(encoding) except UnicodeEncodeError as exc: result += [character] if exc.reason.startswith('iconv:'): # pylint: disable=no-member # Avoid further calls to iconv(1): break return result def _simple_format(self, territory=True): s = self.language_code if territory and self.territory_code is not None: s += '_' + self.territory_code return s def __str__(self): s = self.language_code if self.territory_code is not None: s += '_' + self.territory_code if self.encoding is not None: s += '.' + self.encoding if self.modifier is not None: s += '@' + self.modifier return s def __repr__(self): return ''.format(self) def _read_iso_codes(): # ISO language/territory codes: path = os.path.join(paths.datadir, 'iso-codes') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') cfg_iso_639 = cp['language-codes'] misc.check_sorted(cfg_iso_639) iso_639 = {} for lll, ll in cfg_iso_639.items(): if ll: iso_639[ll] = ll iso_639[lll] = ll else: iso_639[lll] = lll cfg_iso_3166 = cp['territory-codes'] misc.check_sorted(cfg_iso_3166) iso_3166 = frozenset(cc.upper() for cc in cfg_iso_3166.keys()) return (iso_639, iso_3166) [_iso_639, _iso_3166] = _read_iso_codes() def _read_primary_languages(): # Hand-edited linguistic data: path = os.path.join(paths.datadir, 'languages') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') primary_languages = {name: sect for name, sect in cp.items() if sect.name} name_to_code = {} misc.check_sorted(cp) for language, section in cp.items(): if not language: continue for key in section.keys(): if key in {'names', 'characters', 'macrolanguage', 'plural-forms', 'principal-territory'}: continue if key.startswith('characters@'): continue raise misc.DataIntegrityError('unknown key: {}'.format(key)) for name in section['names'].splitlines(): name = _munch_language_name(name) if name: if name in name_to_code: raise misc.DataIntegrityError name_to_code[name] = language return primary_languages, name_to_code def _check_primary_languages_coverage(): # Check if primary languages have full ISO 639-1 coverage: for ll in _iso_639: if len(ll) > 2: continue try: _primary_languages[ll] except LookupError: # no coverage raise misc.DataIntegrityError [_primary_languages, _name_to_code] = _read_primary_languages() _check_primary_languages_coverage() def _lookup_language_code(language): return _iso_639.get(language) def lookup_territory_code(cc): if cc in _iso_3166: return cc def get_language_for_name(name): parse = parse_language _name = _munch_language_name(name) try: return parse(_name_to_code[_name]) except KeyError: pass if ';' in _name: for subname in _name.split(';'): subname = subname.strip() try: return parse(_name_to_code[subname]) except LookupError: pass if ',' in _name: subname = ' '.join(map(str.strip, _name.split(',', 1)[::-1])) try: return parse(_name_to_code[subname]) except LookupError: pass results = set() for subname in _name.split(','): subname = subname.strip() result = _name_to_code.get(subname) if result is not None: results.add(result) if len(results) == 1: return parse(results.pop()) raise LookupError(name) _language_regexp = re.compile(r''' ^ ( [a-z]{2,} ) (?: _ ( [A-Z]{2,} ) )? (?: [.] ( [a-zA-Z0-9+-]+ ) )? (?: @ ( [a-z]+) )? $''', re.VERBOSE) def parse_language(s): match = _language_regexp.match(s) if match is None: raise LanguageSyntaxError return Language(*match.groups()) def get_primary_languages(): return iter(_primary_languages) def _get_plural_forms(language): try: section = _primary_languages[language] except KeyError: return plural_forms = section.get('plural-forms') if plural_forms is None: return return [ s.strip() for s in plural_forms.splitlines() if s and not s.isspace() ] def _get_principal_territory_code(language): try: section = _primary_languages[language] except KeyError: return return section.get('principal-territory') def _get_characters(language, modifier=None, strict=True): try: section = _primary_languages[language] except KeyError: return section_name = 'characters' if modifier is not None: section_name += '@{}'.format(modifier) result = section.get(section_name) if result is None: return if strict: return [ ch.strip('()') for ch in result.split() ] else: return [ ch for ch in result.split() if not (ch.startswith('(') and ch.endswith(')')) ] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/intexpr.py0000644000000000000000000004337013147102065014767 0ustar0000000000000000# Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' C integer expressions ''' import ast import functools import rply import rply.errors LexingError = rply.errors.LexingError ParsingError = rply.errors.ParsingError # http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-runtime/intl/plural.y?id=v0.18.3#n132 @functools.lru_cache(maxsize=None) def create_lexer(): lg = rply.LexerGenerator() lg.add('IF', r'[?]') lg.add('ELSE', r':') lg.add('OR', r'[|][|]') lg.add('AND', r'[&][&]') lg.add('EQ', r'[!=]=') lg.add('CMP', r'[<>]=?') lg.add('ADDSUB', r'[+-]') lg.add('MULDIV', r'[*/%]') lg.add('NOT', r'!') lg.add('LPAR', r'[(]') lg.add('RPAR', r'[)]') lg.add('VAR', r'n') lg.add('INT', r'[0-9]+') lg.ignore(r'[ \t]+') return lg.build() @functools.lru_cache(maxsize=None) def create_parser(lexer): pg = rply.ParserGenerator( [rule.name for rule in lexer.rules], precedence=[ ('right', ['IF', 'ELSE']), ('left', ['OR']), ('left', ['AND']), ('left', ['EQ']), ('left', ['CMP']), ('left', ['ADDSUB']), ('left', ['MULDIV']), ('right', ['NOT']), ], cache_id='i18nspector-intexpr', ) ast_bool = { '&&': ast.And(), '||': ast.Or(), } ast_cmp = { '==': ast.Eq(), '!=': ast.NotEq(), '<': ast.Lt(), '<=': ast.LtE(), '>': ast.Gt(), '>=': ast.GtE(), } ast_arithmetic = { '+': ast.Add(), '-': ast.Sub(), '*': ast.Mult(), '/': ast.Div(), '%': ast.Mod(), } ast_not = ast.Not() # pylint: disable=unused-variable @pg.production('start : exp') def eval_start(p): [exp] = p return ast.Expr(exp) @pg.production('exp : exp IF exp ELSE exp') def expr_ifelse(p): [cond, _, body, _, orelse] = p return ast.IfExp(cond, body, orelse) @pg.production('exp : exp OR exp') @pg.production('exp : exp AND exp') def expr_bool(p): [left, tok, right] = p op = ast_bool[tok.getstr()] return ast.BoolOp(op, [left, right]) @pg.production('exp : exp EQ exp') @pg.production('exp : exp CMP exp') def expr_cmp(p): [left, tok, right] = p op = ast_cmp[tok.getstr()] return ast.Compare(left, [op], [right]) @pg.production('exp : exp ADDSUB exp') @pg.production('exp : exp MULDIV exp') def expr_arithmetic(p): [left, tok, right] = p op = ast_arithmetic[tok.getstr()] return ast.BinOp(left, op, right) @pg.production('exp : NOT exp') def expr_not(p): [_, value] = p return ast.UnaryOp(ast_not, value) @pg.production('exp : LPAR exp RPAR') def expr_par(p): [_, exp, _] = p return exp @pg.production('exp : VAR') def expr_var(p): [tok] = p ident = tok.getstr() assert ident == 'n' return ast.Name(ident, ast.Load()) @pg.production('exp : INT') def expr_int(p): [tok] = p n = int(tok.getstr()) return ast.Num(n) # pylint: enable=unused-variable with misc.throwaway_tempdir('rply'): # Use private temporary directory # to mitigate RPLY's insecure use of /tmp: # CVE-2014-1604, CVE-2014-1938 return pg.build() class Parser(object): def __init__(self): self._lexer = create_lexer() self._parser = create_parser(self._lexer) def parse(self, s): tokens = self._lexer.lex(s) node = self._parser.parse(tokens) return Expression(node) from lib import misc # pylint: disable=wrong-import-position class BaseEvaluator(object): def __init__(self, node): self._ctxt = misc.Namespace() self._node = node def __call__(self): node = self._node assert isinstance(node, ast.Expr) return self._visit_expr(node) def _visit(self, node, *args): try: fn = getattr(self, '_visit_' + type(node).__name__.lower()) except KeyError: # no coverage raise NotImplementedError(type(node).__name__) return fn(node, *args) def _visit_expr(self, node): [node] = ast.iter_child_nodes(node) return self._visit(node) # binary operators # ================ def _visit_binop(self, node): x = self._visit(node.left) if x is None: return y = self._visit(node.right) if y is None: return return self._visit(node.op, x, y) # unary operators # =============== def _visit_unaryop(self, node): x = self._visit(node.operand) if x is None: return return self._visit(node.op, x) # comparison operators # ==================== def _visit_compare(self, node): assert len(node.comparators) == len(node.ops) if len(node.ops) != 1: raise NotImplementedError left = node.left [op] = node.ops [right] = node.comparators left = self._visit(left) if left is None: return right = self._visit(right) if right is None: return return self._visit(op, left, right) # boolean operators # ================= def _visit_boolop(self, node): return self._visit(node.op, *node.values) class Evaluator(BaseEvaluator): def __init__(self, node, n, *, bits): super().__init__(node) self._ctxt.n = n self._ctxt.max = 1 << bits def _check_overflow(self, n): if n < 0: raise OverflowError(n) if n >= self._ctxt.max: raise OverflowError(n) return n # pylint: disable=unused-argument # binary operators # ================ def _visit_add(self, node, x, y): return self._check_overflow(x + y) def _visit_sub(self, node, x, y): return self._check_overflow(x - y) def _visit_mult(self, node, x, y): return self._check_overflow(x * y) def _visit_div(self, node, x, y): return x // y def _visit_mod(self, node, x, y): return x % y # unary operators # =============== def _visit_not(self, node, x): return int(not x) # comparison operators # ==================== def _visit_gte(self, node, x, y): return int(x >= y) def _visit_gt(self, node, x, y): return int(x > y) def _visit_lte(self, node, x, y): return int(x <= y) def _visit_lt(self, node, x, y): return int(x < y) def _visit_eq(self, node, x, y): return int(x == y) def _visit_noteq(self, node, x, y): return int(x != y) # boolean operators # ================= def _visit_and(self, node, *args): for arg in args: if self._visit(arg) == 0: return 0 return 1 def _visit_or(self, node, *args): for arg in args: if self._visit(arg) != 0: return 1 return 0 # if-then-else expression # ======================= def _visit_ifexp(self, node): test = self._visit(node.test) if test: return self._visit(node.body) else: return self._visit(node.orelse) # constants, variables # ==================== def _visit_num(self, node): return self._check_overflow(node.n) def _visit_name(self, node): return self._check_overflow(self._ctxt.n) # pylint: enable=unused-argument class CodomainEvaluator(BaseEvaluator): def __init__(self, node, *, bits): super().__init__(node) self._ctxt.max = 1 << bits # pylint: disable=unused-argument # binary operators # ================ def _visit_add(self, node, x, y): z = ( x[0] + y[0], min(x[1] + y[1], self._ctxt.max - 1) ) if z[0] > z[1]: return return z def _visit_sub(self, node, x, y): z = ( max(x[0] - y[1], 0), x[1] - y[0] ) if z[0] > z[1]: return return z def _visit_mult(self, node, x, y): z = ( x[0] * y[0], min(x[1] * y[1], self._ctxt.max - 1) ) if z[0] > z[1]: return return z def _visit_div(self, node, x, y): if y == (0, 0): # division by zero return assert y[1] > 0 return ( x[0] // y[1], x[1] // max(y[0], 1), ) def _visit_mod(self, node, x, y): if y == (0, 0): # division by zero return assert y[1] > 0 if x[1] < y[0]: # i % j == i if i < j return x return (0, min(x[1], y[1] - 1)) # unary operators # =============== def _visit_not(self, node, x): if x[0] > 0: return (0, 0) elif x == (0, 0): return (1, 1) else: return (0, 1) # comparison operators # ==================== def _visit_gte(self, node, x, y): assert (x is not None) and (y is not None) return ( x[0] >= y[1], x[1] >= y[0], ) def _visit_gt(self, node, x, y): assert (x is not None) and (y is not None) return ( x[0] > y[1], x[1] > y[0], ) def _visit_lte(self, node, x, y): assert (x is not None) and (y is not None) return ( x[1] <= y[0], x[0] <= y[1], ) def _visit_lt(self, node, x, y): assert (x is not None) and (y is not None) return ( x[1] < y[0], x[0] < y[1], ) def _visit_eq(self, node, x, y): assert (x is not None) and (y is not None) if x[0] == x[1] == y[0] == y[1]: return (1, 1) if x[0] <= y[0] <= x[1]: return (0, 1) if y[0] <= x[0] <= y[1]: return (0, 1) return (0, 0) def _visit_noteq(self, node, x, y): assert (x is not None) and (y is not None) if x[0] == x[1] == y[0] == y[1]: return (0, 0) if x[0] <= y[0] <= x[1]: return (0, 1) if y[0] <= x[0] <= y[1]: return (0, 1) return (1, 1) # boolean operators # ================= def _visit_and(self, node, *args): r = (1, 1) for arg in args: assert r != (0, 0) x = self._visit(arg) if x is None: if r == (0, 1): return (0, 0) else: return elif x == (0, 0): return x elif x[0] >= 1: pass else: assert (x[0] == 0) and (x[1] > 0) r = (0, 1) return r def _visit_or(self, node, *args): r = (0, 0) for arg in args: assert r != (1, 1) x = self._visit(arg) if x is None: if r == (0, 1): return (1, 1) else: return elif x[0] >= 1: return (1, 1) elif x == (0, 0): pass else: assert (x[0] == 0) and (x[1] > 0) r = (0, 1) return r # if-then-else expression # ======================= def _visit_ifexp(self, node): test = self._visit(node.test) if test is None: return x = y = None if test[1] > 0: x = self._visit(node.body) if test[0] == 0: y = self._visit(node.orelse) if x is None: return y if y is None: return x return ( min(x[0], y[0]), max(x[1], y[1]), ) # constants, variables # ==================== def _visit_num(self, node): n = node.n if (n < 0) or (n >= self._ctxt.max): return return (n, n) def _visit_name(self, node): return (0, self._ctxt.max - 1) # pylint: enable=unused-argument def gcd(x, y): while y: (x, y) = (y, x % y) return x def lcm(x, *ys): r = x for y in ys: r //= gcd(r, y) r *= y return r class PeriodEvaluator(BaseEvaluator): def __init__(self, node, *, bits): super().__init__(node) self._ctxt.max = 1 << bits # binary operators # ================ def _visit_binop(self, node): const_mod = ( isinstance(node.op, ast.Mod) and isinstance(node.left, ast.Name) and isinstance(node.right, ast.Num) ) if const_mod: n = node.right.n if (n <= 0) or (n >= self._ctxt.max): return return (0, n) x = self._visit(node.left) if x is None: return y = self._visit(node.right) if y is None: return (xo, xp) = x (yo, yp) = y ro = max(xo, yo) rp = lcm(xp, yp) if rp >= self._ctxt.max: return else: return (ro, rp) # unary operators # =============== def _visit_unaryop(self, node): return self._visit(node.operand) # comparison operators # ==================== def _visit_compare(self, node): assert len(node.comparators) == len(node.ops) if len(node.ops) != 1: raise NotImplementedError [op] = node.ops [right] = node.comparators const_cmp = ( isinstance(node.left, ast.Name) and isinstance(right, ast.Num) ) if const_cmp: n = right.n if (n < 0) or (n >= self._ctxt.max): return # (n N) is constant starting with either N or N+1, # depending on : # # …N-1 N N+1 N+2… # -------+---+---+---+---- # n != N | 1 . 0 . 1 . 1 # n == N | 0 . 1 . 0 . 0 # n <= N | 1 . 1 . 0 . 0 # n > N | 0 . 0 . 1 . 1 # -------+---+---+---+---- # n < N | 1 . 0 . 0 . 0 # n >= N | 0 . 1 . 1 . 1 # -------+---+---+---+---- if isinstance(op, (ast.Lt, ast.GtE)): return (n, 1) else: if n + 1 == self._ctxt.max: return return (n + 1, 1) x = self._visit(node.left) if x is None: return y = self._visit(right) if y is None: return (xo, xp) = x (yo, yp) = y ro = max(xo, yo) rp = lcm(xp, yp) if rp >= self._ctxt.max: return else: return (ro, rp) # boolean operators # ================= def _visit_boolop(self, node): (xo, xp) = (0, 1) for arg in node.values: y = self._visit(arg) if y is None: return (yo, yp) = y xo = max(xo, yo) xp = lcm(xp, yp) if xp >= self._ctxt.max: return return (xo, xp) # if-then-else expression # ======================= def _visit_ifexp(self, node): test = self._visit(node.test) if test is None: return (to, tp) = test x = self._visit(node.body) if x is None: return (xo, xp) = x y = self._visit(node.orelse) if y is None: return (yo, yp) = y ro = max(to, xo, yo) rp = lcm(tp, xp, yp) if rp >= self._ctxt.max: return else: return (ro, rp) # constants, variables # ==================== def _visit_num(self, node): n = node.n if n < 0 or n >= self._ctxt.max: return return (0, 1) def _visit_name(self, node): # pylint: disable=unused-argument return class Expression(object): def __init__(self, node): if not isinstance(node, ast.Expr): raise TypeError # no coverage self._node = node def __call__(self, n, *, bits=32): ''' return f(n) ''' e = Evaluator(self._node, n, bits=bits) return e() def codomain(self, *, bits=32): ''' return * (L, R) such that for every n: L ≤ f(n) ≤ R * or None ''' e = CodomainEvaluator(self._node, bits=bits) return e() def period(self, *, bits=32): ''' return * (O, P) such that for every n ≥ O: f(n + P) = f(n) * or None ''' e = PeriodEvaluator(self._node, bits=bits) return e() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/iconv.py0000644000000000000000000002365513147102065014420 0ustar0000000000000000# Copyright © 2012-2013 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string encoding and decoding using iconv(3), with a fallback to iconv(1) ''' import ctypes import errno import os import subprocess as ipc import re import sys default_encoding = sys.getdefaultencoding() _boring_iconv_stderr = re.compile('\nTry .+ for more information[.]$') _libc = ctypes.CDLL(None, use_errno=True) try: _iconv_open = _libc.iconv_open _iconv_close = _libc.iconv_close _iconv = _libc.iconv except AttributeError: _iconv = _iconv_open = _iconv_close = None else: _iconv_open.argtypes = [ctypes.c_char_p, ctypes.c_char_p] _iconv_open.restype = ctypes.c_void_p _iconv_close.argtypes = [ctypes.c_void_p] _iconv_close.restype = ctypes.c_int _iconv.argtypes = ( [ctypes.c_void_p] + [ctypes.POINTER(ctypes.POINTER(ctypes.c_char)), ctypes.POINTER(ctypes.c_size_t)] * 2 ) _iconv.restype = ctypes.c_size_t def _popen(*args): def set_lc_all_c(): os.environ['LC_ALL'] = 'C' # no coverage return ipc.Popen(args, stdin=ipc.PIPE, stdout=ipc.PIPE, stderr=ipc.PIPE, preexec_fn=set_lc_all_c, ) def encode(input: str, encoding=default_encoding, errors='strict'): if not isinstance(input, str): raise TypeError('input must be str, not {tp}'.format(tp=type(input).__name__)) if not isinstance(encoding, str): raise TypeError('encoding must be str, not {tp}'.format(tp=type(encoding).__name__)) if not isinstance(errors, str): raise TypeError('errors must be str, not {tp}'.format(tp=type(errors).__name__)) if len(input) == 0: return b'' if errors != 'strict': raise NotImplementedError('error handler {e!r} is not implemented'.format(e=errors)) return _encode(input, encoding=encoding) def _encode_dl(input: str, *, encoding): if sys.maxunicode < (1 << 16): uencoding = 'UTF-16LE' uwidth = 2 else: uencoding = 'UTF-32LE' uwidth = 4 binput = bytes(input, encoding=uencoding) assert len(binput) == len(input) * uwidth cd = _iconv_open(bytes(encoding, 'ASCII'), bytes(uencoding, 'ASCII')) assert isinstance(cd, int) if cd == ctypes.c_void_p(-1).value: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) try: c_input = ctypes.c_char_p(binput) output_len = len(input) while True: inbuf = ctypes.cast(c_input, ctypes.POINTER(ctypes.c_char)) inbytesleft = ctypes.c_size_t(len(binput)) assert inbytesleft.value == len(binput) # no overflow outbuf = ctypes.create_string_buffer(output_len) outbytesleft = ctypes.c_size_t(output_len) assert outbytesleft.value == output_len # no overflow rc = _iconv(cd, None, None, None, None) if rc == ctypes.c_size_t(-1).value: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) inbufptr = ctypes.pointer(ctypes.cast(inbuf, ctypes.POINTER(ctypes.c_char))) outbufptr = ctypes.pointer(ctypes.cast(outbuf, ctypes.POINTER(ctypes.c_char))) rc = _iconv(cd, inbufptr, ctypes.byref(inbytesleft), outbufptr, ctypes.byref(outbytesleft), ) if rc != ctypes.c_size_t(-1).value: rc = _iconv(cd, None, None, outbufptr, ctypes.byref(outbytesleft), ) if rc == ctypes.c_size_t(-1).value: rc = ctypes.get_errno() if rc == errno.E2BIG: output_len *= 2 continue elif rc in {errno.EILSEQ, errno.EINVAL}: begin = len(input) - inbytesleft.value // uwidth raise UnicodeEncodeError( encoding, input, begin, begin + 1, os.strerror(errno.EILSEQ), ) raise OSError(rc, os.strerror(rc)) assert inbytesleft.value == 0, '{n} bytes left'.format(n=inbytesleft.value) output_len -= outbytesleft.value return outbuf[:output_len] finally: rc = _iconv_close(cd) if rc != 0: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) def _encode_cli(input, *, encoding): child = _popen('iconv', '-f', 'UTF-8', '-t', encoding) (stdout, stderr) = child.communicate(input.encode('UTF-8')) if stderr != b'': stderr = stderr.decode('ASCII', 'replace') stderr = _boring_iconv_stderr.sub('', stderr) raise UnicodeEncodeError(encoding, input, # .object 0, # .begin len(input), # .end stderr.strip() # .reason ) return stdout _encode = _encode_dl if _iconv is not None else _encode_cli def decode(input: bytes, encoding=default_encoding, errors='strict'): if not isinstance(input, bytes): raise TypeError('input must be bytes, not {tp}'.format(tp=type(input).__name__)) if not isinstance(encoding, str): raise TypeError('encoding must be str, not {tp}'.format(tp=type(encoding).__name__)) if not isinstance(errors, str): raise TypeError('errors must be str, not {tp}'.format(tp=type(errors).__name__)) if len(input) == 0: return '' if errors != 'strict': raise NotImplementedError('error handler {e!r} is not implemented'.format(e=errors)) return _decode(input, encoding=encoding) def _decode_dl(input: bytes, *, encoding): cd = _iconv_open(b'WCHAR_T', bytes(encoding, 'ASCII')) assert isinstance(cd, int) if cd == ctypes.c_void_p(-1).value: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) try: c_input = ctypes.c_char_p(input) output_len = len(input) while True: inbuf = ctypes.cast(c_input, ctypes.POINTER(ctypes.c_char)) inbytesleft = ctypes.c_size_t(len(input)) assert inbytesleft.value == len(input) # no overflow outbuf = ctypes.create_unicode_buffer(output_len) outbytesleft = ctypes.c_size_t(output_len) # no overflow assert outbytesleft.value == output_len rc = _iconv(cd, None, None, None, None) if rc == ctypes.c_size_t(-1).value: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) inbufptr = ctypes.pointer(ctypes.cast(inbuf, ctypes.POINTER(ctypes.c_char))) outbufptr = ctypes.pointer(ctypes.cast(outbuf, ctypes.POINTER(ctypes.c_char))) rc = _iconv(cd, inbufptr, ctypes.byref(inbytesleft), outbufptr, ctypes.byref(outbytesleft), ) if rc != ctypes.c_size_t(-1).value: rc = _iconv(cd, None, None, outbufptr, ctypes.byref(outbytesleft), ) if rc == ctypes.c_size_t(-1).value: rc = ctypes.get_errno() if rc == errno.E2BIG: output_len *= 2 continue elif rc in {errno.EILSEQ, errno.EINVAL}: begin = len(input) - inbytesleft.value for end in range(begin + 1, len(input)): # Assume that the encoding can be synchronized on ASCII characters. # That's not necessarily true for _every_ encoding, but oh well. if input[end] < 0x80: break else: end = len(input) raise UnicodeDecodeError( encoding, input, begin, end, os.strerror(errno.EILSEQ), ) raise OSError(rc, os.strerror(rc)) assert inbytesleft.value == 0, '{n} bytes left'.format(n=inbytesleft.value) output_len -= outbytesleft.value assert output_len % ctypes.sizeof(ctypes.c_wchar) == 0 unicode_output_len = output_len // ctypes.sizeof(ctypes.c_wchar) return outbuf[:unicode_output_len] finally: rc = _iconv_close(cd) if rc != 0: rc = ctypes.get_errno() raise OSError(rc, os.strerror(rc)) def _decode_cli(input, *, encoding): child = _popen('iconv', '-f', encoding, '-t', 'UTF-8') (stdout, stderr) = child.communicate(input) if stderr != b'': stderr = stderr.decode('ASCII', 'replace') stderr = _boring_iconv_stderr.sub('', stderr) raise UnicodeDecodeError(encoding, input, # .object 0, # .begin len(input), # .end stderr.strip() # .reason ) return stdout.decode('UTF-8') _decode = _decode_dl if _iconv is not None else _decode_cli __all__ = ['encode', 'decode'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/gettext.py0000644000000000000000000001417413147102065014762 0ustar0000000000000000# Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' gettext header support: - header field names registry - date parser - plural expressions parser - string formats registry ''' import configparser import datetime import os import re from lib import intexpr from lib import misc from lib import paths # ============= # header fields # ============= def _read_header_fields(): path = os.path.join(paths.datadir, 'header-fields') with open(path, 'rt', encoding='ASCII') as file: fields = [ s.rstrip() for s in file if s.rstrip() and not s.startswith('#') ] misc.check_sorted(fields) return frozenset(fields) header_fields = _read_header_fields() # ========================== # header and message parsing # ========================== is_valid_field_name = re.compile(r'^[\x21-\x39\x3b-\x7e]+$').match # https://tools.ietf.org/html/rfc5322#section-3.6.8 def parse_header(s): lines = s.split('\n') if lines[-1] == '': lines.pop() for line in lines: key, *values = line.split(':', 1) if values and is_valid_field_name(key): assert len(values) == 1 value = values[0].strip(' \t') yield {key: value} else: yield line search_for_conflict_marker = re.compile(r'^#-#-#-#-# .+ #-#-#-#-#$', re.MULTILINE).search # http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/msgl-cat.c?id=v0.18.3#n590 # https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia # ============ # plural forms # ============ class PluralFormsSyntaxError(Exception): pass class PluralExpressionSyntaxError(PluralFormsSyntaxError): pass def parse_plural_expression(s): parser = intexpr.Parser() try: return parser.parse(s) except intexpr.LexingError: raise PluralExpressionSyntaxError except intexpr.ParsingError: raise PluralExpressionSyntaxError _parse_plural_forms = re.compile(r'nplurals=([1-9][0-9]*);[ \t]*plural=([^;]+);?').search def parse_plural_forms(s, strict=True): match = _parse_plural_forms(s) if match is None: raise PluralFormsSyntaxError n = int(match.group(1), 10) expr = parse_plural_expression(match.group(2)) if strict: if match.start() != 0: raise PluralFormsSyntaxError if match.end() != len(s): raise PluralFormsSyntaxError return (n, expr) else: ljunk = s[:match.start()] rjunk = s[match.end():] return (n, expr, ljunk, rjunk) # ===== # Dates # ===== class DateSyntaxError(Exception): pass class BoilerplateDate(DateSyntaxError): pass def _read_timezones(): path = os.path.join(paths.datadir, 'timezones') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.optionxform = str cp.read(path, encoding='ASCII') return { abbrev: offsets.split() for abbrev, offsets in cp['timezones'].items() } _timezones = _read_timezones() _tz_re = '|'.join(re.escape(tz) for tz in _timezones) _parse_date = re.compile(r''' ^ ( [0-9]{4}-[0-9]{2}-[0-9]{2} ) # YYYY-MM-DD (?: \s+ | T ) ( [0-9]{2}:[0-9]{2} ) # hh:mm (?: : [0-9]{2} )? # ss \s* (?: (?: GMT | UTC )? ( [+-] [0-9]{2} ) :? ( [0-9]{2} ) # ZZzz | [+]? (''' + _tz_re + ''') ) ? $ ''', re.VERBOSE).match boilerplate_date = 'YEAR-MO-DA HO:MI+ZONE' _search_for_date_boilerplate = re.compile(r''' ^ YEAR - | - MO - | - DA \s | \s HO : | : MI (?:[+]|$) | [+] ZONE $ ''', re.VERBOSE).search def fix_date_format(s, *, tz_hint=None): s = s.strip() if _search_for_date_boilerplate(s): raise BoilerplateDate if tz_hint is not None: datetime.datetime.strptime(tz_hint, '%z') # just check syntax match = _parse_date(s) if match is None: raise DateSyntaxError (date, time, zhour, zminute, zabbr) = match.groups() if (zhour is not None) and (zminute is not None): zone = zhour + zminute elif zabbr is not None: try: [zone] = _timezones[zabbr] except ValueError: raise DateSyntaxError('ambiguous timezone abbreviation: ' + zabbr) elif tz_hint is not None: zone = tz_hint else: raise DateSyntaxError s = '{} {}{}'.format(date, time, zone) assert len(s) == 21, 'len({!r}) != 21'.format(s) parse_date(s) # just check syntax return s def parse_date(s): try: return datetime.datetime.strptime(s, '%Y-%m-%d %H:%M%z') except ValueError as exc: raise DateSyntaxError(exc) epoch = datetime.datetime(1995, 7, 2, tzinfo=datetime.timezone.utc) # ============== # string formats # ============== def _read_string_formats(): path = os.path.join(paths.datadir, 'string-formats') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='ASCII') section = cp['formats'] misc.check_sorted(section) return { name: frozenset(examples.split()) for name, examples in section.items() } string_formats = _read_string_formats() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/encodings.py0000644000000000000000000001664313147102065015252 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' - encoding information registry - codecs for unusual encodings ''' import codecs import configparser import encodings.aliases as encoding_aliases import errno import functools import itertools import os import unicodedata from lib import iconv from lib import misc from lib import paths class EncodingLookupError(LookupError): def __init__(self, encoding): LookupError.__init__(self, 'unknown encoding: ' + encoding) def _not_implemented(*args, **kwargs): # no coverage del args, kwargs raise NotImplementedError def charmap_encoding(encoding): def encode(input, errors='strict'): return codecs.charmap_encode(input, errors, encoding_table) def decode(input, errors='strict'): return codecs.charmap_decode(input, errors, decoding_table) path = os.path.join(paths.datadir, 'charmaps', encoding.upper()) try: file = open(path, 'rb') except IOError as exc: if exc.errno == errno.ENOENT: raise EncodingLookupError(encoding) raise with file: decoding_table = file.read() decoding_table = decoding_table.decode('UTF-8') encoding_table = codecs.charmap_build(decoding_table) return codecs.CodecInfo( encode=encode, decode=decode, streamreader=_not_implemented, streamwriter=_not_implemented, incrementalencoder=_not_implemented, incrementaldecoder=_not_implemented, name=encoding, ) def iconv_encoding(encoding): def encode(input, errors='strict'): output = iconv.encode(input, encoding=encoding, errors=errors) return output, len(input) def decode(input, errors='strict'): output = iconv.decode(bytes(input), encoding=encoding, errors=errors) return output, len(input) return codecs.CodecInfo( encode=encode, decode=decode, streamreader=_not_implemented, streamwriter=_not_implemented, incrementalencoder=_not_implemented, incrementaldecoder=_not_implemented, name=encoding, ) _interesting_ascii_bytes = bytes(itertools.chain([ 0, # NUL 4, # EOT 7, # BEL 8, # BS 9, # HT 10, # LF 11, # VT 12, # FF 13, # CR 27, # ESC ], range(32, 127))) _interesting_ascii_str = _interesting_ascii_bytes.decode() def _read_encodings(): path = os.path.join(paths.datadir, 'encodings') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') e2c = {} c2e = {} for encoding, extra in cp['portable-encodings'].items(): e2c[encoding] = None if extra == '': pycodec = codecs.lookup(encoding) e2c[encoding] = pycodec c2e.setdefault(pycodec.name, encoding) elif extra == 'not-python': pass else: raise misc.DataIntegrityError extra_encodings = { key.lower() for key, value in cp['extra-encodings'].items() } return (e2c, c2e, extra_encodings) [_portable_encodings, _pycodec_to_encoding, _extra_encodings] = _read_encodings() def _read_control_characters(): path = os.path.join(paths.datadir, 'control-characters') cp = configparser.ConfigParser(interpolation=None, default_section='') cp.read(path, encoding='UTF-8') for section in cp.values(): if not section.name: continue misc.check_sorted(section) for code, name in section.items(): if len(code) != 2: raise misc.DataIntegrityError code = chr(int(code, 16)) if unicodedata.category(code) != 'Cc': raise misc.DataIntegrityError if name.upper() != name: raise misc.DataIntegrityError yield (code, name) _control_character_names = dict(_read_control_characters()) def get_portable_encodings(python=True): return ( encoding for encoding, codec in _portable_encodings.items() if (not python) or (codec is not None) ) def is_portable_encoding(encoding, python=True): encoding = encoding.lower() if encoding.startswith('iso_'): encoding = 'iso-' + encoding[4:] if python: return _portable_encodings.get(encoding, None) is not None else: return encoding in _portable_encodings def propose_portable_encoding(encoding, python=True): del python # never used; only encodings supported by Python are proposed try: pycodec = codecs.lookup(encoding) new_encoding = _pycodec_to_encoding[pycodec.name] except LookupError: return assert is_portable_encoding(new_encoding, python=True) return new_encoding.upper() def is_ascii_compatible_encoding(encoding, *, missing_ok=True): try: decoded_ascii_bytes = _interesting_ascii_bytes.decode(encoding) if isinstance(decoded_ascii_bytes, bytes): # may happen on PyPy for non-text encodings raise RuntimeError return decoded_ascii_bytes == _interesting_ascii_str except UnicodeDecodeError: return False except LookupError: pass except Exception: # no coverage; pylint: disable=broad-except pass if missing_ok: return False else: raise EncodingLookupError(encoding) def _codec_search_function(encoding): if _portable_encodings.get(encoding, False) is None: # portable according to gettext documentation # but not supported directly by Python pass elif encoding in _extra_encodings: # non-portable, but used by real-world software pass else: return try: return charmap_encoding(encoding) except EncodingLookupError: return iconv_encoding(encoding) @functools.lru_cache(maxsize=1) def install_extra_encodings(): codecs.register(_codec_search_function) for enc_name in _portable_encodings: if enc_name.startswith('iso-'): suffix = enc_name[4:].replace('-', '_') encoding_aliases.aliases.setdefault(suffix, 'iso' + suffix) def get_character_name(ch): try: return unicodedata.name(ch) except ValueError: if unicodedata.category(ch) == 'Cn': return 'non-character' name = _control_character_names.get(ch) if name is None: raise return 'control character ' + name # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/domains.py0000644000000000000000000000456113147102065014727 0ustar0000000000000000# Copyright © 2013-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' special-use domain names ''' # https://www.iana.org/assignments/special-use-domain-names/special-use-domain-names.xhtml import re _regexps = [ # RFC 1035, §3.5 : '.+[.]in-addr[.]arpa', # RFC 3596, §2.5 : '.+[.]ip6[.]arpa', # RFC 6761, §6 : '(.+[.])?test', '(.+[.])?localhost', '(.+[.])?invalid', '(.+[.])?example([.](com|net|org))?', # RFC 6762, §3 : '(.+[.])local', ] _is_special = re.compile( '^({re})$'.format(re='|'.join(_regexps)) ).match def is_special_domain(domain): domain = domain.lower() return _is_special(domain) def is_email_in_special_domain(email): _, domain = email.rsplit('@', 1) return is_special_domain(domain) def is_dotless_domain(domain): return '.' not in domain def is_email_in_dotless_domain(email): # Technically, e-mail addresses in dotless domains are not forbidden. # But in practice they are almost certainly mistakes. # See also: RFC 7085 _, domain = email.rsplit('@', 1) return is_dotless_domain(domain) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/cli.py0000644000000000000000000001741413147102065014045 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' command-line interface ''' import argparse import concurrent.futures import functools import io import multiprocessing import os import subprocess as ipc import sys import tempfile from lib import check from lib import ling from lib import misc from lib import paths as pathmod from lib import tags from lib import terminal __version__ = '0.25.5' def initialize_terminal(): if sys.stdout.isatty(): terminal.initialize() if sys.stdout.errors != 'strict': return sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding=sys.stdout.encoding, errors='backslashreplace', line_buffering=sys.stdout.line_buffering, ) class Checker(check.Checker): def tag(self, tagname, *extra): if tagname in self.options.ignore_tags: return try: tag = tags.get_tag(tagname) except KeyError: raise misc.DataIntegrityError( 'attempted to emit an unknown tag: {tag!r}'.format(tag=tagname) ) s = tag.format(self.fake_path, *extra, color=True) print(s) def check_regular_file(filename, *, options): checker_instance = Checker(filename, options=options) checker_instance.check() def copy_options(options, **update): kwargs = vars(options) kwargs.update(update) return argparse.Namespace(**kwargs) class UnsupportedFileType(ValueError): pass def check_deb(filename, *, options): if filename.endswith('.deb'): binary = True elif filename.endswith('.dsc'): binary = False else: raise UnsupportedFileType ignore_tags = set(options.ignore_tags) ignore_tags.add('unknown-file-type') with tempfile.TemporaryDirectory(prefix='i18nspector.deb.') as tmpdir: if binary: ipc.check_call(['dpkg-deb', '-x', filename, tmpdir]) real_root = os.path.join(tmpdir, '') else: real_root = os.path.join(tmpdir, 's', '') with open(os.devnull) as bitbucket: ipc.check_call( ['dpkg-source', '--no-copy', '--no-check', '-x', filename, real_root], stdout=bitbucket # dpkg-source would be noisy without this... ) options = copy_options(options, ignore_tags=ignore_tags, fake_root=(real_root, os.path.join(filename, '')) ) for root, dirs, files in os.walk(tmpdir): del dirs for path in files: path = os.path.join(root, path) if os.path.islink(path): continue if os.path.isfile(path): check_file(path, options=options) def check_file(path, *, options): if options.unpack_deb: try: return check_deb(path, options=options) except UnsupportedFileType: pass return check_regular_file(path, options=options) def check_file_s(path, *, options): ''' check_file() with captured stdout ''' orig_stdout = sys.stdout sys.stdout = io_stdout = io.StringIO() try: check_file(path, options=options) finally: sys.stdout = orig_stdout return io_stdout.getvalue() def check_all(paths, *, options): if (len(paths) <= 1) or (options.jobs <= 1): for path in paths: check_file(path, options=options) else: executor = concurrent.futures.ProcessPoolExecutor(max_workers=options.jobs) with executor: check_file_opt = functools.partial(check_file_s, options=options) for s in executor.map(check_file_opt, paths): sys.stdout.write(s) def parse_jobs(s): if s == 'auto': try: return multiprocessing.cpu_count() except NotImplementedError: return 1 n = int(s) if n <= 0: raise ValueError return n parse_jobs.__name__ = 'jobs' class VersionAction(argparse.Action): def __init__(self, option_strings, dest=argparse.SUPPRESS): super().__init__( option_strings=option_strings, dest=dest, nargs=0, help="show program's version information and exit" ) def __call__(self, parser, namespace, values, option_string=None): print('{prog} {0}'.format(__version__, prog=parser.prog)) print('+ Python {0}.{1}.{2}'.format(*sys.version_info)) print('+ polib {0}'.format(check.polib.__version__)) rply = check.gettext.intexpr.rply try: rply_version = rply.__version__ except AttributeError: # __version__ is available only since rply 0.7.4+: # https://github.com/alex/rply/pull/58 try: import pkg_resources [dist, *rest] = pkg_resources.require('rply') del rest assert dist.project_name == 'rply' rply_version = dist.version except ImportError: # oh well... rply_version = None if rply_version is not None: print('+ rply {0}'.format(rply_version)) parser.exit() def main(): initialize_terminal() ap = argparse.ArgumentParser(description=__doc__) ap.add_argument('--version', action=VersionAction) ap.add_argument('-l', '--language', metavar='', help='assume this language') ap.add_argument('--unpack-deb', action='store_true', help='allow unpacking Debian packages') ap.add_argument('-j', '--jobs', type=parse_jobs, metavar='', default=None, help='use processes') ap.add_argument('--parallel', type=int, metavar='', default=None, help=argparse.SUPPRESS) # renamed as -j/--jobs in 0.25 ap.add_argument('--file-type', metavar='', help=argparse.SUPPRESS) ap.add_argument('--traceback', action='store_true', help=argparse.SUPPRESS) ap.add_argument('files', metavar='', nargs='+') options = ap.parse_args() files = options.files del options.files pathmod.check() if options.language is not None: try: language = ling.parse_language(options.language) language.fix_codes() except ling.LanguageError: if options.traceback: raise ap.error('invalid language') language.remove_encoding() language.remove_nonlinguistic_modifier() options.language = language if options.jobs is None: if options.parallel is not None: options.jobs = options.parallel if options.jobs is None: options.jobs = 1 del options.parallel options.ignore_tags = set() options.fake_root = None Checker.patch_environment() check_all(files, options=options) __all__ = ['main'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/check/0000755000000000000000000000000013147102065013772 5ustar0000000000000000i18nspector-0.25.5/lib/check/msgrepr.py0000644000000000000000000000303113147102065016020 0ustar0000000000000000# Copyright © 2012-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' string representation of messages ''' from lib import tags def message_repr(message, template='{}'): subtemplate = 'msgid {id}' kwargs = dict(id=message.msgid) if message.msgctxt is not None: subtemplate += ' msgctxt {ctxt}' kwargs.update(ctxt=message.msgctxt) template = template.format(subtemplate) return tags.safe_format(template, **kwargs) __all__ = ['message_repr'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/check/msgformat/0000755000000000000000000000000013147102065015771 5ustar0000000000000000i18nspector-0.25.5/lib/check/msgformat/python.py0000644000000000000000000001465313147102065017675 0ustar0000000000000000# Copyright © 2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks: Python's %-formatting ''' from lib import tags from lib.check.msgformat import Checker as CheckerBase from lib.check.msgrepr import message_repr from lib.strformat import python as backend class Checker(CheckerBase): backend = backend def check_string(self, ctx, message, s): prefix = message_repr(message, template='{}:') fmt = None try: fmt = backend.FormatString(s) except backend.ArgumentTypeMismatch as exc: [s, key, types] = exc.args # pylint: disable=unbalanced-tuple-unpacking self.tag('python-format-string-error', prefix, tags.safestr(exc.message), tags.safestr(key), tags.safestr(', '.join(sorted(x for x in types))), ) except backend.Error as exc: self.tag('python-format-string-error', prefix, tags.safestr(exc.message), *exc.args[:1] ) if fmt is None: return for warn in fmt.warnings: try: raise warn except backend.RedundantFlag as exc: if len(exc.args) == 2: [s, *args] = exc.args else: [s, a1, a2] = exc.args if a1 == a2: args = ['duplicate', a1] else: args = [a1, tags.safe_format('overridden by {}', a2)] args += ['in', s] self.tag('python-format-string-redundant-flag', prefix, *args ) except backend.RedundantPrecision as exc: [s, a] = exc.args self.tag('python-format-string-redundant-precision', prefix, a, 'in', s ) except backend.RedundantLength as exc: [s, a] = exc.args self.tag('python-format-string-redundant-length', prefix, a, 'in', s ) except backend.ObsoleteConversion as exc: [s, c1, c2] = exc.args args = [c1, '=>', c2] if s != c1: args += ['in', s] self.tag('python-format-string-obsolete-conversion', prefix, *args ) if ctx.is_template: if len(fmt.seq_conversions) > 1: self.tag('python-format-string-multiple-unnamed-arguments', message_repr(message) ) elif len(fmt.seq_conversions) == 1: arg_for_plural = ( message.msgid_plural is not None and fmt.seq_conversions[0].type == 'int' ) if arg_for_plural: self.tag('python-format-string-unnamed-plural-argument', message_repr(message) ) return fmt def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): prefix = message_repr(message, template='{}:') # unnamed arguments: src_args = src_fmt.seq_arguments dst_args = dst_fmt.seq_arguments if len(dst_args) != len(src_args): self.tag('python-format-string-argument-number-mismatch', prefix, len(dst_args), tags.safestr('({})'.format(dst_loc)), '!=', len(src_args), tags.safestr('({})'.format(src_loc)), ) for src_arg, dst_arg in zip(src_args, dst_args): if src_arg.type != dst_arg.type: self.tag('python-format-string-argument-type-mismatch', prefix, tags.safestr(dst_arg.type), tags.safestr('({})'.format(dst_loc)), '!=', tags.safestr(src_arg.type), tags.safestr('({})'.format(src_loc)), ) # named arguments: src_args = src_fmt.map_arguments dst_args = dst_fmt.map_arguments for key in sorted(dst_args.keys() & src_args.keys()): src_arg = src_args[key][0] dst_arg = dst_args[key][0] if src_arg.type != dst_arg.type: self.tag('python-format-string-argument-type-mismatch', prefix, tags.safestr(dst_arg.type), tags.safestr('({})'.format(dst_loc)), '!=', tags.safestr(src_arg.type), tags.safestr('({})'.format(src_loc)), ) for key in sorted(dst_args.keys() - src_args.keys()): self.tag('python-format-string-unknown-argument', prefix, key, tags.safestr('in'), tags.safestr(dst_loc), tags.safestr('but not in'), tags.safestr(src_loc), ) missing_keys = src_args.keys() - dst_args.keys() if len(missing_keys) == 1 and omitted_int_conv_ok: [missing_key] = missing_keys if all(arg.type == 'int' for arg in src_args[missing_key]): missing_keys = set() for key in sorted(missing_keys): self.tag('python-format-string-missing-argument', prefix, key, tags.safestr('not in'), tags.safestr(dst_loc), tags.safestr('while in'), tags.safestr(src_loc), ) __all__ = ['Checker'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/check/msgformat/pybrace.py0000644000000000000000000000664113147102065017777 0ustar0000000000000000# Copyright © 2016-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks: Python's str.format() ''' from lib import tags from lib.check.msgformat import Checker as CheckerBase from lib.check.msgrepr import message_repr from lib.strformat import pybrace as backend class Checker(CheckerBase): backend = backend def check_string(self, ctx, message, s): prefix = message_repr(message, template='{}:') fmt = None try: fmt = backend.FormatString(s) except backend.Error as exc: self.tag('python-brace-format-string-error', prefix, tags.safestr(exc.message), *exc.args[:1] ) else: return fmt def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): def sort_key(item): return (isinstance(item, str), item) prefix = message_repr(message, template='{}:') src_args = src_fmt.argument_map dst_args = dst_fmt.argument_map for key in sorted(dst_args.keys() & src_args.keys(), key=sort_key): src_arg = src_args[key][0] dst_arg = dst_args[key][0] if not (src_arg.types & dst_arg.types): self.tag('python-brace-format-string-argument-type-mismatch', prefix, tags.safestr(', '.join(dst_arg.types)), tags.safestr('({})'.format(dst_loc)), '!=', tags.safestr(', '.join(src_arg.types)), tags.safestr('({})'.format(src_loc)), ) for key in sorted(dst_args.keys() - src_args.keys(), key=sort_key): self.tag('python-brace-format-string-unknown-argument', prefix, key, tags.safestr('in'), tags.safestr(dst_loc), tags.safestr('but not in'), tags.safestr(src_loc), ) missing_keys = src_args.keys() - dst_args.keys() if len(missing_keys) == 1 and omitted_int_conv_ok: [missing_key] = missing_keys if all('int' in arg.types for arg in src_args[missing_key]): missing_keys = set() for key in sorted(missing_keys): self.tag('python-brace-format-string-missing-argument', prefix, key, tags.safestr('not in'), tags.safestr(dst_loc), tags.safestr('while in'), tags.safestr(src_loc), ) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/check/msgformat/c.py0000644000000000000000000001252013147102065016565 0ustar0000000000000000# Copyright © 2014-2015 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks: C ''' from lib import tags from lib.check.msgformat import Checker as CheckerBase from lib.check.msgrepr import message_repr from lib.strformat import c as backend class Checker(CheckerBase): backend = backend def check_msgids(self, message, msgid_fmts): if msgid_fmts.get(0) is not None: try: [[arg]] = msgid_fmts[0].arguments except ValueError: pass else: if arg.type == 'int *': self.tag('qt-plural-format-mistaken-for-c-format', message_repr(message)) def check_string(self, ctx, message, s): prefix = message_repr(message, template='{}:') fmt = None try: fmt = backend.FormatString(s) except backend.MissingArgument as exc: self.tag('c-format-string-error', prefix, tags.safestr(exc.message), tags.safestr('{1}$'.format(*exc.args)), ) except backend.ArgumentTypeMismatch as exc: self.tag('c-format-string-error', prefix, tags.safestr(exc.message), tags.safestr('{1}$'.format(*exc.args)), tags.safestr(', '.join(sorted(x for x in exc.args[2]))), ) except backend.FlagError as exc: [conv, flag] = exc.args # pylint: disable=unbalanced-tuple-unpacking self.tag('c-format-string-error', prefix, tags.safestr(exc.message), flag, tags.safestr('in'), conv ) except backend.Error as exc: self.tag('c-format-string-error', prefix, tags.safestr(exc.message), *exc.args[:1] ) if fmt is None: return for warn in fmt.warnings: try: raise warn except backend.RedundantFlag as exc: if len(exc.args) == 2: [s, *args] = exc.args else: [s, a1, a2] = exc.args if a1 == a2: args = ['duplicate', a1] else: args = [a1, tags.safe_format('overridden by {}', a2)] args += ['in', s] self.tag('c-format-string-redundant-flag', prefix, *args ) except backend.NonPortableConversion as exc: [s, c1, c2] = exc.args args = [c1, '=>', c2] if s != c1: args += ['in', s] self.tag('c-format-string-non-portable-conversion', prefix, *args ) return fmt def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): prefix = message_repr(message, template='{}:') src_args = src_fmt.arguments dst_args = dst_fmt.arguments if len(dst_args) > len(src_args): self.tag('c-format-string-excess-arguments', prefix, len(dst_args), tags.safestr('({})'.format(dst_loc)), '>', len(src_args), tags.safestr('({})'.format(src_loc)), ) elif len(dst_args) < len(src_args): if omitted_int_conv_ok: n_args_omitted = len(src_args) - len(dst_args) omitted_int_conv_ok = src_fmt.get_last_integer_conversion(n=n_args_omitted) if not omitted_int_conv_ok: self.tag('c-format-string-missing-arguments', prefix, len(dst_args), tags.safestr('({})'.format(dst_loc)), '<', len(src_args), tags.safestr('({})'.format(src_loc)), ) for src_arg, dst_arg in zip(src_args, dst_args): src_arg = src_arg[0] dst_arg = dst_arg[0] if src_arg.type != dst_arg.type: self.tag('c-format-string-argument-type-mismatch', prefix, tags.safestr(dst_arg.type), tags.safestr('({})'.format(dst_loc)), '!=', tags.safestr(src_arg.type), tags.safestr('({})'.format(src_loc)), ) __all__ = ['Checker'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/check/msgformat/__init__.py0000644000000000000000000001545413147102065020113 0ustar0000000000000000# Copyright © 2014-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' message format checks ''' import abc from lib import misc class Checker(object, metaclass=abc.ABCMeta): def __init__(self, parent): self.parent = parent @abc.abstractproperty def backend(self): return def tag(self, tagname, *extra): return self.parent.tag(tagname, *extra) def check_message(self, ctx, message, flags): msgids = [message.msgid] if message.msgid_plural is not None: msgids += [message.msgid_plural] msgid_fmts = {} for i, s in enumerate(msgids): if ctx.is_template: fmt = self.check_string(ctx, message, s) else: try: fmt = self.backend.FormatString(s) except self.backend.Error: # If msgid isn't even a valid format string, then # reporting errors against msgstr is not worth the trouble. return if fmt is not None: msgid_fmts[i] = fmt if ctx.is_template and (len(msgid_fmts) == 2): self.check_args( message, 'msgid_plural', msgid_fmts[1], 'msgid', msgid_fmts[0], omitted_int_conv_ok=True, ) self.check_msgids(message, msgid_fmts) if flags.fuzzy: return if ctx.encoding is None: return has_msgstr = bool(message.msgstr) has_msgstr_plural = any(message.msgstr_plural.values()) strings = [] if has_msgstr: d = misc.Namespace() d.src_loc = 'msgid' d.src_fmt = msgid_fmts.get(0) d.dst_loc = 'msgstr' d.dst_fmt = self.check_string(ctx, message, message.msgstr) d.omitted_int_conv_ok = False strings += [d] if has_msgstr_plural and ctx.plural_preimage: for i, s in sorted(message.msgstr_plural.items()): assert isinstance(i, int) d = misc.Namespace() msgid_fmt = msgid_fmts.get(0) msgid_plural_fmt = msgid_fmts.get(1) d.src_loc = 'msgid_plural' d.src_fmt = msgid_plural_fmt d.dst_loc = 'msgstr[{}]'.format(i) d.dst_fmt = self.check_string(ctx, message, s) if d.dst_fmt is None: continue try: preimage = ctx.plural_preimage[i] except KeyError: # broken plural forms continue preimage = [ x for x in preimage if flags.range_min <= x <= flags.range_max ] # XXX In theory, the msgstr[] corresponding to n=1 should # not have more arguments than msgid. In practice, it's not # uncommon to see something like this: # # Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; # # msgid "one byte" # msgid_plural "%d bytes" # msgstr[0] "%d bajt" # msgstr[1] "%d bajta" # msgstr[2] "%d bajtova" # # Here %d in msgstr[0] cannot be omitted, because it is used # not only for n=1, but also for n=21, n=31, and so on. # # To be pedantically correct, one could use a different # Plural-Forms, such that there is a separate value for n=1. # # See also: https://bugs.debian.org/753946 if preimage == [1]: # FIXME: “preimage” is not necessarily complete. # So it's theoretically possible that this msgstr[] # corresponds to both n=1 and another n. d.src_loc = 'msgid' d.src_fmt = msgid_fmt d.omitted_int_conv_ok = ( msgid_fmt is not None and msgid_plural_fmt is not None and len(msgid_fmt) == len(msgid_plural_fmt) # FIXME: The length equality is a rather weak indicator # that msgid and msgid_plural are equivalent. ) elif len(preimage) <= 1: d.omitted_int_conv_ok = True elif len(preimage) == 2 and preimage[0] == 0: # XXX In theory, the integer conversion should not be # omitted in the msgstr[] corresponding to both n=0 and # another n. In practice, it's sometimes obvious from # context that the message will never be used for n=0. d.omitted_int_conv_ok = True else: d.omitted_int_conv_ok = False strings += [d] for d in strings: if d.dst_fmt is None: continue if d.src_fmt is None: continue assert d.src_loc is not None assert d.dst_loc is not None self.check_args(message, d.src_loc, d.src_fmt, d.dst_loc, d.dst_fmt, omitted_int_conv_ok=d.omitted_int_conv_ok, ) def check_msgids(self, message, msgid_fmts): pass # no coverage @abc.abstractmethod def check_string(self, ctx, message, s): pass # no coverage @abc.abstractmethod def check_args(self, message, src_loc, src_fmt, dst_loc, dst_fmt, *, omitted_int_conv_ok=False): pass # no coverage __all__ = ['Checker'] # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/check/__init__.py0000644000000000000000000013250213147102065016106 0ustar0000000000000000# Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' checks ''' import abc import collections import difflib import email.utils import heapq import os import re import urllib.parse import polib from lib import domains from lib import encodings as encinfo from lib import gettext from lib import ling from lib import misc from lib import polib4us from lib import tags from lib import xml from lib.check.msgformat import c as msgformat_c from lib.check.msgformat import pybrace as msgformat_pybrace from lib.check.msgformat import python as msgformat_python from lib.check.msgrepr import message_repr class EnvironmentNotPatched(RuntimeError): pass class EnvironmentAlreadyPatched(RuntimeError): pass find_unusual_characters = re.compile( r'[\x00-\x08\x0B-\x1A\x1C-\x1F]' # C0 except TAB, LF, ESC r'|\x1B(?!\[)' # ESC, except when followed by [ r'|\x7F' # DEL r'|[\x80-\x9F]' # C1 '|\uFEFF' # ZERO WIDTH NO-BREAK SPACE '|\uFFFD' # REPLACEMENT CHARACTER '|[\uFFFE\uFFFF]' # non-characters r'|(?<=\w)\xBF' # INVERTED QUESTION MARK but only directly after a letter ).findall header_fields_with_dedicated_checks = set() def checks_header_fields(*fields): def identity(x): return x header_fields_with_dedicated_checks.update(fields) return identity class Checker(object, metaclass=abc.ABCMeta): _patched_environment = None @classmethod def patch_environment(cls): if cls._patched_environment is not None: raise EnvironmentAlreadyPatched encinfo.install_extra_encodings() polib4us.install_patches() cls._patched_environment = True def __init__(self, path, *, options): if self._patched_environment is not True: raise EnvironmentNotPatched self.path = path self.fake_path = path if options.fake_root is not None: (real_root, fake_root) = options.fake_root if not real_root.endswith(os.sep): raise ValueError if not fake_root.endswith(os.sep): raise ValueError if path.startswith(real_root): self.fake_path = fake_root + path[len(real_root):] self.options = options self._message_format_checkers = { 'c': msgformat_c.Checker(self), 'python': msgformat_python.Checker(self), 'python-brace': msgformat_pybrace.Checker(self), } @abc.abstractmethod def tag(self, tagname, *extra): return def check(self): # If a file passed to polib doesn't exist, it will “helpfully” treat it # as PO/MO file _contents_. This is definitely not what we want. To # prevent such disaster, fail early if the file doesn't exit. try: os.stat(self.path) except EnvironmentError as exc: self.tag('os-error', tags.safestr(exc.strerror)) return if self.options.file_type is None: extension = os.path.splitext(self.path)[-1] else: extension = '.' + self.options.file_type is_template = False is_binary = False if extension == '.po': constructor = polib.pofile elif extension == '.pot': constructor = polib.pofile is_template = True elif extension in ('.mo', '.gmo'): constructor = polib.mofile is_binary = True else: self.tag('unknown-file-type') return broken_encoding = False try: try: file = constructor(self.path) except UnicodeDecodeError as exc: broken_encoding = exc file = constructor(self.path, encoding='ISO-8859-1') except polib4us.moparser.SyntaxError as exc: self.tag('invalid-mo-file', tags.safestr(exc)) return except IOError as exc: message = str(exc) if exc.errno is not None: self.tag('os-error', tags.safestr(exc.strerror)) return elif message.startswith('Syntax error in po file '): message = message[24:] message_parts = [] if message.startswith(self.path + ' '): message = message[len(self.path)+1:] match = re.match(r'^\(line ([0-9]+)\)(?:: (.+))?$', message) if match is not None: lineno_part = 'line {}'.format(match.group(1)) message = match.group(2) if message is not None: lineno_part += ':' if re.match(r'^[a-z]+( [a-z]+)*$', message): message = tags.safestr(message) message_parts += [tags.safestr(lineno_part)] if message is not None: message_parts += [message] self.tag('syntax-error-in-po-file', *message_parts) return raise finally: if broken_encoding: # pylint: disable=no-member s = broken_encoding.object assert isinstance(s, bytes) begin = max(broken_encoding.start - 40, 0) end = broken_encoding.start + 40 s = s[begin:end] self.tag('broken-encoding', s, tags.safestr('cannot be decoded as'), broken_encoding.encoding.upper(), ) # pylint: enable=no-member broken_encoding = True ctx = misc.Namespace() ctx.file = file ctx.is_template = is_template ctx.is_binary = is_binary self.check_comments(ctx) self.check_headers(ctx) self.check_language(ctx) self.check_plurals(ctx) self.check_mime(ctx) if broken_encoding: ctx.encoding = None self.check_dates(ctx) self.check_project(ctx) self.check_translator(ctx) self.check_messages(ctx) def check_comments(self, ctx): regexs = { r'\bPACKAGE package\b', r'\bCopyright \S+ YEAR\b', r"\bTHE PACKAGE'S COPYRIGHT HOLDER\b", } if not ctx.is_template: regexs |= { r'\bFIRST AUTHOR\b', r'', r'(?<=>), YEAR\b', } regex = re.compile('|'.join(regexs)) for line in ctx.file.header.splitlines(): match = regex.search(line) if match is None: continue self.tag('boilerplate-in-initial-comments', line) @checks_header_fields('Language', 'X-Poedit-Language', 'X-Poedit-Country') def check_language(self, ctx): ctx.language = None duplicate_meta_language = False meta_languages = ctx.metadata['Language'] if len(meta_languages) > 1: self.tag('duplicate-header-field-language') meta_languages = sorted(set(meta_languages)) if len(meta_languages) > 1: duplicate_meta_language = True if len(meta_languages) == 1: [meta_language] = meta_languages else: meta_language = None orig_meta_language = meta_language if ctx.is_template: if meta_language is None: self.tag('no-language-header-field') return language = self.options.language language_source = 'command-line' language_source_quality = 1 if language is None: path_components = os.path.normpath(self.path).split('/') try: i = path_components.index('LC_MESSAGES') except ValueError: i = 0 if i > 0: language = path_components[i - 1] try: language = ling.parse_language(language) language.fix_codes() language.remove_encoding() language.remove_nonlinguistic_modifier() except ling.LanguageError: # It's not our job to report possible errors in _pathnames_. language = None else: language_source = 'pathname' del path_components, i if language is None and self.path.endswith('.po'): language, ext = os.path.splitext(os.path.basename(self.path)) assert ext == '.po' try: language = ling.parse_language(language) if language.encoding is not None: # It's very likely that something else has been confused # for the apparent encoding. raise ling.LanguageError language.fix_codes() language.remove_nonlinguistic_modifier() except ling.LanguageError: # It's not our job to report possible errors in _pathnames_. language = None else: language_source = 'pathname' language_source_quality = 0 if meta_language: try: meta_language = ling.parse_language(meta_language) except ling.LanguageError: try: new_meta_language = ling.get_language_for_name(meta_language) except LookupError: new_meta_language = None if new_meta_language: self.tag('invalid-language', orig_meta_language, '=>', new_meta_language) else: self.tag('invalid-language', orig_meta_language) meta_language = new_meta_language if meta_language: if meta_language.remove_encoding(): self.tag('encoding-in-language-header-field', orig_meta_language) if meta_language.remove_nonlinguistic_modifier(): self.tag('language-variant-does-not-affect-translation', orig_meta_language) try: if meta_language.fix_codes(): self.tag('invalid-language', orig_meta_language, '=>', meta_language) except ling.LanguageError: self.tag('invalid-language', orig_meta_language) meta_language = None if language_source_quality <= 0 and ( '/{lang}/'.format(lang=meta_language) in self.path or '/{lang}/'.format(lang=str(meta_language).replace('_', '-')) in self.path ): # For LibreOffice, PO basename does not designate translation # language, but one of the path components does. # For example, # translations/source/da/dictionaries/pl_PL.po # is a Danish translation. language = None if meta_language: if language is None: language = meta_language language_source = 'Language header field' elif language != meta_language: self.tag('language-disparity', language, tags.safestr('({})'.format(language_source)), '!=', meta_language, tags.safestr('(Language header field)') ) 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 = 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)) if len(poedit_languages) == 1 and len(poedit_countries) <= 1: [poedit_language] = poedit_languages # FIXME: This should take also X-Poedit-Country into account. try: poedit_language = ling.get_language_for_name(poedit_language) except LookupError: self.tag('unknown-poedit-language', poedit_language) else: if language is None: language = poedit_language language_source = 'X-Poedit-Language header field' elif language.language_code != poedit_language.language_code: self.tag('language-disparity', language, tags.safestr('({})'.format(language_source)), '!=', poedit_language, tags.safestr('(X-Poedit-Language header field)') ) if language is None: if not orig_meta_language and not duplicate_meta_language: self.tag('no-language-header-field') self.tag('unable-to-determine-language') return if not orig_meta_language and not duplicate_meta_language: self.tag('no-language-header-field', tags.safestr('Language:'), language) ctx.language = language @checks_header_fields('Plural-Forms') def check_plurals(self, ctx): ctx.plural_preimage = None plural_forms = ctx.metadata['Plural-Forms'] if len(plural_forms) > 1: self.tag('duplicate-header-field-plural-forms') plural_forms = sorted(set(plural_forms)) if len(plural_forms) > 1: return if len(plural_forms) == 1: [plural_forms] = plural_forms else: assert len(plural_forms) == 0 plural_forms = None correct_plural_forms = None 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 ctx.file: if message.obsolete: continue if message.msgid_plural is not None: has_plurals = True if not message.translated(): continue expected_nplurals[len(message.msgstr_plural)] = message if len(expected_nplurals) > 1: break if len(expected_nplurals) > 1: args = [] for n, message in sorted(expected_nplurals.items()): args += [n, message_repr(message, template='({})'), '!='] self.tag('inconsistent-number-of-plural-forms', *args[:-1]) if ctx.is_template: plural_forms_hint = 'nplurals=INTEGER; plural=EXPRESSION;' elif correct_plural_forms: plural_forms_hint = tags.safe_format( ' or '.join('{}' for s in correct_plural_forms), *correct_plural_forms ) else: plural_forms_hint = 'nplurals=; plural=' if plural_forms is None: if has_plurals: if expected_nplurals: self.tag('no-required-plural-forms-header-field', plural_forms_hint) else: self.tag('no-plural-forms-header-field', plural_forms_hint) return if ctx.is_template: return try: (n, expr, ljunk, rjunk) = gettext.parse_plural_forms(plural_forms, strict=False) except gettext.PluralFormsSyntaxError: if has_plurals: self.tag('syntax-error-in-plural-forms', plural_forms, '=>', plural_forms_hint) else: self.tag('syntax-error-in-unused-plural-forms', plural_forms, '=>', plural_forms_hint) return if ljunk: self.tag('leading-junk-in-plural-forms', ljunk) if rjunk: self.tag('trailing-junk-in-plural-forms', rjunk) if len(expected_nplurals) == 1: [expected_nplurals] = expected_nplurals.keys() if n != expected_nplurals: self.tag('incorrect-number-of-plural-forms', n, tags.safestr('(Plural-Forms header field)'), '!=', expected_nplurals, tags.safestr('(number of msgstr items)') ) locally_correct_n = locally_correct_expr = None if correct_plural_forms is not None: locally_correct_plural_forms = [ (i, expression) for i, expression in map(gettext.parse_plural_forms, correct_plural_forms) if i == n ] if not locally_correct_plural_forms: if has_plurals: self.tag('unusual-plural-forms', plural_forms, '=>', plural_forms_hint) else: self.tag('unusual-unused-plural-forms', plural_forms, '=>', plural_forms_hint) elif len(locally_correct_plural_forms) == 1: [[locally_correct_n, locally_correct_expr]] = locally_correct_plural_forms plural_preimage = collections.defaultdict(list) unusual_plural_forms = False codomain_limit = 200 try: for i in range(codomain_limit): fi = expr(i) if fi >= n: message = tags.safe_format('f({}) = {} >= {}'.format(i, fi, n)) if has_plurals: self.tag('codomain-error-in-plural-forms', message) else: self.tag('codomain-error-in-unused-plural-forms', message) break plural_preimage[fi] += [i] if (n == locally_correct_n) and (fi != locally_correct_expr(i)) and (not unusual_plural_forms): if has_plurals: self.tag('unusual-plural-forms', plural_forms, '=>', plural_forms_hint) else: self.tag('unusual-unused-plural-forms', plural_forms, '=>', plural_forms_hint) unusual_plural_forms = True else: ctx.plural_preimage = dict(plural_preimage) except OverflowError: message = tags.safe_format('f({}): integer overflow', i) if has_plurals: self.tag('arithmetic-error-in-plural-forms', message) else: self.tag('arithmetic-error-in-unused-plural-forms', message) except ZeroDivisionError: message = tags.safe_format('f({}): division by zero', i) if has_plurals: self.tag('arithmetic-error-in-plural-forms', message) else: self.tag('arithmetic-error-in-unused-plural-forms', message) codomain = expr.codomain() if codomain is not None: (x, y) = codomain uncov_rngs = [] if x > 0: uncov_rngs += [range(0, x)] if y + 1 < n: uncov_rngs += [range(y + 1, n)] if (not uncov_rngs) and (ctx.plural_preimage is not None): period = expr.period() if period is None: period = (0, 1e999) if sum(period) < codomain_limit: for i in sorted(ctx.plural_preimage): if (i > 0) and (i - 1 not in ctx.plural_preimage): uncov_rngs += [range(i - 1, i)] break if (i + 1 < n) and (i + 1 not in ctx.plural_preimage): uncov_rngs += [range(i + 1, i + 2)] break for rng in uncov_rngs: rng = misc.format_range(rng, max=5) message = tags.safestr('f(x) != {}'.format(rng)) if has_plurals: self.tag('codomain-error-in-plural-forms', message) else: self.tag('codomain-error-in-unused-plural-forms', message) ctx.plural_preimage = None @checks_header_fields('MIME-Version', 'Content-Transfer-Encoding', 'Content-Type') def check_mime(self, ctx): ctx.encoding = None # 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)) for mime_version in mime_versions: if mime_version != '1.0': self.tag('invalid-mime-version', mime_version, '=>', '1.0') if len(mime_versions) == 0: self.tag('no-mime-version-header-field', tags.safestr('MIME-Version: 1.0')) # 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)) for cte in ctes: if cte != '8bit': self.tag('invalid-content-transfer-encoding', cte, '=>', '8bit') if len(ctes) == 0: self.tag('no-content-transfer-encoding-header-field', tags.safestr('Content-Transfer-Encoding: 8bit')) # Content-Type: cts = ctx.metadata['Content-Type'] if len(cts) > 1: self.tag('duplicate-header-field-content-type') cts = sorted(set(cts)) elif len(cts) == 0: content_type_hint = 'text/plain; charset=' self.tag('no-content-type-header-field', tags.safestr('Content-Type: ' + content_type_hint)) return encodings = set() for ct in cts: content_type_hint = 'text/plain; charset=' match = re.search(r'(\Atext/plain; )?\bcharset=([^\s;]+)\Z', ct) if match: encoding = match.group(2) try: is_ascii_compatible = encinfo.is_ascii_compatible_encoding(encoding, missing_ok=False) except encinfo.EncodingLookupError: if encoding == 'CHARSET': if not ctx.is_template: self.tag('boilerplate-in-content-type', ct) else: self.tag('unknown-encoding', encoding) encoding = None else: if not is_ascii_compatible: self.tag('non-ascii-compatible-encoding', encoding) elif encinfo.is_portable_encoding(encoding): pass else: new_encoding = encinfo.propose_portable_encoding(encoding) if new_encoding is not None: self.tag('non-portable-encoding', encoding, '=>', new_encoding) encoding = new_encoding else: self.tag('non-portable-encoding', 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:] = ['...'] self.tag('unrepresentable-characters', encoding, *unrepresentable_characters) if match.group(1) is None: if encoding is not None: content_type_hint = content_type_hint.replace('', encoding) self.tag('invalid-content-type', ct, '=>', content_type_hint) if encoding is not None: encodings.add(encoding) else: self.tag('invalid-content-type', ct, '=>', content_type_hint) if len(encodings) == 1: [ctx.encoding] = encodings @checks_header_fields('POT-Creation-Date', 'PO-Revision-Date') def check_dates(self, ctx): try: 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 = ctx.metadata[field] if len(dates) > 1: self.tag('duplicate-header-field-date', field) dates = sorted(set(dates)) elif len(dates) == 0: if field.startswith('POT-') and ctx.is_binary: # In gettext >> 0.19.8.1, msgfmt will be removing # the POT-Creation-Date header. # https://savannah.gnu.org/bugs/?49654 continue self.tag('no-date-header-field', field) continue for date in dates: 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: # https://sources.debian.net/src/publican/2.8-3/lib/Publican/Translate.pm/?hl=748#L744 # https://bugs.debian.org/714739 tz_hint = '-0000' else: tz_hint = None try: fixed_date = gettext.fix_date_format(date, tz_hint=tz_hint) except gettext.BoilerplateDate: self.tag('boilerplate-in-date', tags.safestr(field + ':'), date) continue except gettext.DateSyntaxError: self.tag('invalid-date', tags.safestr(field + ':'), date) continue else: if date != fixed_date: self.tag('invalid-date', tags.safestr(field + ':'), date, '=>', fixed_date) stamp = gettext.parse_date(fixed_date) if stamp > misc.utc_now(): self.tag('date-from-future', tags.safestr(field + ':'), date) if stamp < gettext.epoch: self.tag('ancient-date', tags.safestr(field + ':'), date) @checks_header_fields('Project-Id-Version', 'Report-Msgid-Bugs-To') def check_project(self, ctx): # 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)) elif len(project_id_versions) == 0: self.tag('no-project-id-version-header-field') for project_id_version in project_id_versions: if project_id_version in {'PACKAGE VERSION', 'PROJECT VERSION'}: self.tag('boilerplate-in-project-id-version', project_id_version) else: if not re.search(r'[^_\d\W]', 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 = 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)) if report_msgid_bugs_tos == ['']: report_msgid_bugs_tos = [] if len(report_msgid_bugs_tos) == 0: self.tag('no-report-msgid-bugs-to-header-field') for report_msgid_bugs_to in report_msgid_bugs_tos: real_name, email_address = email.utils.parseaddr(report_msgid_bugs_to) del real_name if '@' not in email_address: uri = urllib.parse.urlparse(report_msgid_bugs_to) if uri.scheme == '': self.tag('invalid-report-msgid-bugs-to', report_msgid_bugs_to) elif domains.is_email_in_special_domain(email_address): self.tag('invalid-report-msgid-bugs-to', report_msgid_bugs_to) elif email_address == 'EMAIL@ADDRESS': self.tag('boilerplate-in-report-msgid-bugs-to', report_msgid_bugs_to) elif domains.is_email_in_dotless_domain(email_address): self.tag('invalid-report-msgid-bugs-to', report_msgid_bugs_to) @checks_header_fields('Last-Translator', 'Language-Team') def check_translator(self, ctx): # Last-Translator: translators = ctx.metadata['Last-Translator'] if len(translators) > 1: self.tag('duplicate-header-field-last-translator') translators = sorted(set(translators)) elif len(translators) == 0: self.tag('no-last-translator-header-field') translator_emails = {} for translator in translators: translator_name, translator_email = email.utils.parseaddr(translator) del translator_name translator_emails[translator_email] = translator if '@' not in translator_email: self.tag('invalid-last-translator', translator) elif domains.is_email_in_special_domain(translator_email): self.tag('invalid-last-translator', translator) elif translator_email == 'EMAIL@ADDRESS': if not ctx.is_template: self.tag('boilerplate-in-last-translator', translator) elif domains.is_email_in_dotless_domain(translator_email): self.tag('invalid-last-translator', translator) # Language-Team: teams = ctx.metadata['Language-Team'] if len(teams) > 1: self.tag('duplicate-header-field-language-team') teams = sorted(set(teams)) elif len(teams) == 0: self.tag('no-language-team-header-field') for team in teams: team_name, team_email = email.utils.parseaddr(team) del team_name if '@' not in team_email: # TODO: A URL is also allowed here. # self.tag('invalid-language-team', translator) pass elif domains.is_email_in_special_domain(team_email): self.tag('invalid-language-team', team) elif team_email in {'LL@li.org', 'EMAIL@ADDRESS'}: if not ctx.is_template: self.tag('boilerplate-in-language-team', team) elif domains.is_email_in_dotless_domain(team_email): self.tag('invalid-language-team', team) else: translator = translator_emails.get(team_email) if translator is not None: self.tag('language-team-equal-to-last-translator', team, translator) def check_headers(self, ctx): metadata = collections.defaultdict(list) strays = [] ctx.file.header_entry = None seen_header_entry = False for entry in ctx.file: if not is_header_entry(entry) or entry.obsolete: continue if seen_header_entry: self.tag('duplicate-header-entry') break if entry.occurrences: self.tag('empty-msgid-message-with-source-code-references', *(':'.join((path, line)) for path, line in entry.occurrences) ) if entry.msgid_plural is not None: self.tag('empty-msgid-message-with-plural-forms') msgstr = entry.msgstr_plural.get(0, entry.msgstr) # At least in polib 1.0.0, if the source PO file is empty, # msgstr for the header entry is None. msgstr = msgstr or '' for line in gettext.parse_header(msgstr): if isinstance(line, dict): [(key, value)] = line.items() metadata[key] += [value] else: strays += [line] flags = collections.Counter(entry.flags) for flag, n in sorted(flags.items()): if flag == 'fuzzy': 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') else: self.tag('unexpected-flag-for-header-entry', flag) if n > 1: self.tag('duplicate-flag-for-header-entry', flag) if entry is not ctx.file[0]: self.tag('distant-header-entry') unusual_chars = set(find_unusual_characters(msgstr)) if unusual_chars: unusual_char_names = ', '.join( 'U+{:04X} {}'.format(ord(ch), encinfo.get_character_name(ch)) for ch in sorted(unusual_chars) ) self.tag('unusual-character-in-header-entry', tags.safestr(unusual_char_names)) seen_header_entry = True seen_conflict_marker = False for stray in strays: if gettext.search_for_conflict_marker(stray): if not seen_conflict_marker: self.tag('conflict-marker-in-header-entry', stray) seen_conflict_marker = True else: self.tag('stray-header-line', stray) header_fields = frozenset(gettext.header_fields) header_fields_lc = {str.lower(s): s for s in header_fields} for key, values in sorted(metadata.items()): if key.startswith(('X-', 'x-')): pass # ok elif key in header_fields: pass # ok else: hint = header_fields_lc.get(key.lower()) if hint is None: hints = difflib.get_close_matches(key, header_fields, n=1, cutoff=0.8) if hints: [hint] = hints if hint in metadata: hint = None if hint is None: self.tag('unknown-header-field', key) else: 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) ctx.metadata = metadata del ctx.file.metadata del ctx.file.metadata_is_fuzzy def check_messages(self, ctx): found_unusual_characters = set() msgid_counter = collections.Counter() for message in ctx.file: if message.obsolete: continue if is_header_entry(message): continue flags = self._check_message_flags(message) self._check_message_formats(ctx, message, flags) msgid_counter[message.msgid, message.msgctxt] += 1 if msgid_counter[message.msgid, message.msgctxt] == 2: self.tag('duplicate-message-definition', message_repr(message)) has_msgstr = bool(message.msgstr) has_msgstr_plural = any(message.msgstr_plural.values()) if ctx.is_template: if has_msgstr or has_msgstr_plural: self.tag('translation-in-template', message_repr(message)) leading_lf = message.msgid.startswith('\n') trailing_lf = message.msgid.endswith('\n') has_previous_msgid = any(s is not None for s in [ message.previous_msgctxt, message.previous_msgid, message.previous_msgid_plural, ]) if has_previous_msgid and not flags.fuzzy: self.tag('stray-previous-msgid', message_repr(message)) strings = [] if message.msgid_plural is not None: strings += [message.msgid_plural] if not flags.fuzzy: if has_msgstr: strings += [message.msgstr] if has_msgstr_plural: strings += message.msgstr_plural.values() # the order doesn't matter here for s in strings: if s.startswith('\n') != leading_lf: self.tag('inconsistent-leading-newlines', message_repr(message)) break for s in strings: if s.endswith('\n') != trailing_lf: self.tag('inconsistent-trailing-newlines', message_repr(message)) break strings = [] if has_msgstr: strings += [message.msgstr] if has_msgstr_plural: strings += misc.sorted_vk(message.msgstr_plural) if ctx.encoding is not None: msgid_uc = ( set(find_unusual_characters(message.msgid)) | set(find_unusual_characters(message.msgid_plural or '')) ) for msgstr in strings: msgstr_uc = set(find_unusual_characters(msgstr)) uc = msgstr_uc - msgid_uc - found_unusual_characters if not uc: continue names = ', '.join( 'U+{:04X} {}'.format(ord(ch), encinfo.get_character_name(ch)) for ch in sorted(uc) ) self.tag('unusual-character-in-translation', message_repr(message, template='{}:'), tags.safestr(names) ) found_unusual_characters |= uc if not flags.fuzzy: for msgstr in strings: conflict_marker = gettext.search_for_conflict_marker(msgstr) if conflict_marker is not None: conflict_marker = conflict_marker.group(0) self.tag('conflict-marker-in-translation', message_repr(message), conflict_marker) break if has_msgstr_plural and not all(message.msgstr_plural.values()): self.tag('partially-translated-message', message_repr(message)) if len(msgid_counter) == 0: possible_hidden_strings = False if ctx.is_binary: possible_hidden_strings = ctx.file.possible_hidden_strings if not possible_hidden_strings: self.tag('empty-file') def _check_message_flags(self, message): info = misc.Namespace() info.fuzzy = False info.range_min = 0 info.range_max = 1e999 # +inf info.formats = None flags = collections.Counter(message.flags) wrap = None format_flags = collections.defaultdict(dict) range_flags = collections.defaultdict( collections.Counter ) for flag, n in sorted(flags.items()): known_flag = True if flag == 'fuzzy': info.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 message.msgid_plural is None: self.tag('range-flag-without-plural-string') match = re.match(r'\A([0-9]+)[.][.]([0-9]+)\Z', flag[6:].strip(' \t\r\f\v')) if match is not None: i, j = map(int, match.groups()) if i < j: info.range_min = i info.range_max = j else: match = None if match is None: self.tag('invalid-range-flag', message_repr(message, template='{}:'), flag ) else: range_flags[i, j][flag] += n n = 0 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 ) if len(range_flags) > 1: [range1, range2] = heapq.nsmallest(2, range_flags.keys()) self.tag('conflicting-message-flags', message_repr(message, template='{}:'), min(range_flags[range1].keys()), min(range_flags[range2].keys()), ) elif len(range_flags) == 1: [range_flags] = range_flags.values() if sum(range_flags.values()) > 1: self.tag('duplicate-message-flag', message_repr(message, template='{}:'), min(range_flags.keys()) ) positive_format_flags = format_flags[''] info.formats = frozenset(positive_format_flags) for fmt1, flag1 in sorted(positive_format_flags.items()): for fmt2, flag2 in sorted(positive_format_flags.items()): if fmt1 >= fmt2: continue fmt_ex1 = gettext.string_formats[fmt1] fmt_ex2 = gettext.string_formats[fmt2] if fmt_ex1 & fmt_ex2: # the formats are, at least to some extent, compatible continue self.tag('conflicting-message-flags', message_repr(message, template='{}:'), flag1, flag2 ) 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 info def _check_message_formats(self, ctx, message, flags): for fmt in sorted(flags.formats): try: checker = self._message_format_checkers[fmt] except KeyError: continue checker.check_message(ctx, message, flags) if re.match(r'\Atype: Content of: (<{xmlname}>)+\Z'.format(xmlname=xml.name_re), message.comment or ''): self._check_message_xml_format(ctx, message, flags) def _check_message_xml_format(self, ctx, message, flags): if ctx.encoding is None: return prefix = message_repr(message, template='{}:') try: xml.check_fragment(message.msgid) except xml.SyntaxError as exc: if ctx.is_template: self.tag('malformed-xml', prefix, tags.safestr(exc)) return if flags.fuzzy: return if not message.msgstr: return try: xml.check_fragment(message.msgstr) except xml.SyntaxError as exc: self.tag('malformed-xml', prefix, tags.safestr(exc)) __all__ = ['Checker'] def is_header_entry(entry): return ( entry.msgid == '' and entry.msgctxt is None ) # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/lib/__init__.py0000644000000000000000000000015413147102065015026 0ustar0000000000000000''' i18nspector's private modules ''' # pylint: disable=pointless-statement ... # Python >= 3 is required i18nspector-0.25.5/i18nspector0000755000000000000000000000546513147102065014266 0ustar0000000000000000#!/usr/bin/env python3 # encoding=UTF-8 # Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ''' checking tool for gettext POT, PO and MO files ''' import os import sys # ---------------------------------------- def error(message): try: import argparse ap = argparse.ArgumentParser() prog = ap.prog except ImportError: import optparse # pylint: disable=deprecated-module ap = optparse.OptionParser() prog = ap.get_prog_name() message = ''.join((prog, ': error: ', message, '\n')) ap.exit(1, message) def require_python(*version): if sys.version_info < version: version_str = '.'.join(map(str, version)) message = 'Python >= %s is required' % version_str error(message) def require_maxunicode(n): if sys.maxunicode < n: message = 'sys.maxunicode >= 0x%X is required' % n error(message) def require_polib(*version): import polib polib_version = tuple( int(x) for x in polib.__version__.split('.') ) if polib_version < version: version_str = '.'.join(map(str, version)) message = 'polib >= {ver} is required'.format(ver=version_str) error(message) require_python(3, 2) require_maxunicode(0x10FFFF) require_polib(1, 0, 0) # ---------------------------------------- basedir_fallback = None basedir = os.environ.get('I18NSPECTOR_BASEDIR', basedir_fallback) if basedir is None: basedir = os.path.dirname( os.path.realpath(__file__) ) basedir = os.path.join(basedir, '') os.stat(basedir) sys.path[:0] = [basedir] # pylint: disable=wrong-import-position from lib import paths assert os.path.samefile(basedir, paths.basedir) from lib import cli cli.__doc__ = (__doc__ or '').strip() cli.main() # vim:ts=4 sts=4 sw=4 et i18nspector-0.25.5/doc/0000755000000000000000000000000013147102076012716 5ustar0000000000000000i18nspector-0.25.5/doc/i18nspector.10000644000000000000000000014403513147102076015166 0ustar0000000000000000.\" Man page generated from reStructuredText. . .TH I18NSPECTOR 1 "2017-08-22" "i18nspector 0.25.5" "" .SH NAME i18nspector \- checking tool for gettext POT, PO and MO files . .nr rst2man-indent-level 0 . .de rstReportMargin \\$1 \\n[an-margin] level \\n[rst2man-indent-level] level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] - \\n[rst2man-indent0] \\n[rst2man-indent1] \\n[rst2man-indent2] .. .de INDENT .\" .rstReportMargin pre: . RS \\$1 . nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin] . nr rst2man-indent-level +1 .\" .rstReportMargin post: .. .de UNINDENT . RE .\" indent \\n[an-margin] .\" old: \\n[rst2man-indent\\n[rst2man-indent-level]] .nr rst2man-indent-level -1 .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. .SH SYNOPSIS .sp \fBi18nspector\fP [\fIoptions\fP] \fIfile\fP [\fIfile\fP …] .SH DESCRIPTION .sp \fBi18nspector\fP is a tool for checking translation templates (POT), message catalogues (PO) and compiled message catalogues (MO) files for common problems. These files are used by the GNU gettext translation functions and tools in many different development environments. .SH OPTIONS .INDENT 0.0 .TP .BI \-l \ lang\fR,\fB \ \-\-language \ lang Assume this language. \fIlang\fP should be a 2\- or 3\-letter ISO 639 language code, possibly followed by underscore and a 2\-letter ISO 3166 territory code. .TP .B \-\-unpack\-deb Allow unpacking Debian (binary or source) packages. .TP .BI \-j \ n\fR,\fB \ \-\-jobs \ n Use \fIn\fP processes in parallel. \fIn\fP can be a positive integer, or \fBauto\fP to determine the number automatically. The default is to use only a single process. .TP .B \-h\fP,\fB \-\-help Show the help message and exit. .TP .B \-\-version Show the program's version information and exit. .UNINDENT .SH OUTPUT FORMAT .sp The following format is used for all the reported problems: .sp \ \ \fIcode\fP\fB:\fP \fIfile\fP\fB:\fP \fItag\fP [\fIextra\fP] .sp where: .INDENT 0.0 .IP \(bu 2 \fIcode\fP is a letter indicating type of the message: \fBE\fP (error), \fBW\fP (warning), \fBI\fP (informative message), or \fBP\fP (pedantic message); .IP \(bu 2 \fItag\fP is a name of the problem that was discovered; .IP \(bu 2 \fIextra\fP can contain additional information about the problem. .UNINDENT .SH TAGS .\" This file has been generated automatically by private/tags-as-rst. .\" Do not edit. . .SS ancient\-date .sp The date refers to the time before the first GNU gettext release. As such, it's extremely unlikely to be correct. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%http://git.savannah.gnu.org/cgit/gettext.git/tree/ChangeLog.0#n1767\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS arithmetic\-error\-in\-plural\-forms .sp Computing a plural form value triggers division by zero or integer overflow. This normally indicates an error in the plural form expression. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS arithmetic\-error\-in\-unused\-plural\-forms .sp Computing a plural form value triggers division by zero or integer overflow. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS boilerplate\-in\-content\-type .sp The Content\-Type header field contains xgettext boilerplate. It should be in the form \fBtext/plain; charset=\fP\fIencoding\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-of\-PO\-files\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-date .sp The date header field contains xgettext boilerplate. The date format should be \fBYYYY\-MM\-DD hh:mm+ZZzz\fP, e.g. \fB2011\-11\-05 10:14+0100\fP\&. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-initial\-comments .sp The initial comments contain xgettext or msginit boilerplate. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, possible .UNINDENT .UNINDENT .SS boilerplate\-in\-language\-team .sp The Language\-Team header field contains xgettext boilerplate. It should contain English name of the language, and the email address or homepage URL of the language team. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-last\-translator .sp The Last\-Translator header field contains xgettext boilerplate. It should contain the last translator's name and email address. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-project\-id\-version .sp The Project\-Id\-Version header field contains xgettext boilerplate. It should contain the name and the version of the package. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS boilerplate\-in\-report\-msgid\-bugs\-to .sp The Report\-Msgid\-Bugs\-To header field contains xgettext boilerplate. It should contain an email address or URL where one can report bugs in the untranslated strings. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS broken\-encoding .sp Header fields and messages contained by this file couldn't be decoded to Unicode. The usual cause of this is incorrect or missing encoding declaration. .sp Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-of\-PO\-files\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-5\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-argument\-type\-mismatch .sp There's a type mismatch between a C format argument in \fBmsgid\fP and the corresponding format argument in \fBmsgid_plural\fP; or between a C format argument in \fBmsgstr\fP and \fBmsgid\fP; or between a C format argument in \fBmsgstr[\fP\fIN\fP\fB]\fP and corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-error .sp A C format string could not be parsed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-excess\-arguments .sp A C format string for \fBmsgid\fP consumes more arguments than \fBmsgid_plural\fP; or \fBmsgstr\fP consumes more arguments than \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP consumes more arguments than corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-missing\-arguments .sp A C format string for \fBmsgid\fP consumes fewer arguments than \fBmsgid_plural\fP; or \fBmsgstr\fP consumes fewer arguments than \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP consumes fewer arguments than corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Note that in some languages, the commonly used Plural\-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; \&... msgid "one byte" msgid_plural "%d bytes" msgstr[0] "%d bajt" msgstr[1] "%d bajta" msgstr[2] "%d bajtova" .ft P .fi .UNINDENT .UNINDENT .sp Here \fB%d\fP should not be replaced with the spelled\-out form \fBjedan\fP\&. Either \fB%d\fP should be kept, or the Plural\-Forms expression should be amended, so that there is a special case for n=1: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 \&... msgid "one byte" msgid_plural "%d bytes" msgstr[0] "%d bajt" msgstr[1] "%d bajta" msgstr[2] "%d bajtova" msgstr[3] "jedan bajt" .ft P .fi .UNINDENT .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS c\-format\-string\-non\-portable\-conversion .sp A C format string uses a conversion specified or length modifier, for which a more portable replacement exists: .INDENT 0.0 .IP \(bu 2 For integer conversions (\fB%d\fP, \fB%i\fP, \fB%o\fP, \fB%u\fP, \fB%x\fP, and \fB%X\fP), use the \fBll\fP length modifier instead of \fBL\fP or \fBq\fP\&. .IP \(bu 2 For floating\-point conversions (\fB%a\fP, \fB%A\fP, \fB%e\fP, \fB%E\fP, \fB%f\fP, \fB%F\fP, \fB%g\fP, and \fB%G\fP), don't use the \fBl\fP length modifier. .IP \(bu 2 Use the \fBz\fP length modifier instead of \fBZ\fP\&. .IP \(bu 2 Use \fB%lc\fP instead of \fB%C\fP\&. .IP \(bu 2 Use \fB%ls\fP instead of \fB%S\fP\&. .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS c\-format\-string\-redundant\-flag .sp A C format string includes a redundant character flag. Either it's a duplicate, or it has no effect: .INDENT 0.0 .IP \(bu 2 The \fB+\fP flag overrides the \fIspace\fP flag. .IP \(bu 2 The \fB\-\fP flag overrides the \fB0\fP flag. .IP \(bu 2 If a precision is given, the \fB0\fP flag has no effect on integer conversions (\fB%d\fP, \fB%i\fP, \fB%o\fP, \fB%u\fP, \fB%x\fP, and \fB%X\fP). .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fBprintf\fP(3) .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS codomain\-error\-in\-plural\-forms .sp Either a plural form value is outside the declared range, or some values within the declared range can never be reached. This normally indicates an error in the plural form expression. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS codomain\-error\-in\-unused\-plural\-forms .sp Either a plural form value is outside the declared range, or some values within the declared range can never be reached. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS conflict\-marker\-in\-header\-entry .sp The header contains a conflict marker (\fB#\-#\-#\-#\-#\fP \fI…\fP \fB#\-#\-#\-#\-#\fP). The conflict will have to be resolved manually. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Creating\-Compendia.html#Creating\-Compendia\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS conflict\-marker\-in\-translation .sp One of the translated messages appear to contain a conflict marker (\fB#\-#\-#\-#\-#\fP \fI…\fP \fB#\-#\-#\-#\-#\fP). The conflict will have to be resolved manually. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Creating\-Compendia.html#Creating\-Compendia\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS conflicting\-message\-flags .sp Two flags with conflicting meanings are associated with one of the messages. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS date\-from\-future .sp The date refers to the future. As such, it's extremely unlikely to be correct. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS distant\-header\-entry .sp The header entry in this file is preceded by other entries. The header entry should be always the first one. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS duplicate\-flag\-for\-header\-entry .sp Multiple identical flags are associated with the header entry. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS duplicate\-header\-entry .sp This file contains multiple header entries. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field .sp This file contains multiple header fields of the same name. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, wild\-guess .UNINDENT .UNINDENT .SS duplicate\-header\-field\-content\-transfer\-encoding .sp This file contains multiple Content\-Transfer\-Encoding header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-content\-type .sp This file contains multiple Content\-Type header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-date .sp This file contains multiple date header fields of the same name. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-language .sp This file contains multiple Language header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-language\-team .sp This file contains multiple Language\-Team header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-last\-translator .sp This file contains multiple Last\-Translator header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-mime\-version .sp This file contains multiple MIME\-Version header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-plural\-forms .sp This file contains multiple Plural\-Forms header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-project\-id\-version .sp This file contains multiple Project\-Id\-Version header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-report\-msgid\-bugs\-to .sp This file contains multiple Report\-Msgid\-Bugs\-To header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-header\-field\-x\-poedit .sp This file contains multiple X\-Poedit\-\fI*\fP header fields. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS duplicate\-message\-definition .sp This file contains multiple definitions of the same message. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS duplicate\-message\-flag .sp Multiple identical flags are associated with one of the messages. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS empty\-file .sp This file doesn't contain any messages. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS empty\-msgid\-message\-with\-plural\-forms .sp The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call \fBngettext("", …)\fP\&. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS empty\-msgid\-message\-with\-source\-code\-references .sp The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call \fBgettext("")\fP\&. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS encoding\-in\-language\-header\-field .sp The language header field contains encoding declaration. Such information shouldn't be included in this field. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS fuzzy\-header\-entry .sp The header entry is marked as fuzzy. For compatibility with very old (<< 0.11) \fBmsgfmt\fP(1) versions, which didn't support fuzzy header entries, it shouldn't be marked as such. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%http://git.savannah.gnu.org/cgit/gettext.git/tree/NEWS?id=v0.11#n44\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS inconsistent\-leading\-newlines .sp Some strings in an entry start with a newline, but some don't. Either all of them should start with a newline, or none of them should. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS inconsistent\-number\-of\-plural\-forms .sp Number of plural forms in a message definition doesn't match number of plural forms declared in another message definition. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS inconsistent\-trailing\-newlines .sp Some strings in an entry end with a newline, but some don't. Either all of them should end with a newline, or none of them should. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS incorrect\-number\-of\-plural\-forms .sp Number of plural forms in a message definition doesn't match number of plural forms declared in the header. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS invalid\-content\-transfer\-encoding .sp Value of the Content\-Transfer\-Encoding header field is invalid. It should be \fB8bit\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-6.1\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS invalid\-content\-type .sp Value of the Content\-Type header field should is invalid. It should be in the form \fBtext/plain; charset=\fP\fIencoding\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-of\-PO\-files\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-5\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS invalid\-date .sp The date is invalid or in an invalid format. The format should be \fBYYYY\-MM\-DD hh:mm+ZZzz\fP, e.g. \fB2011\-11\-05 10:14+0100\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS invalid\-language .sp The Language header field couldn't be parsed, or it contains an unknown language. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS invalid\-language\-team .sp The Language\-Team header field contains an e\-mail address that uses a reserved domain name, or a partially qualified domain name. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://tools.ietf.org/html/rfc2606\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS invalid\-last\-translator .sp The Last\-Translator header field could neither be parsed as an e\-mail, or the e\-mail address uses a reserved domain name, or a partially qualified domain name. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP \fI\%https://tools.ietf.org/html/rfc2606\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS invalid\-mime\-version .sp Value of the MIME\-Version header field is invalid. It should be \fB1.0\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://tools.ietf.org/html/rfc2045#section\-4\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS invalid\-mo\-file .sp This file couldn't be parsed a MO file. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS invalid\-range\-flag .sp A \fBrange:\fP flag couldn't be parsed, or the designated range contained fewer than two numbers. The syntax is \fBrange:\fP \fImin\fP\fB\&..\fP\fImax\fP, where both values are non\-negative integers. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS invalid\-report\-msgid\-bugs\-to .sp The Report\-Msgid\-Bugs\-To header field could neither be parsed as an e\-mail nor as a URL, or the e\-mail address uses a reserved domain name, or a partially qualified domain name. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP \fI\%https://tools.ietf.org/html/rfc2606\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS language\-disparity .sp Language of this file has been declared in multiple places, but the declarations don't match. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS language\-team\-equal\-to\-last\-translator .sp Language\-Team and Last\-Translator header fields contain the same e\-mail address. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, possible .UNINDENT .UNINDENT .SS language\-variant\-does\-not\-affect\-translation .sp The Language header field contains a variant designator that is not relevant for the message translation. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, possible .UNINDENT .UNINDENT .SS leading\-junk\-in\-plural\-forms .sp The Plural\-Forms header field contains unexpected text before the \fBnplurals=\fP string. .sp GNU gettext runtime ignores such leading junk, but other header parsers might be less liberal in what they accept. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS malformed\-xml .sp The original string or the translated string contains an XML fragment, which is not well\-formed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.w3.org/TR/REC\-xml/#sec\-well\-formed\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS no\-content\-transfer\-encoding\-header\-field .sp The Content\-Transfer\-Encoding header field doesn't exist. It should be set to \fB8bit\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-6.1\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS no\-content\-type\-header\-field .sp The Content\-Type header field doesn't exist. It should be set to \fBtext/plain; charset=\fP\fIencoding\fP\&. .sp Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-of\-PO\-files\fP \fI\%https://tools.ietf.org/html/rfc2045#section\-5\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS no\-date\-header\-field .sp The date header field doesn't exist. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS no\-language\-header\-field .sp The Language header field doesn't exist. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS no\-language\-team\-header\-field .sp The Language\-Team header field does not exist. It should contain English name of the language, and the email address or homepage URL of the language team. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS no\-last\-translator\-header\-field .sp The Last\-Translator header field doesn't exist. It should contain the last translator's name and email address. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS no\-mime\-version\-header\-field .sp The MIME\-Version header field doesn't exist. It should be to set to \fB1.0\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://tools.ietf.org/html/rfc2045#section\-4\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS no\-package\-name\-in\-project\-id\-version .sp The Project\-Id\-Version header field doesn't appear to contain any name. It should contain both the name and the version of the package. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, possible .UNINDENT .UNINDENT .SS no\-plural\-forms\-header\-field .sp The Plural\-Forms header field does not exist, even though some of the messages use plural forms (although none of them have been translated). .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS no\-project\-id\-version\-header\-field .sp The Project\-Id\-Version header field does not exist. It should contain the name and the version of the package. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS no\-report\-msgid\-bugs\-to\-header\-field .sp The Report\-Msgid\-Bugs\-To header field does not exist or it is empty. It should contain an email address or URL where one can report bugs in the untranslated strings. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS no\-required\-plural\-forms\-header\-field .sp The Plural\-Forms header field does not exist, even though some of the translated messages use plural forms. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS no\-version\-in\-project\-id\-version .sp The Project\-Id\-Version header field doesn't appear to contain any version. It should contain both the name and the version of the package. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS non\-ascii\-compatible\-encoding .sp This file uses an encoding that is not compatible with ASCII. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS non\-portable\-encoding .sp This file uses an encoding that is not widely supported by software. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Header\-Entry.html#index\-encoding\-list\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS os\-error .sp An input/output error or another operating system error occurred while checking this file. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS partially\-translated\-message .sp Translation is missing for some plural forms of a message. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-brace\-format\-string\-argument\-type\-mismatch .sp There's a type mismatch between a Python format argument in \fBmsgid\fP and the corresponding format argument in \fBmsgid_plural\fP; or between a Python format argument in \fBmsgstr\fP and \fBmsgid\fP; or between a Python format argument in \fBmsgstr[\fP\fIN\fP\fB]\fP and \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/string.html#formatstrings\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-brace\-format\-string\-error .sp A Python format string could not be parsed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/string.html#formatstrings\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-brace\-format\-string\-missing\-argument .sp A Python format string for \fBmsgid\fP doesn't use a named argument that is used in \fBmsgid_plural\fP; or \fBmsgstr\fP doesn't use a named argument that is used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP doesn't use a named argument that is used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Note that in some languages, the commonly used Plural\-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; \&... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" .ft P .fi .UNINDENT .UNINDENT .sp Here \fB{n}\fP should not be replaced with the spelled\-out form \fBjedan\fP\&. Either \fB{n}\fP should be kept, or the Plural\-Forms expression should be amended, so that there is a special case for n=1: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 \&... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" msgstr[3] "jedan bajt" .ft P .fi .UNINDENT .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/string.html#formatstrings\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-brace\-format\-string\-unknown\-argument .sp A Python format string for \fBmsgid\fP uses a named argument that isn't used in \fBmsgid_plural\fP; or \fBmsgstr\fP uses a named argument that isn't used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP uses a named argument that isn't used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. This indicates that the conversion would try to consume an argument that weren't supplied. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/string.html#formatstrings\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-argument\-number\-mismatch .sp A Python format string for \fBmsgid\fP consumes more arguments than \fBmsgid_plural\fP; or \fBmsgstr\fP consumes more arguments than \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP consumes more arguments than \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Python, unlike C, requires that all unnamed arguments are consumed during conversion. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-argument\-type\-mismatch .sp There's a type mismatch between a Python format argument in \fBmsgid\fP and the corresponding format argument in \fBmsgid_plural\fP; or between a Python format argument in \fBmsgstr\fP and \fBmsgid\fP; or between a Python format argument in \fBmsgstr[\fP\fIN\fP\fB]\fP and \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-error .sp A Python format string could not be parsed. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-missing\-argument .sp A Python format string for \fBmsgid\fP doesn't use a named argument that is used in \fBmsgid_plural\fP; or \fBmsgstr\fP doesn't use a named argument that is used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP doesn't use a named argument that is used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. .sp Note that in some languages, the commonly used Plural\-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; \&... msgid "one byte" msgid_plural "%(n)d bytes" msgstr[0] "%(n)d bajt" msgstr[1] "%(n)d bajta" msgstr[2] "%(n)d bajtova" .ft P .fi .UNINDENT .UNINDENT .sp Here \fB%d\fP should not be replaced with the spelled\-out form \fBjedan\fP\&. Either \fB%d\fP should be kept, or the Plural\-Forms expression should be amended, so that there is a special case for n=1: .INDENT 0.0 .INDENT 3.5 .sp .nf .ft C Plural\-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 \&... msgid "one byte" msgid_plural "%(n)d bytes" msgstr[0] "%(n)d bajt" msgstr[1] "%(n)d bajta" msgstr[2] "%(n)d bajtova" msgstr[3] "jedan bajt" .ft P .fi .UNINDENT .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Translating\-plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-multiple\-unnamed\-arguments .sp A Python format string uses multiple unnamed arguments (such as \fB%d\fP). The translator might need to reorder the arguments to properly translate the message, but this is not possible with unnamed arguments. Named arguments (such as \fB%(num)d\fP) should be used instead. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-obsolete\-conversion .sp A Python format string uses an obsolete conversion specifier: .INDENT 0.0 .IP \(bu 2 Use \fB%d\fP instead of \fB%u\fP\&. .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS python\-format\-string\-redundant\-flag .sp A Python format string includes a redundant character flag. Either it's a duplicate, or it has no effect: .INDENT 0.0 .IP \(bu 2 The \fB+\fP flag overrides the \fIspace\fP flag. .IP \(bu 2 The \fB\-\fP flag overrides the \fB0\fP flag. .IP \(bu 2 If a precision is given, the \fB0\fP flag has no effect on integer conversions (\fB%d\fP, \fB%i\fP, \fB%o\fP, \fB%u\fP, \fB%x\fP, and \fB%X\fP). .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS python\-format\-string\-redundant\-length .sp A Python format string includes a redundant length modifier. Length modifiers (\fBh\fP, \fBl\fP, or \fBL\fP) have no effect in Python. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS python\-format\-string\-redundant\-precision .sp A C format string includes precision that has no effect on the conversion. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, possible .UNINDENT .UNINDENT .SS python\-format\-string\-unknown\-argument .sp A Python format string for \fBmsgid\fP uses a named argument that isn't used in \fBmsgid_plural\fP; or \fBmsgstr\fP uses a named argument that isn't used in \fBmsgid\fP; or \fBmsgstr[\fP\fIN\fP\fB]\fP uses a named argument that isn't used in corresponding \fBmsgid\fP or \fBmsgid_plural\fP\&. This indicates that the conversion would try to consume an argument that weren't supplied. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS python\-format\-string\-unnamed\-plural\-argument .sp A Python format string uses an unnamed arguments (such as \fB%d\fP) in the context of plural forms. The translator might want not to use the numeric argument in the singular form; but this is not possible if the argument is unnamed, because python, unlike C, requires that all unnamed arguments are consumed during conversion. Named arguments (such as \fB%(n)d\fP) should be used instead. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://docs.python.org/2/library/stdtypes.html#string\-formatting\-operations\fP \fI\%https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 wishlist, possible .UNINDENT .UNINDENT .SS qt\-plural\-format\-mistaken\-for\-c\-format .sp A \fBc\-format\fP flag is associated with the message, but \fBqt\-plural\-format\fP should be used instead. .sp The only C format directive that the message uses is \fB%n\fP\&. It is very atypical to use it alone in a C format string. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%http://doc.qt.io/qt\-5/i18n\-source\-translation.html#handling\-plurals\fP \fBprintf\fP(3) .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS range\-flag\-without\-plural\-string .sp A \fBrange:\fP flag is associated with a message that doesn't have plural string. \fBrange:\fP flags only make sense for translations involving plural forms. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, certain .UNINDENT .UNINDENT .SS redundant\-message\-flag .sp A flag associated with one of the messages is redundant, because it's implied by another flag. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 pedantic, certain .UNINDENT .UNINDENT .SS stray\-header\-line .sp The header contains a line that does not belong to any header field. Note that RFC\-822\-style folding of long headers is not supported. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://lists.gnu.org/archive/html/bug\-gettext/2012\-12/msg00010.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS stray\-previous\-msgid .sp The message entry contains annotations about previous untranslated string (\fB#| msgid\fP\ \fI\&...\fP), even though the message is not marked as fuzzy. These annotations are only useful for fuzzy messages, and should be removed when unfuzzying. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, certain .UNINDENT .UNINDENT .SS syntax\-error\-in\-plural\-forms .sp Value of the Plural\-Forms header field could not be parsed. It should be in the form \fBnplurals=\fP\fIn\fP\fB; plural=\fP\fIexpression\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, certain .UNINDENT .UNINDENT .SS syntax\-error\-in\-po\-file .sp This file couldn't be parsed a PO file. In some rare cases this is due to incorrect or missing encoding declaration. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP \fI\%https://bugs.debian.org/692283\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS syntax\-error\-in\-unused\-plural\-forms .sp Value of the Plural\-Forms header field could not be parsed. (But there are no translated messages which use plural forms.) It should be in the form \fBnplurals=\fP\fIn\fP\fB; plural=\fP\fIexpression\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/Plural\-forms.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS trailing\-junk\-in\-plural\-forms .sp The Plural\-Forms header field contains unexpected text after the plural expression. .sp GNU gettext runtime ignores such trailing junk, but other header parsers might be less liberal in what they accept. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .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. Absence of this information will prevent it from performing further checks. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, wild\-guess .UNINDENT .UNINDENT .SS unexpected\-flag\-for\-header\-entry .sp An unexpected flag is associated with the header entry. The only flag that makes sense for the header entry is \fBfuzzy\fP\&. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SS unknown\-encoding .sp This file declares an encoding that couldn't be recognized by i18nspector. It might be a typo. Absence of encoding information will prevent i18nspector from performing further checks. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS unknown\-file\-type .sp File format of this file couldn't be recognized. It might be a bug in i18nspector. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, wild\-guess .UNINDENT .UNINDENT .SS unknown\-header\-field .sp The header field name is unknown to i18nspector. It might be a typo or a capitalization error (header field names are case\-sensitive). .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://lists.gnu.org/archive/html/bug\-gettext/2012\-12/msg00010.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, wild\-guess .UNINDENT .UNINDENT .SS unknown\-message\-flag .sp An unknown flag is associated with one of the messages. It might be a typo. .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%https://www.gnu.org/software/gettext/manual/html_node/PO\-Files.html\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, wild\-guess .UNINDENT .UNINDENT .SS unknown\-poedit\-language .sp Language declared in X\-Poedit\-Language couldn't be recognized. It might be a bug in i18nspector. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 minor, wild\-guess .UNINDENT .UNINDENT .SS unrepresentable\-characters .sp The declared encoding cannot represent all characters commonly used in this language. This is a strong indication that the declared encoding is incorrect. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS unusual\-character\-in\-header\-entry .sp The header entry contains an unusual character. This is usually an indication of an encoding problem, such as: .INDENT 0.0 .IP \(bu 2 using ISO 2022 escape sequences, or .IP \(bu 2 using UTF\-8 despite declaring an 8\-bit encoding. .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%http://www.unicode.org/faq/utf_bom.html#bom6\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, certain .UNINDENT .UNINDENT .SS unusual\-character\-in\-translation .sp One of the translated messages contains an unusual character. This is usually an indication of an encoding problem, such as: .INDENT 0.0 .IP \(bu 2 using ISO 2022 escape sequences, or .IP \(bu 2 using UTF\-8 despite declaring an 8\-bit encoding. .UNINDENT .sp References: .INDENT 0.0 .INDENT 3.5 .nf \fI\%http://www.unicode.org/faq/utf_bom.html#bom6\fP .fi .sp .UNINDENT .UNINDENT .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 important, possible .UNINDENT .UNINDENT .SS unusual\-plural\-forms .sp The Plural\-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 serious, possible .UNINDENT .UNINDENT .SS unusual\-unused\-plural\-forms .sp The Plural\-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. (But there are no translated messages which use plural forms.) .sp Severity, certainty: .INDENT 0.0 .INDENT 3.5 normal, possible .UNINDENT .UNINDENT .SH SEE ALSO .sp \fBmsgfmt\fP(1), particularly the \fB\-c\fP option . .\" Generated by docutils manpage writer. . i18nspector-0.25.5/doc/tags.txt0000644000000000000000000011520713147102074014421 0ustar0000000000000000.. This file has been generated automatically by private/tags-as-rst. Do not edit. ancient-date ~~~~~~~~~~~~ The date refers to the time before the first GNU gettext release. As such, it's extremely unlikely to be correct. References: | http://git.savannah.gnu.org/cgit/gettext.git/tree/ChangeLog.0#n1767 Severity, certainty: normal, certain arithmetic-error-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Computing a plural form value triggers division by zero or integer overflow. This normally indicates an error in the plural form expression. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible arithmetic-error-in-unused-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Computing a plural form value triggers division by zero or integer overflow. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: normal, possible boilerplate-in-content-type ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Content-Type header field contains xgettext boilerplate. It should be in the form ``text/plain; charset=``\ *encoding*. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files Severity, certainty: important, certain boilerplate-in-date ~~~~~~~~~~~~~~~~~~~ The date header field contains xgettext boilerplate. The date format should be ``YYYY-MM-DD hh:mm+ZZzz``, e.g. ``2011-11-05 10:14+0100``. Severity, certainty: normal, certain boilerplate-in-initial-comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The initial comments contain xgettext or msginit boilerplate. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, possible boilerplate-in-language-team ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Language-Team header field contains xgettext boilerplate. It should contain English name of the language, and the email address or homepage URL of the language team. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain boilerplate-in-last-translator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Last-Translator header field contains xgettext boilerplate. It should contain the last translator's name and email address. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain boilerplate-in-project-id-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Project-Id-Version header field contains xgettext boilerplate. It should contain the name and the version of the package. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain boilerplate-in-report-msgid-bugs-to ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Report-Msgid-Bugs-To header field contains xgettext boilerplate. It should contain an email address or URL where one can report bugs in the untranslated strings. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain broken-encoding ~~~~~~~~~~~~~~~ Header fields and messages contained by this file couldn't be decoded to Unicode. The usual cause of this is incorrect or missing encoding declaration. Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files | https://tools.ietf.org/html/rfc2045#section-5 Severity, certainty: serious, possible c-format-string-argument-type-mismatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There's a type mismatch between a C format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a C format argument in ``msgstr`` and ``msgid``; or between a C format argument in ``msgstr[``\ *N*\ ``]`` and corresponding ``msgid`` or ``msgid_plural``. References: | **printf**\ (3) | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible c-format-string-error ~~~~~~~~~~~~~~~~~~~~~ A C format string could not be parsed. References: | **printf**\ (3) Severity, certainty: serious, possible c-format-string-excess-arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string for ``msgid`` consumes more arguments than ``msgid_plural``; or ``msgstr`` consumes more arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes more arguments than corresponding ``msgid`` or ``msgid_plural``. References: | **printf**\ (3) | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible c-format-string-missing-arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string for ``msgid`` consumes fewer arguments than ``msgid_plural``; or ``msgstr`` consumes fewer arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes fewer arguments than corresponding ``msgid`` or ``msgid_plural``. Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; ... msgid "one byte" msgid_plural "%d bytes" msgstr[0] "%d bajt" msgstr[1] "%d bajta" msgstr[2] "%d bajtova" Here ``%d`` should not be replaced with the spelled-out form ``jedan``. Either ``%d`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 ... msgid "one byte" msgid_plural "%d bytes" msgstr[0] "%d bajt" msgstr[1] "%d bajta" msgstr[2] "%d bajtova" msgstr[3] "jedan bajt" References: | **printf**\ (3) | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, possible c-format-string-non-portable-conversion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string uses a conversion specified or length modifier, for which a more portable replacement exists: * For integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``), use the ``ll`` length modifier instead of ``L`` or ``q``. * For floating-point conversions (``%a``, ``%A``, ``%e``, ``%E``, ``%f``, ``%F``, ``%g``, and ``%G``), don't use the ``l`` length modifier. * Use the ``z`` length modifier instead of ``Z``. * Use ``%lc`` instead of ``%C``. * Use ``%ls`` instead of ``%S``. References: | **printf**\ (3) Severity, certainty: pedantic, possible c-format-string-redundant-flag ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string includes a redundant character flag. Either it's a duplicate, or it has no effect: * The ``+`` flag overrides the *space* flag. * The ``-`` flag overrides the ``0`` flag. * If a precision is given, the ``0`` flag has no effect on integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``). References: | **printf**\ (3) Severity, certainty: pedantic, possible codomain-error-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Either a plural form value is outside the declared range, or some values within the declared range can never be reached. This normally indicates an error in the plural form expression. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, certain codomain-error-in-unused-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Either a plural form value is outside the declared range, or some values within the declared range can never be reached. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: normal, certain conflict-marker-in-header-entry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The header contains a conflict marker (``#-#-#-#-#`` *…* ``#-#-#-#-#``). The conflict will have to be resolved manually. References: | https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia Severity, certainty: serious, certain conflict-marker-in-translation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ One of the translated messages appear to contain a conflict marker (``#-#-#-#-#`` *…* ``#-#-#-#-#``). The conflict will have to be resolved manually. References: | https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia Severity, certainty: serious, possible conflicting-message-flags ~~~~~~~~~~~~~~~~~~~~~~~~~ Two flags with conflicting meanings are associated with one of the messages. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: important, possible date-from-future ~~~~~~~~~~~~~~~~ The date refers to the future. As such, it's extremely unlikely to be correct. Severity, certainty: normal, certain distant-header-entry ~~~~~~~~~~~~~~~~~~~~ The header entry in this file is preceded by other entries. The header entry should be always the first one. Severity, certainty: important, certain duplicate-flag-for-header-entry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Multiple identical flags are associated with the header entry. Severity, certainty: minor, certain duplicate-header-entry ~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple header entries. Severity, certainty: serious, certain duplicate-header-field ~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple header fields of the same name. Severity, certainty: minor, wild-guess duplicate-header-field-content-transfer-encoding ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Content-Transfer-Encoding header fields. Severity, certainty: pedantic, certain duplicate-header-field-content-type ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Content-Type header fields. Severity, certainty: serious, certain duplicate-header-field-date ~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple date header fields of the same name. Severity, certainty: normal, certain duplicate-header-field-language ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Language header fields. Severity, certainty: important, certain duplicate-header-field-language-team ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Language-Team header fields. Severity, certainty: normal, certain duplicate-header-field-last-translator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Last-Translator header fields. Severity, certainty: normal, certain duplicate-header-field-mime-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple MIME-Version header fields. Severity, certainty: pedantic, certain duplicate-header-field-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Plural-Forms header fields. Severity, certainty: serious, certain duplicate-header-field-project-id-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Project-Id-Version header fields. Severity, certainty: minor, certain duplicate-header-field-report-msgid-bugs-to ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple Report-Msgid-Bugs-To header fields. Severity, certainty: normal, certain duplicate-header-field-x-poedit ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple X-Poedit-*\** header fields. Severity, certainty: normal, certain duplicate-message-definition ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file contains multiple definitions of the same message. Severity, certainty: serious, certain duplicate-message-flag ~~~~~~~~~~~~~~~~~~~~~~ Multiple identical flags are associated with one of the messages. Severity, certainty: minor, certain empty-file ~~~~~~~~~~ This file doesn't contain any messages. Severity, certainty: normal, certain empty-msgid-message-with-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call ``ngettext("", …)``. Severity, certainty: serious, certain empty-msgid-message-with-source-code-references ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call ``gettext("")``. Severity, certainty: serious, possible encoding-in-language-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The language header field contains encoding declaration. Such information shouldn't be included in this field. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain fuzzy-header-entry ~~~~~~~~~~~~~~~~~~ The header entry is marked as fuzzy. For compatibility with very old (<< 0.11) **msgfmt**\ (1) versions, which didn't support fuzzy header entries, it shouldn't be marked as such. References: | http://git.savannah.gnu.org/cgit/gettext.git/tree/NEWS?id=v0.11#n44 Severity, certainty: pedantic, certain inconsistent-leading-newlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some strings in an entry start with a newline, but some don't. Either all of them should start with a newline, or none of them should. Severity, certainty: important, possible inconsistent-number-of-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Number of plural forms in a message definition doesn't match number of plural forms declared in another message definition. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, certain inconsistent-trailing-newlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some strings in an entry end with a newline, but some don't. Either all of them should end with a newline, or none of them should. Severity, certainty: important, possible incorrect-number-of-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Number of plural forms in a message definition doesn't match number of plural forms declared in the header. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, certain invalid-content-transfer-encoding ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Value of the Content-Transfer-Encoding header field is invalid. It should be ``8bit``. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html | https://tools.ietf.org/html/rfc2045#section-6.1 Severity, certainty: pedantic, certain invalid-content-type ~~~~~~~~~~~~~~~~~~~~ Value of the Content-Type header field should is invalid. It should be in the form ``text/plain; charset=``\ *encoding*. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files | https://tools.ietf.org/html/rfc2045#section-5 Severity, certainty: important, possible invalid-date ~~~~~~~~~~~~ The date is invalid or in an invalid format. The format should be ``YYYY-MM-DD hh:mm+ZZzz``, e.g. ``2011-11-05 10:14+0100``. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain invalid-language ~~~~~~~~~~~~~~~~ The Language header field couldn't be parsed, or it contains an unknown language. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: important, possible invalid-language-team ~~~~~~~~~~~~~~~~~~~~~ The Language-Team header field contains an e-mail address that uses a reserved domain name, or a partially qualified domain name. References: | https://tools.ietf.org/html/rfc2606 Severity, certainty: normal, possible invalid-last-translator ~~~~~~~~~~~~~~~~~~~~~~~ The Last-Translator header field could neither be parsed as an e-mail, or the e-mail address uses a reserved domain name, or a partially qualified domain name. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html | https://tools.ietf.org/html/rfc2606 Severity, certainty: normal, possible invalid-mime-version ~~~~~~~~~~~~~~~~~~~~ Value of the MIME-Version header field is invalid. It should be ``1.0``. References: | https://tools.ietf.org/html/rfc2045#section-4 Severity, certainty: pedantic, certain invalid-mo-file ~~~~~~~~~~~~~~~ This file couldn't be parsed a MO file. Severity, certainty: serious, certain invalid-range-flag ~~~~~~~~~~~~~~~~~~ A ``range:`` flag couldn't be parsed, or the designated range contained fewer than two numbers. The syntax is ``range:``\ *min*\ ``..``\ *max*, where both values are non-negative integers. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: important, certain invalid-report-msgid-bugs-to ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Report-Msgid-Bugs-To header field could neither be parsed as an e-mail nor as a URL, or the e-mail address uses a reserved domain name, or a partially qualified domain name. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html | https://tools.ietf.org/html/rfc2606 Severity, certainty: normal, possible language-disparity ~~~~~~~~~~~~~~~~~~ Language of this file has been declared in multiple places, but the declarations don't match. Severity, certainty: normal, possible language-team-equal-to-last-translator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Language-Team and Last-Translator header fields contain the same e-mail address. Severity, certainty: minor, possible language-variant-does-not-affect-translation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Language header field contains a variant designator that is not relevant for the message translation. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, possible leading-junk-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms header field contains unexpected text before the ``nplurals=`` string. GNU gettext runtime ignores such leading junk, but other header parsers might be less liberal in what they accept. Severity, certainty: important, certain malformed-xml ~~~~~~~~~~~~~ The original string or the translated string contains an XML fragment, which is not well-formed. References: | https://www.w3.org/TR/REC-xml/#sec-well-formed Severity, certainty: serious, possible no-content-transfer-encoding-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Content-Transfer-Encoding header field doesn't exist. It should be set to ``8bit``. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html | https://tools.ietf.org/html/rfc2045#section-6.1 Severity, certainty: pedantic, certain no-content-type-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Content-Type header field doesn't exist. It should be set to ``text/plain; charset=``\ *encoding*. Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files | https://tools.ietf.org/html/rfc2045#section-5 Severity, certainty: important, certain no-date-header-field ~~~~~~~~~~~~~~~~~~~~ The date header field doesn't exist. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain no-language-header-field ~~~~~~~~~~~~~~~~~~~~~~~~ The Language header field doesn't exist. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: pedantic, certain no-language-team-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Language-Team header field does not exist. It should contain English name of the language, and the email address or homepage URL of the language team. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: pedantic, certain no-last-translator-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Last-Translator header field doesn't exist. It should contain the last translator's name and email address. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain no-mime-version-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The MIME-Version header field doesn't exist. It should be to set to ``1.0``. References: | https://tools.ietf.org/html/rfc2045#section-4 Severity, certainty: pedantic, certain no-package-name-in-project-id-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Project-Id-Version header field doesn't appear to contain any name. It should contain both the name and the version of the package. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, possible no-plural-forms-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms header field does not exist, even though some of the messages use plural forms (although none of them have been translated). References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: minor, certain no-project-id-version-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Project-Id-Version header field does not exist. It should contain the name and the version of the package. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: minor, certain no-report-msgid-bugs-to-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Report-Msgid-Bugs-To header field does not exist or it is empty. It should contain an email address or URL where one can report bugs in the untranslated strings. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: normal, certain no-required-plural-forms-header-field ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms header field does not exist, even though some of the translated messages use plural forms. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, certain no-version-in-project-id-version ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Project-Id-Version header field doesn't appear to contain any version. It should contain both the name and the version of the package. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html Severity, certainty: pedantic, possible non-ascii-compatible-encoding ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file uses an encoding that is not compatible with ASCII. Severity, certainty: serious, certain non-portable-encoding ~~~~~~~~~~~~~~~~~~~~~ This file uses an encoding that is not widely supported by software. References: | https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-list Severity, certainty: important, certain os-error ~~~~~~~~ An input/output error or another operating system error occurred while checking this file. Severity, certainty: serious, certain partially-translated-message ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Translation is missing for some plural forms of a message. Severity, certainty: serious, possible python-brace-format-string-argument-type-mismatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There's a type mismatch between a Python format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a Python format argument in ``msgstr`` and ``msgid``; or between a Python format argument in ``msgstr[``\ *N*\ ``]`` and ``msgid`` or ``msgid_plural``. References: | https://docs.python.org/2/library/string.html#formatstrings Severity, certainty: serious, possible python-brace-format-string-error ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string could not be parsed. References: | https://docs.python.org/2/library/string.html#formatstrings Severity, certainty: serious, possible python-brace-format-string-missing-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; ... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" Here ``{n}`` should not be replaced with the spelled-out form ``jedan``. Either ``{n}`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 ... msgid "one byte" msgid_plural "{n} bytes" msgstr[0] "{n} bajt" msgstr[1] "{n} bajta" msgstr[2] "{n} bajtova" msgstr[3] "jedan bajt" References: | https://docs.python.org/2/library/string.html#formatstrings | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, possible python-brace-format-string-unknown-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. References: | https://docs.python.org/2/library/string.html#formatstrings | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible python-format-string-argument-number-mismatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` consumes more arguments than ``msgid_plural``; or ``msgstr`` consumes more arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes more arguments than ``msgid`` or ``msgid_plural``. Python, unlike C, requires that all unnamed arguments are consumed during conversion. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python Severity, certainty: serious, possible python-format-string-argument-type-mismatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There's a type mismatch between a Python format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a Python format argument in ``msgstr`` and ``msgid``; or between a Python format argument in ``msgstr[``\ *N*\ ``]`` and ``msgid`` or ``msgid_plural``. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: serious, possible python-format-string-error ~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string could not be parsed. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: serious, possible python-format-string-missing-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; ... msgid "one byte" msgid_plural "%(n)d bytes" msgstr[0] "%(n)d bajt" msgstr[1] "%(n)d bajta" msgstr[2] "%(n)d bajtova" Here ``%d`` should not be replaced with the spelled-out form ``jedan``. Either ``%d`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 ... msgid "one byte" msgid_plural "%(n)d bytes" msgstr[0] "%(n)d bajt" msgstr[1] "%(n)d bajta" msgstr[2] "%(n)d bajtova" msgstr[3] "jedan bajt" References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html Severity, certainty: serious, possible python-format-string-multiple-unnamed-arguments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string uses multiple unnamed arguments (such as ``%d``). The translator might need to reorder the arguments to properly translate the message, but this is not possible with unnamed arguments. Named arguments (such as ``%(num)d``) should be used instead. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python Severity, certainty: serious, possible python-format-string-obsolete-conversion ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string uses an obsolete conversion specifier: * Use ``%d`` instead of ``%u``. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: pedantic, possible python-format-string-redundant-flag ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string includes a redundant character flag. Either it's a duplicate, or it has no effect: * The ``+`` flag overrides the *space* flag. * The ``-`` flag overrides the ``0`` flag. * If a precision is given, the ``0`` flag has no effect on integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``). References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: pedantic, possible python-format-string-redundant-length ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string includes a redundant length modifier. Length modifiers (``h``, ``l``, or ``L``) have no effect in Python. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: pedantic, possible python-format-string-redundant-precision ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A C format string includes precision that has no effect on the conversion. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations Severity, certainty: pedantic, possible python-format-string-unknown-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, possible python-format-string-unnamed-plural-argument ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Python format string uses an unnamed arguments (such as ``%d``) in the context of plural forms. The translator might want not to use the numeric argument in the singular form; but this is not possible if the argument is unnamed, because python, unlike C, requires that all unnamed arguments are consumed during conversion. Named arguments (such as ``%(n)d``) should be used instead. References: | https://docs.python.org/2/library/stdtypes.html#string-formatting-operations | https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python Severity, certainty: wishlist, possible qt-plural-format-mistaken-for-c-format ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A ``c-format`` flag is associated with the message, but ``qt-plural-format`` should be used instead. The only C format directive that the message uses is ``%n``. It is very atypical to use it alone in a C format string. References: | http://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals | **printf**\ (3) Severity, certainty: important, possible range-flag-without-plural-string ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A ``range:`` flag is associated with a message that doesn't have plural string. ``range:`` flags only make sense for translations involving plural forms. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: normal, certain redundant-message-flag ~~~~~~~~~~~~~~~~~~~~~~ A flag associated with one of the messages is redundant, because it's implied by another flag. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: pedantic, certain stray-header-line ~~~~~~~~~~~~~~~~~ The header contains a line that does not belong to any header field. Note that RFC-822-style folding of long headers is not supported. References: | https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00010.html Severity, certainty: important, certain stray-previous-msgid ~~~~~~~~~~~~~~~~~~~~ The message entry contains annotations about previous untranslated string (``#| msgid``\ *...*), even though the message is not marked as fuzzy. These annotations are only useful for fuzzy messages, and should be removed when unfuzzying. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: minor, certain syntax-error-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Value of the Plural-Forms header field could not be parsed. It should be in the form ``nplurals=``\ *n*\ ``; plural=``\ *expression*. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: serious, certain syntax-error-in-po-file ~~~~~~~~~~~~~~~~~~~~~~~ This file couldn't be parsed a PO file. In some rare cases this is due to incorrect or missing encoding declaration. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html | https://bugs.debian.org/692283 Severity, certainty: serious, possible syntax-error-in-unused-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Value of the Plural-Forms header field could not be parsed. (But there are no translated messages which use plural forms.) It should be in the form ``nplurals=``\ *n*\ ``; plural=``\ *expression*. References: | https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html Severity, certainty: important, certain trailing-junk-in-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms header field contains unexpected text after the plural expression. GNU gettext runtime ignores such trailing junk, but other header parsers might be less liberal in what they accept. Severity, certainty: important, certain 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. Absence of this information will prevent it from performing further checks. Severity, certainty: normal, wild-guess unexpected-flag-for-header-entry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ An unexpected flag is associated with the header entry. The only flag that makes sense for the header entry is ``fuzzy``. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: normal, possible unknown-encoding ~~~~~~~~~~~~~~~~ This file declares an encoding that couldn't be recognized by i18nspector. It might be a typo. Absence of encoding information will prevent i18nspector from performing further checks. Severity, certainty: important, possible unknown-file-type ~~~~~~~~~~~~~~~~~ File format of this file couldn't be recognized. It might be a bug in i18nspector. Severity, certainty: normal, wild-guess unknown-header-field ~~~~~~~~~~~~~~~~~~~~ The header field name is unknown to i18nspector. It might be a typo or a capitalization error (header field names are case-sensitive). References: | https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00010.html Severity, certainty: minor, wild-guess unknown-message-flag ~~~~~~~~~~~~~~~~~~~~ An unknown flag is associated with one of the messages. It might be a typo. References: | https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html Severity, certainty: normal, wild-guess unknown-poedit-language ~~~~~~~~~~~~~~~~~~~~~~~ Language declared in X-Poedit-Language couldn't be recognized. It might be a bug in i18nspector. Severity, certainty: minor, wild-guess unrepresentable-characters ~~~~~~~~~~~~~~~~~~~~~~~~~~ The declared encoding cannot represent all characters commonly used in this language. This is a strong indication that the declared encoding is incorrect. Severity, certainty: serious, possible unusual-character-in-header-entry ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The header entry contains an unusual character. This is usually an indication of an encoding problem, such as: * using ISO 2022 escape sequences, or * using UTF-8 despite declaring an 8-bit encoding. References: | http://www.unicode.org/faq/utf_bom.html#bom6 Severity, certainty: important, certain unusual-character-in-translation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ One of the translated messages contains an unusual character. This is usually an indication of an encoding problem, such as: * using ISO 2022 escape sequences, or * using UTF-8 despite declaring an 8-bit encoding. References: | http://www.unicode.org/faq/utf_bom.html#bom6 Severity, certainty: important, possible unusual-plural-forms ~~~~~~~~~~~~~~~~~~~~ The Plural-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. Severity, certainty: serious, possible unusual-unused-plural-forms ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Plural-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. (But there are no translated messages which use plural forms.) Severity, certainty: normal, possible i18nspector-0.25.5/doc/LICENSE0000644000000000000000000000207413147102065013724 0ustar0000000000000000Copyright © 2012-2017 Jakub Wilk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. i18nspector-0.25.5/doc/todo0000644000000000000000000001510013147102065013601 0ustar0000000000000000Add more ``Plural-Forms``. Document how the current ``Plural-Forms`` were obtained. * http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html?id=l10n/pluralforms * http://unicode.org/cldr/trac/browser/trunk/common/supplemental/plurals.xml Complain about incorrect locale codes: * https://www.loc.gov/standards/iso639-2/php/code_changes.php * ``al`` → ``sq`` * ``bh`` → ``bho`` | ``mai`` | ``mag`` * ``ca-XV`` → ``ca@valencia`` * ``cn`` → ``zh`` * ``cz`` → ``cs`` * ``dk`` → ``da`` * ``en_UK`` → ``en_GB`` * ``gr`` → ``el`` * ``in`` → ``id`` * ``iw`` → ``he`` * ``ji`` → ``yi`` * ``jw`` → ``jv`` * ``mo`` → ``ro_MD`` * ``no`` → ``nb`` * ``sh_BA`` → ``bs_BA`` * ``sh_HR`` → ``hr_HR`` * ``sh_RS`` → ``sr_RS`` * ``sr@Latn`` → ``sr@latin`` * ``sr_CS`` → ``sr`` * ``sr_SR`` → ``sr_RS`` * ``sr_YU`` → ``sr`` * ``uk_UK`` → ``uk_UA`` * ``vn`` → ``vi`` Correct locale codes in invalid format, e.g.: * ``da-DK`` → ``da_DK``: https://anonscm.debian.org/cgit/debian-handbook/debian-handbook.git/tree/da-DK/00a_preface.po?h=debian/8.20151209 * ``pt_br`` → ``pt_BR``: https://sources.debian.net/data/main/p/pam-pkcs11/0.6.8-1/po/pt_br.po * ``Pt`` → ``pt``: https://sources.debian.net/data/main/d/darcsweb/1.1-3.1/debian/po/pt.po Correct ``Language`` with both a natural language and a language code, e.g.: * ``nl (Dutch)``: https://sources.debian.net/data/main/g/garcon/0.1.12-1/po/nl.po * ``Serbian (sr)``: https://sources.debian.net/data/main/a/at-spi2-atk/2.5.3-2/po/sr.po Guess language from ``Language-Team``. * https://translationproject.org/team/ Guess language from the filename even when it includes encoding. Test-cases: * https://sources.debian.net/src/vim/2:7.3.547-7/src/po/ Add ``characters=``\ … for more languages. Document how the current values were obtained. Fix support for ``X-Poedit-Language: (Afan) Oromo``. Fix support for ``X-Poedit-Language: Serbian (Latin)``. Document the security model. Add tests for: * Debian source packages * Debian binary packages * MO files (at least against some tags) * languages with multiple correct ``Plural-Forms`` * lib.moparser * all non-Python encodings * 0x5c byte as a part of a multibyte character: https://sources.debian.net/src/vim/2:7.3.547-7/src/po/zh_TW.po/#L13 * SHIFT_JIS encoding: http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/po-lex.c?id=v0.18.3#n179 Detect question marks in unusual places. Add support for configuration files. Once it's implemented: * Disable ``--pedantic`` by default. Add support for profiles: severity of a tag may depend on whether you are upstream, a translator, or a user. Add support for overrides. Add option for disabling/forcing colored output. Use `blessings `_ for colored output. Reimplement the EUC-TW codec with PyICU. Check for hardcoded Language in POT files. Add option for printing tag descriptions. When emitting ``encoding-in-language-header-field``, check if the encoding matches the one from ``Content-Type``. Test-cases: * https://sources.debian.net/data/main/r/rhn-client-tools/1.8.9-3/po/zh_CN.GB2312.po Split ``no-email-address-in-last-translator`` from ``invalid-last-translator``. Test-cases: * https://sources.debian.net/data/main/m/mtpaint/3.40-1/po/de.po * https://sources.debian.net/data/main/y/yaboot-installer/1.1.26/debian/po/hi.po Split ``missing-timezone-in-date`` from ``invalid-date``. Check for non-ASCII (translated?) project id. Test-case: * https://sources.debian.net/data/main/a/alarm-clock/1.2.5-1.2/po/sr.po Check for localized boilerplate in headers. Decide what to do with commas in ``Last-Translator``: either accept them, or provide a better error message. Test-case: * https://sources.debian.net/data/main/i/installation-guide/20130503/po/zh_TW/using-d-i.po polib PO encoding detection is not robust enough. Test-case: ``xfail-header-imitation.po`` Add support for system-dependent messages (minor revision 1). Check for PO files that are not encoding-aware: * https://marc.info/?l=openbsd-ports&m=98988950322667&w=2 Add support for MediaWiki Translate's ``invalid-plural`` flag. Test-case: * https://sources.debian.net/data/main/e/evolution/3.4.4-3/po/fi.po Add support for pygettext's ``docstring`` flag. Check .desktop files: * https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s04.html Check Shared Mime Info files: * https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html Figure out what to do with software that call ``gettext("")`` intentionally. Test-case: * https://sources.debian.net/src/evolution/3.4.4-3/shell/main.c/#L579 Check for ``msgstr_plural`` without ``msgstr[N]``, and other way round. Verify that if *n* = plural(1) = plural(*i*) for some *i* > 1, then msgstr[*n*] distinguishes singular and plural forms, even when no numeral is involved. * https://bugs.debian.org/753946#51 Add support for more string formats (in order of popularity on GitHub):: php-format javascript-format perl-format java-format csharp-format kde-format sh-format qt-format tcl-format perl-brace-format scheme-format ycp-format lisp-format awk-format objc-format object-pascal-format librep-format smalltalk-format boost-format qt-plural-format lua-format kde-kuit gfc-internal-format gcc-internal-format elisp-format Improve C format string checks: * Check for the ``I`` C format string flag in msgid. * Recognize type mismatch between ``%*d%d`` and ``%d%*d``. * Make sure ``%%`` is treated as text wrt. omitting integer conversion. SHIFT_JIS and JOHAB encodings are broken in Python; or at least they are not compatible with glibc. Implement a work-around. Test-case:: assert b'\\'.decode('SHIFT_JIS') == '\N{YEN SIGN}' assert b'\\'.decode('JOHAB') == '\N{WON SIGN}' Timezone abbreviations not only are not unique, but also can change their meaning over time. * https://mm.icann.org/pipermail/tz/2014-June/021089.html Check for capitalization inconsistencies. Language codes for some locales supported by glibc aren't recognized:: ayc ber brx cmn hak hne lij lzh mhr nan nhn pap quz shs szl the unm wae yue The tag name ``invalid-language`` might be misleading. Rename or split it. Check for ``li.org`` mailing lists in ``Language-Team``. * https://lists.gnu.org/archive/html/bug-gettext/2016-02/msg00003.html Add support for xgettext message syntax check flags: * http://git.savannah.gnu.org/cgit/gettext.git/commit/?id=d9fc3d2a3f43 .. vim:ft=rst ts=3 sts=3 sw=3 i18nspector-0.25.5/doc/i18nspector.txt0000644000000000000000000000331713147102065015640 0ustar0000000000000000=========== i18nspector =========== ---------------------------------------------- checking tool for gettext POT, PO and MO files ---------------------------------------------- :manual section: 1 :version: i18nspector 0.25.5 :date: |date| Synopsis -------- **i18nspector** [*options*] *file* [*file* …] Description ----------- **i18nspector** is a tool for checking translation templates (POT), message catalogues (PO) and compiled message catalogues (MO) files for common problems. These files are used by the GNU gettext translation functions and tools in many different development environments. Options ------- -l lang, --language lang Assume this language. *lang* should be a 2- or 3-letter ISO 639 language code, possibly followed by underscore and a 2-letter ISO 3166 territory code. --unpack-deb Allow unpacking Debian (binary or source) packages. -j n, --jobs n Use *n* processes in parallel. *n* can be a positive integer, or ``auto`` to determine the number automatically. The default is to use only a single process. -h, --help Show the help message and exit. --version Show the program's version information and exit. Output format ------------- The following format is used for all the reported problems:   *code*\ **:** *file*\ **:** *tag* [*extra*] where: * *code* is a letter indicating type of the message: **E** (error), **W** (warning), **I** (informative message), or **P** (pedantic message); * *tag* is a name of the problem that was discovered; * *extra* can contain additional information about the problem. Tags ---- .. include:: tags.txt .. |date| date:: %Y-%m-%d See also -------- **msgfmt**\ (1), particularly the ``-c`` option .. vim:ft=rst ts=3 sts=3 sw=3 i18nspector-0.25.5/doc/changelog0000644000000000000000000007317413147102065014602 0ustar0000000000000000i18nspector (0.25.5) unstable; urgency=low * Don't complain about POT-Creation-Date missing in MO files. In the future versions of gettext (>> 0.19.8.1), msgfmt will be removing the POT-Creation-Date header. https://savannah.gnu.org/bugs/?49654 * Improve error handling. -- Jakub Wilk Tue, 22 Aug 2017 21:21:13 +0200 i18nspector (0.25.4) unstable; urgency=low * Fix crash when checking Python brace formats string that have both named and numbered arguments. * Reorder sections in the manual page, as per man-pages(7) recommendations. * Put license into a separate file. -- Jakub Wilk Fri, 23 Jun 2017 18:25:35 +0200 i18nspector (0.25.3) unstable; urgency=low * Rewrite shebang at install time. Thanks to Kyrill Detinov for the bug report. https://github.com/jwilk/i18nspector/issues/1 -- Jakub Wilk Mon, 29 Aug 2016 13:25:33 +0200 i18nspector (0.25.2) unstable; urgency=low * Don't disable stdout line buffering. * Make --version print also versions of Python and the libraries. * Make --version print to stdout, not stderr. https://bugs.python.org/issue18920 * Use /usr/bin/env in shebangs. * Fix compatibility with PyPy 3. * Improve documentation about dependencies. * Improve the test suite. -- Jakub Wilk Sun, 21 Aug 2016 21:33:49 +0200 i18nspector (0.25.1) unstable; urgency=low * Fix compatibility with Python 3.6. -- Jakub Wilk Thu, 16 Jun 2016 11:27:08 +0200 i18nspector (0.25) unstable; urgency=low * Rename --parallel as -j/--jobs. * Make it possible to specify “auto” as the number of processes to use. * Remove empty lines between references in the manual page. * Improve the test suite. -- Jakub Wilk Tue, 31 May 2016 17:24:25 +0200 i18nspector (0.24) unstable; urgency=low * Summary of tag changes: + Added: - python-brace-format-string-argument-type-mismatch - python-brace-format-string-error - python-brace-format-string-missing-argument - python-brace-format-string-unknown-argument * Check for errors in Python brace format strings. * Raise certainty of syntax-error-in-plural-forms and syntax-error-in-unused-plural-forms to “certain”. (The main reason the certainty was only “possible” is that the tag was also triggered by leading and trailing junk, for which there are separate tags since 0.23.) * Check for partially qualified domain names in e-mail addresses. * Add option for parallel execution (--parallel). * Improve the test suite. -- Jakub Wilk Wed, 24 Feb 2016 16:46:20 +0100 i18nspector (0.23) unstable; urgency=low * Summary of tag changes: + Added: - leading-junk-in-plural-forms - trailing-junk-in-plural-forms * Make separate tags for leading and trailing junk in Plural-Forms. * Fix typos in tag descriptions. * Use HTTPS for more URLs. -- Jakub Wilk Sat, 06 Feb 2016 15:15:26 +0100 i18nspector (0.22) unstable; urgency=low * Summary of tag changes: + Renamed: - unusual-plural-forms (from incorrect-plural-forms) - unusual-unused-plural-forms (from incorrect-unused-plural-forms) * Fix typo in a tag description. * Fix typo in the help message. * Update QT documentation URLs. * Fix option formatting in the manual page. * Remove redundant parentheses from some exemplary Plural-Forms. * Improve plural forms codomain checks. -- Jakub Wilk Thu, 21 Jan 2016 21:58:52 +0100 i18nspector (0.21) unstable; urgency=low * Summary of tag changes: + Added: - boilerplate-in-initial-comments * Check for xgettext and msginit boilerplate in initial comments. * Improve error handling. * Improve the test suite. -- Jakub Wilk Thu, 19 Nov 2015 19:20:40 +0100 i18nspector (0.20.1) unstable; urgency=low * Set up temporary cache directory in tests/run-tests. -- Jakub Wilk Tue, 15 Sep 2015 17:38:38 +0200 i18nspector (0.20) unstable; urgency=low * Use RPLY for parsing plural expressions. This should make the parser more robust. * Improve the test suite. -- Jakub Wilk Thu, 10 Sep 2015 21:45:40 +0200 i18nspector (0.19) unstable; urgency=low * Summary of tag changes: + Added: - python-format-string-argument-number-mismatch - python-format-string-argument-type-mismatch - python-format-string-error - python-format-string-missing-argument - python-format-string-multiple-unnamed-arguments - python-format-string-obsolete-conversion - python-format-string-redundant-flag - python-format-string-redundant-length - python-format-string-redundant-precision - python-format-string-unknown-argument - python-format-string-unnamed-plural-argument * Check for errors in Python format strings. * Add “kde-kuit” as a known string format. * Verify that polib version is sufficiently new. * Fix language-team-equal-to-last-translator when there are multiple Last-Translator fields. * Improve descriptions of a few tags. * Improve the test suite. -- Jakub Wilk Mon, 06 Jul 2015 20:29:22 +0200 i18nspector (0.18.1) unstable; urgency=low * Make the plural expression parser more robust. * Improve the test suite. -- Jakub Wilk Mon, 02 Mar 2015 12:25:43 +0100 i18nspector (0.18) unstable; urgency=low * Rename --debian as --unpack-deb. Don't make it default even on Debian(-like) systems. * Make the plural expression parser more robust. * Improve the test suite. -- Jakub Wilk Tue, 27 Jan 2015 23:24:53 +0100 i18nspector (0.17.2) unstable; urgency=low * Fix parsing Language header fields containing commas. * Document -h/--help and --version in the manual page. * Improve the test suite. -- Jakub Wilk Wed, 19 Nov 2014 15:11:06 +0100 i18nspector (0.17.1) unstable; urgency=low * Restore compatibility with polib 1.0.3 and earlier versions. Thanks to Kyrill Detinov for the bug report. * Improve the test suite. -- Jakub Wilk Sat, 18 Oct 2014 17:19:17 +0200 i18nspector (0.17) unstable; urgency=low * Summary of tag changes: + Added: - malformed-xml * Check syntax of PO4A XML fragments. * Check for duplicate or conflicting “range” flags. * Tighten the check for invalid “range” flags. * Make URLs for the Content-Type header field documentation more precise. * Improve the test suite. -- Jakub Wilk Fri, 26 Sep 2014 22:25:14 +0200 i18nspector (0.16) unstable; urgency=low * Summary of tag changes: + Added: - c-format-string-missing-arguments - qt-plural-format-mistaken-for-c-format - stray-previous-msgid * Check for C format strings in msgstr/msgstr_plural[N] consuming fewer arguments than corresponding msgid/msgid_plural. Thanks to Guillem Jover for the bug report. https://bugs.debian.org/753946 * Check for previous msgid annotations (“#| msgid …”) attached to non-fuzzy messages. * Check for plural Qt format string mistakenly tagged as C format strings. * Temper checks for conflicting and redundant message flags: + Don't complain about two different format flags applied to the same message when the formats compatible are (to some extent) compatible. + Don't complain when a positive format flag (-format) and a negative format flag (no--format) apply to the same message. The negative format flag might be still a useful hint for the translator. * Never consider non-ASCII characters and control-characters as part of C format string conversion. * Don't complain about unknown header fields starting with lowercase “x-”. * Improve descriptions of a few tags. * Improve the test suite. -- Jakub Wilk Fri, 22 Aug 2014 19:22:47 +0200 i18nspector (0.15) unstable; urgency=low * Summary of tag changes: + Added: - c-format-string-argument-type-mismatch - c-format-string-error - c-format-string-excess-arguments - c-format-string-non-portable-conversion - c-format-string-redundant-flag - partially-translated-message * Check for errors in C format strings. * Check for inconsistent leading/trailing newlines in translations even when encoding is unknown or broken. * Check for conflict markers in translations even when encoding is unknown or broken. * Check for incomplete translations in messages with plural forms. * Fix calculation of current time. * When emitting unusual-character-in-translation, don't output the translated string (which is likely to contain mojibake), but only the message identifier. * Suggest using “-0000” (rather than “+0000”) to indicate that the offset to local time is unknown. This convention is inspired by RFC 3339 §4.3 and RFC 5322 §3.3. * Improve the test suite. -- Jakub Wilk Fri, 08 Aug 2014 23:00:29 +0200 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 unknown or broken. * Check for inconsistent leading/trailing newlines between msgid and msgid_plural even when encoding is unknown or broken. * Improve the test suite. -- Jakub Wilk 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. * Don't complain about conflict markers in fuzzy messages. Thanks to Guillem Jover for the bug report. https://bugs.debian.org/753924 -- Jakub Wilk Mon, 07 Jul 2014 15:01:31 +0200 i18nspector (0.13.4) unstable; urgency=low * Regenerate the timezone information file using tzdata 2014a. * Recognize “8859-n” (without the “ISO-” prefix) as encoding names. * Recognize *.local, *.in-addr.arpa and *.ip6.arpa as special domain names. * Fix compatibility with polib 1.0.4. https://bugs.debian.org/742162 * Improve the test suite. -- Jakub Wilk Thu, 20 Mar 2014 13:54:53 +0100 i18nspector (0.13.3) unstable; urgency=low * Fix incorrect plural expression codomain evaluation. * Fix incorrect precedence of the boolean not operator in plural expressions. * Forbid unary plus and unary minus in plural expressions. * Improve the test suite. -- Jakub Wilk Mon, 20 Jan 2014 20:04:22 +0100 i18nspector (0.13.2) unstable; urgency=low * Reject early encodings that are not compatible with ASCII. https://bugs.python.org/issue19619 * Improve the test suite. -- Jakub Wilk Thu, 02 Jan 2014 13:30:16 +0100 i18nspector (0.13.1) unstable; urgency=low * Fix test failures with Python 3.4. * Fix stripping delay annotations from terminfo capabilities. * Improve the test suite. -- Jakub Wilk Mon, 09 Dec 2013 09:11:05 +0100 i18nspector (0.13) unstable; urgency=low * Summary of tag changes: + Added: - conflicting-message-flags - duplicate-message-flag - invalid-range-flag - range-flag-without-plural-string - redundant-message-flag - unknown-message-flag * Check for duplicate, conflicting, redundant, or unknown message flags. * Strip leading and trailing spaces from flag lines. * Be verbose when checking for messages with empty msgid with source code references. * Reduce duplicate-flag-for-header-entry severity to minor. * Check for zero width no-break space (U+FEFF) in translations and header entries. * Improve the test suite. * Work around a trailing comment parsing bug in polib. https://bitbucket.org/izi/polib/issues/51 -- Jakub Wilk Wed, 11 Sep 2013 14:00:20 +0200 i18nspector (0.12) unstable; urgency=low * Summary of tag changes: + Added: - boilerplate-in-date [ Jakub Wilk ] * Don't emit empty-file for MO files with only system-dependent messages, or with minor revision greater than 1. * Don't emit no-package-name-in-project-id-version if the package name consists of only non-ASCII letters. * Fix parsing some atypical PO comments. * Parse more date formats. * Check for xgettext boilerplate in dates. * Strip trailing whitespace when parsing header entry. * Allow only tabs and spaces between “nplurals=…” and “plural=…”. * Remove Bihari (codes “bh”, “bih”) from the data files; it's not a single language, but a language collection. * Implement 8-bit encodings without iconv(3) or iconv(1). * Add “SEE ALSO” section to the manual page. * Improve the test suite. * Improve the makefile: + Add “clean” target. + Make it possible to use a custom install(1) implementation for “make install”. (This is useful for systems such as FreeBSD which have GNU install available under the name “ginstall”.) + Fix compatibility with find(1) implementations that require a path argument. [ Christopher Meng ] * Makefile: preserve file timestamps. -- Jakub Wilk Fri, 26 Jul 2013 14:18:37 +0200 i18nspector (0.11.1) unstable; urgency=low * Fix the MO file parser: + Detect encoding by inspecting only the first message with empty msgid. + Fix compatibility with Python 3.3. Thanks to Kyrill Detinov for the bug report. * Use the custom MO file encoding detection method rather than the provided by polib. -- Jakub Wilk Mon, 24 Jun 2013 20:28:58 +0200 i18nspector (0.11) unstable; urgency=low * Summary of tag changes: + Added: - distant-header-entry - duplicate-flag-for-header-entry - duplicate-header-entry - duplicate-header-field-x-poedit - empty-msgid-message-with-plural-forms - empty-msgid-message-with-source-code-references - unexpected-flag-for-header-entry - unusual-character-in-header-entry * Fix letter codes for tags with severity important. * Reduce severity of arithmetic-error-in-unused-plural-forms, codomain-error-in-unused-plural-forms, and incorrect-unused-plural-forms to normal. * Implement custom header parser for PO files, and custom MO file parser. (The ones in polib are inadequate for i18nspector's purposes.) * Check for duplicate header entries. * Check for unusually located header entries. * Overhaul handling of duplicates and stray lines in the header entry. + Emit duplicate-header-field-x-poedit (instead of the generic duplicate-header-field) for duplicate X-Poedit-Language and X-Poedit-Country headers fields. * Work around a flag parsing bug in polib. https://bitbucket.org/izi/polib/issues/46 * Check for duplicate and unexpected flags for header entries. * Check for unusual characters in header entries. * Check for messages with empty msgid (header entries?) with source code references or plural forms. * Fix some false-positive language-disparity when PO basename does not designate translation language. * Fix the no-report-msgid-bugs-to-header-field description. * Fix a few typos in the tag descriptions. * Improve the test suite. + Add new tests. + Use a dedicated nose plugin for blackbox tests. -- Jakub Wilk Sun, 23 Jun 2013 22:42:43 +0200 i18nspector (0.10) unstable; urgency=low * Summary of tag changes: + Added: - boilerplate-in-content-type - conflict-marker-in-header-entry - conflict-marker-in-translation - duplicate-header-field-content-transfer-encoding - duplicate-header-field-content-type - duplicate-header-field-date - duplicate-header-field-language - duplicate-header-field-language-team - duplicate-header-field-last-translator - duplicate-header-field-mime-version - duplicate-header-field-plural-forms - duplicate-header-field-project-id-version - duplicate-header-field-report-msgid-bugs-to - fuzzy-header-entry * Check for boilerplate (“charset=CHARSET”) in the Content-Type header field. * Check header field name syntax. * Overhaul duplicate header field detection. + Emit duplicate-header-field only for non-standard fields. Downgrade duplicate-header-field to minor/wild-guess. + Emit duplicate-header-field-$NAME for standard fields. + Don't trust values of standard header fields if duplicates exist. * Check for conflict markers (“#-#-#-#-# … #-#-#-#-#”). * Check for fuzzy header entries. * Fix a typo in the language-team-equal-to-last-translator description. * Post-process the manual page, so that it can be more easily translated by po4a. * If iconv(3) is available in the C standard library, use it to implement encodings that are not implemented in the Python standard library. * Don't pass -s to iconv(1); it makes GNU iconv quieten errors, and other implementations don't have this option at all. * Improve the test suite: + Add new tests. + Make exception messages raised when a subprocess fails more readable. + Make it possible to use a custom Python interpreter for “make test”. -- Jakub Wilk Sat, 15 Jun 2013 17:37:22 +0200 i18nspector (0.9.2) unstable; urgency=low * When emitting broken-encoding, don't output the whole file, but only the undecodable bytes in a small context. -- Jakub Wilk Sat, 08 Jun 2013 11:40:23 +0200 i18nspector (0.9.1) unstable; urgency=low * Brown paper bag release. * Don't complain about leading/trailing newlines in fuzzy messages. Thanks to Guillem Jover for the bug report. https://bugs.debian.org/708586 * Improve the test suite. -- Jakub Wilk Fri, 17 May 2013 15:23:30 +0200 i18nspector (0.9) unstable; urgency=low * Summary of tag changes: + Added: - inconsistent-leading-newlines - inconsistent-trailing-newlines * Check for inconsistent leading/trailing newlines in messages. * Check for unusual characters also in plural translations. * Add information about version and date to the manual page. * Fix stripping delay annotations from terminfo capabilities. -- Jakub Wilk Wed, 15 May 2013 19:37:44 +0200 i18nspector (0.8.3) unstable; urgency=low * Improve the test suite. + Skip some tests when run with (pseudo-)root privileges. Thanks to Stuart Prescott for the bug report. * Add “test” target to Makefile. Thanks to Kyrill Detinov for the bug report. * Recognize “PROJECT VERSION” as boilerplate in the Project-Id-Version header field. -- Jakub Wilk Fri, 03 May 2013 01:23:29 +0200 i18nspector (0.8.2) unstable; urgency=low * Make it possible to declare that a language has more than one correct Plural-Forms. Thanks to Guillem Jover for the bug report. * Add plural forms information for the following languages: Belarusian, Bosnian, Croatian, Hungarian, Russian, Serbian, Turkish, Ukrainian. * Improve the test suite. -- Jakub Wilk Thu, 11 Apr 2013 01:13:24 +0200 i18nspector (0.8.1) unstable; urgency=low * Improve the documentation. + Document the dependencies. Thanks to Kyrill Detinov for the bug report. + Fix a grammar mistake in the unknown-encoding description. + Update description in the “NAME” section of the manual page. + Rename the “USAGE” section of the manual page as “SYNOPSIS”. + Add “DESCRIPTION” section to the manual page. + Document that --debian is enabled on modern Debian(-like) systems. * Remove an incorrect assertion in the plural expression parser. Thanks to Fabio Pirola for the bug report. * Improve the test suite. -- Jakub Wilk Sun, 24 Feb 2013 12:24:46 +0100 i18nspector (0.8) unstable; urgency=low * Summary of tag changes: + Added: - incorrect-plural-forms - incorrect-unused-plural-forms * Add writing system information for the following languages: Burmese, Maori. * Comment out plural forms information for Hungarian and some Slavic languages: Belarusian, Bosnian, Croatian, Russian, Slovak, Serbian and Ukrainian; there is no consensus for the correct plural forms expression for them. * Check for mismatches between Plural-Forms declarations and i18nspector's linguistic data. -- Jakub Wilk Fri, 01 Feb 2013 01:32:42 +0100 i18nspector (0.7.3) unstable; urgency=low * Avoid very long lists of unrepresentable characters; output at most 5 characters at a time. * Output at most 5 items of long integer ranges. * Add writing system information for the following languages: Chinese, English with Shavian alphabet, Japanese, Korean, Malagasy, Pashto, Tagalog, Volapük. * Add plural forms information for the following languages: Frisian, Malagasy, Pashto, Tagalog, Xhosa. * Improve the test suite. -- Jakub Wilk Fri, 25 Jan 2013 01:32:28 +0100 i18nspector (0.7.2) unstable; urgency=low * Add writing system information for the following languages: Assamese, Bengali, Breton, Dzongkha, Esperanto, Galician, Gujarati, Hindi, Kannada, Khmer, Malayalam, Marathi, Nepali, Oriya, Punjabi, Sindhi, Serbian Ijekavian with Latin alphabet, Sinhala, Tajik, Tamil, Telugu, Thai, Urdu, Vietnamese, Walloon. * Update alphabet information for the following languages: Asturian, Spanish. * Add plural forms information for the following languages: Afrikaans: Albanian, Amharic, Assamese, Asturian, Basque, Bengali, Breton, Catalan, Galician, Georgian, Gujarati, Hindi, Indonesian, Interlingua, Kazakh, Khmer, Kinyarwanda, Kurdish Low German, Maithili, Malayalam, Marathi, Mongolian, Nepali, Occitan, Oriya, Persian, Punjabi, Sinhala, Tajik, Tamil, Telugu, Urdu, Uyghur. -- Jakub Wilk Fri, 18 Jan 2013 00:20:50 +0100 i18nspector (0.7.1) unstable; urgency=low * Add writing system information for: - Mongolian; - Semitic languages: Amharic, Arabic, Geez, Hebrew, Tigre, Tigrinya; - Turkic languages: Azerbaijani, Crimean Tatar, Kazakh, Kyrgyz, Tatar, Turkish, Tuvinian, Uyghur, Uzbek; - Uralic languages: Estonian, Finnish, Hungarian, Northern Sami. -- Jakub Wilk Fri, 11 Jan 2013 14:05:44 +0100 i18nspector (0.7) unstable; urgency=low * Summary of tag changes: + Added: - empty-file - invalid-language-team * Check for empty files. * Check for use of RFC 2606 reserved domain names. * Add alphabet information for: - Iranian languages: Kurdish, Ossetic, Persian; - Georgian; - Basque; - Northwest Caucasian languages: Abkhazian, Adyghe. * Handle some malformed MO files more gracefully. * Add a prefix to temporary directory names. * Make it possible to override code/data directory with an environment variable (I18NSPECTOR_BASEDIR). * Produce a useful error message when one tries to run the script with Python < 3.2. * Improve the test suite. -- Jakub Wilk Fri, 04 Jan 2013 18:12:30 +0100 i18nspector (0.6) unstable; urgency=low * Summary of tag changes: + Added: - arithmetic-error-in-plural-forms - arithmetic-error-in-unused-plural-forms - codomain-error-in-plural-forms - codomain-error-in-unused-plural-forms * Perform more checks on Plural-Forms. * Rename the ‘po-header-fields’ data file to ‘header-fields’. * User terminfo for color terminal support, instead of hardcoded EMCA-48 sequences. * Improve the test suite. * Remove some dead code. * Use ast.literal_eval() instead of eval(). -- Jakub Wilk Sun, 16 Dec 2012 21:16:28 +0100 i18nspector (0.5) unstable; urgency=low * Summary of tag changes: + Added: - stray-header-line * If a typo or a capitalization error in a header field name is detected, suggest the correct name. * Check for header lines that do not belong to any header fields. * Refactor the environment patching code. * Optimize PO file decoding. * Improve the test suite. -- Jakub Wilk Fri, 07 Dec 2012 23:08:27 +0100 i18nspector (0.4.1) unstable; urgency=low * Rename the package. -- Jakub Wilk Sun, 02 Dec 2012 16:54:08 +0100 gettext-inspector (0.4) unstable; urgency=low * Summary of tag changes: + Added: - inconsistent-number-of-plural-forms - incorrect-number-of-plural-forms - no-plural-forms-header-field - no-required-plural-forms-header-field - syntax-error-in-unused-plural-forms * Don't unpack control file directories of Debian binary packages; they almost certainly don't contain any interesting files. * Add DEL (U+007F) to the list of control characters. * Change the way message identifiers are formatted in tag output. * Perform more checks on Plural-Forms. * Upgrade syntax-error-in-plural-forms severity to serious. * Don't crash when parsing dates with double space between date and time. * Don't allow whitespace characters other than space and tab in plural expressions. * Don't emit spurious duplicate-header-field tags on multi-line header fields. * Don't complain about issues with obsolete messages. * Don't guess language from PO file name if it appears to contain an encoding declaration, as it's very likely that something else has been confused for the apparent encoding. * Try to propose encoding for invalid-content-type. * Fix untrusted input sanitization. * Work around an escape sequence decoding bug in polib. https://bitbucket.org/izi/polib/issues/31 * Fix typos and formatting errors in the manual page. * Improve the test suite. -- Jakub Wilk Fri, 30 Nov 2012 00:08:29 +0100 gettext-inspector (0.3) unstable; urgency=low * Summary of tag changes: + Added: - duplicate-header-field - duplicate-message-definition - non-ascii-compatible-encoding + Renamed: - unusual-character-in-translation (from c1-control-characters) * Add alphabet information for: - Dutch; - Romance languages (Asturian, Catalan, Corsican, French, Italian, Occitan, Portuguese, Romanian, Spanish). * Add national varieties of English and Chinese languages to the language data file. * Add “Brazilian Portuguese” as another name for pt_BR. * Check for duplicate message definitions. * Check for duplicate header fields. * Check for encodings incompatible with ASCII. * Check for more unusual characters in translations: - C0 control characters; - replacement character (U+FFFD); - inverted question mark (U+00BF) directly after a letter. * Work around a newline decoding bug in polib. https://bugs.debian.org/692283 * Improve the test suite. -- Jakub Wilk Thu, 22 Nov 2012 23:50:05 +0100 gettext-inspector (0.2) unstable; urgency=low * Summary of tag changes: + Added: - boilerplate-in-language-team - boilerplate-in-last-translator - invalid-last-translator - language-team-equal-to-last-translator - no-language-team-header-field - no-last-translator-header-field * Add support for the following encodings: - EUC-TW - GEORGIAN-PS - KOI8-RU - KOI8-T - VISCII * Don't fail if /etc/os-release doesn't exist. * Improve the test suite. * Add alphabet information for: - Albanian; - Armenian; - Baltic languages (Latvian, Lithuanian); - Celtic languages (Irish, Scottish Gaelic, Welsh); - Greek; - Germanic languages (Danish, Faroese, Frisian, German, Icelandic, Low German, Norwegian, Swedish); - South Slavic languages (Bosnian, Bulgarian, Croatian, Macedonian, Slovenian, Serbian). * Validate the Last-Translator and Language-Team header fields. -- Jakub Wilk Fri, 16 Nov 2012 19:57:26 +0100 gettext-inspector (0.1.1) unstable; urgency=low * Improve the test suite. * Makefile: remove bogus shebang. Thanks to Paul Wise for the bug report. * Add “This file has been generated automatically by […]. Do not edit.” comments where appropriate. * Add alphabet information for East Slavic languages (Belarusian, Russian, Ukrainian). * Do not make KOI8-RU an alias for KOI8-R. They are in fact distinct encodings. -- Jakub Wilk Mon, 12 Nov 2012 16:10:21 +0100 gettext-inspector (0.1) unstable; urgency=low * Initial release. * Summary of tag changes: + Added: - ancient-date - boilerplate-in-project-id-version - boilerplate-in-report-msgid-bugs-to - broken-encoding - c1-control-characters - date-from-future - encoding-in-language-header-field - invalid-content-transfer-encoding - invalid-content-type - invalid-date - invalid-language - invalid-mime-version - invalid-mo-file - invalid-report-msgid-bugs-to - language-disparity - language-variant-does-not-affect-translation - no-content-transfer-encoding-header-field - no-content-type-header-field - no-date-header-field - no-language-header-field - no-mime-version-header-field - no-package-name-in-project-id-version - no-project-id-version-header-field - no-report-msgid-bugs-to-header-field - no-version-in-project-id-version - non-portable-encoding - os-error - syntax-error-in-plural-forms - syntax-error-in-po-file - unable-to-determine-language - unknown-encoding - unknown-file-type - unknown-header-field - unknown-poedit-language - unrepresentable-characters -- Jakub Wilk Sun, 11 Nov 2012 16:22:46 +0100 i18nspector-0.25.5/doc/README0000644000000000000000000000171013147102065013573 0ustar0000000000000000Overview ======== **i18nspector** is a tool for checking translation templates (POT), message catalogues (PO) and compiled message catalogues (MO) files for common problems. These files are used by the GNU gettext translation functions and tools in many different development environments. Prerequisites ============= The following software is needed to run i18nspector: * Python ≥ 3.2; * polib_ ≥ 1.0.0, a gettext catalogs manipulation library; * RPLY_, a parser generator. Additionally, the following software is needed to rebuild the manual page from source: * docutils_ ≥ 0.6. For pip users:: python3 -m pip install polib rply python3 -m pip install docutils For Debian users:: apt-get install python3-polib python3-rply apt-get install python3-docutils .. _polib: https://pypi.python.org/pypi/polib .. _RPLY: https://pypi.python.org/pypi/rply .. _docutils: http://docutils.sourceforge.net/ .. vim:ft=rst ts=3 sts=3 sw=3 i18nspector-0.25.5/doc/Makefile0000644000000000000000000000343313147102065014357 0ustar0000000000000000# Copyright © 2012-2017 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. export LC_ALL=C rst2man = $(or $(shell which rst2man),rst2man.py) exe = i18nspector .PHONY: all all: $(exe).1 tags.txt: ../data/tags ../private/tags-as-rst > $(@).tmp mv $(@).tmp $(@) $(exe).1: $(exe).txt tags.txt $(rst2man) --input-encoding=UTF-8:strict < $(<) > $(@).tmp sed -i -e '/^[.]BI/ { s/\\fP/\\fR/g; }' $(@).tmp # work-around for https://bugs.debian.org/806601 sed -i -e 's/^[.]de1/.de/' $(@).tmp # work-around for https://bugs.debian.org/710678 sed -i -e "s/\([a-z]\)\\\\(aq\([a-z]\)/\1'\2/g" $(@).tmp # prefer ' to \(aq when used as an apostrophe sed -i -e '/.\" vim:/d' $(@).tmp mv $(@).tmp $(@) .PHONY: clean clean: rm -f tags.txt $(exe).1 # vim:ts=4 sts=4 sw=4 noet i18nspector-0.25.5/data/0000755000000000000000000000000013147102065013060 5ustar0000000000000000i18nspector-0.25.5/data/timezones0000644000000000000000000000615513147102065015027 0ustar0000000000000000# This file has been generated automatically by private/update-timezones. # Do not edit. # Timezone database version: 2014e # Last update: 2014-07-07 [timezones] ACT = -0500 ADT = +0400 -0300 AFT = +0430 AKDT = -0800 AKST = -0900 ALMST = +0700 ALMT = +0600 AMST = +0400 +0500 -0300 AMT = +0300 +0400 -0400 ANAST = +1200 +1300 ANAT = +1100 +1200 AQTST = +0500 +0600 AQTT = +0400 +0500 ARST = -0200 -0300 ART = -0300 AST = +0300 -0400 AZOST = +0000 AZOT = -0100 AZST = +0500 AZT = +0400 BDST = +0700 BDT = +0600 BNT = +0800 BOT = -0400 BRST = -0200 BRT = -0300 BST = +0100 BTT = +0600 CAST = +1100 CAT = +0200 CCT = +0630 CDT = -0400 -0500 CEST = +0200 CET = +0100 CHADT = +1345 CHAST = +1245 CHOST = +1000 CHOT = +0800 +0900 CHUT = +1000 CKT = -1000 CLST = -0300 CLT = -0400 COT = -0500 CST = +0800 +0930 +1030 -0500 -0600 CVT = -0100 CWST = +0845 +0945 CXT = +0700 ChST = +1000 DAVT = +0500 +0700 DDUT = +1000 EASST = -0500 EAST = -0600 EAT = +0300 ECT = -0500 EDT = -0400 EEST = +0300 EET = +0200 EGST = +0000 EGT = -0100 EST = +1000 +1100 -0500 FET = +0300 FJST = +1300 FJT = +1200 FKST = -0300 FKT = -0400 FNST = -0100 FNT = -0200 GALT = -0600 GAMT = -0900 GEST = +0400 +0500 GET = +0300 +0400 GFT = -0300 GILT = +1200 GMT = +0000 GST = +0400 +1000 -0200 GYT = -0400 HADT = -0900 HAST = -1000 HKT = +0800 HOVST = +0800 HOVT = +0700 HST = -1000 ICT = +0700 IDT = +0300 IOT = +0500 +0600 IRDT = +0430 IRKST = +0900 IRKT = +0800 +0900 IRST = +0330 IST = +0100 +0200 +0530 JST = +0900 KGST = +0600 KGT = +0500 +0600 KOST = +1100 +1200 KRAST = +0800 KRAT = +0700 +0800 KST = +0900 LHST = +1030 +1100 LINT = +1400 -1000 LKT = +0600 +0630 MAGST = +1200 MAGT = +1100 +1200 MART = -0930 MAWT = +0500 +0600 MDT = -0600 MEST = +0200 MET = +0100 MHT = +1200 MIST = +1100 MMT = +0630 MOT = +0800 MPT = +1000 MSD = +0400 MSK = +0300 +0400 MST = -0700 MUST = +0500 MUT = +0400 MVT = +0500 MYT = +0800 MeST = -0800 NCST = +1200 NCT = +1100 NDT = -0230 NFT = +1130 NOVST = +0700 NOVT = +0600 +0700 NPT = +0545 NRT = +1200 NST = -0330 NUT = -1100 NZDT = +1300 NZST = +1200 OMSST = +0700 OMST = +0600 +0700 ORAST = +0500 ORAT = +0400 +0500 PDT = -0700 PET = -0500 PETST = +1200 +1300 PETT = +1100 +1200 PGT = +1000 PHOT = +1300 -1100 PHT = +0800 PKST = +0600 PKT = +0500 PMDT = -0200 PMST = -0300 PNT = -0830 PONT = +1100 PST = -0800 PWT = +0900 PYST = -0300 PYT = -0400 QYZST = +0700 QYZT = +0600 RET = +0400 ROTT = -0300 SAKST = +1100 +1200 SAKT = +1000 +1100 SAMST = +0400 +0500 SAMT = +0300 +0400 SAST = +0200 SBT = +1100 SCT = +0400 SGT = +0800 SRT = -0300 SST = -1100 SYOT = +0300 TAHT = -1000 TFT = +0500 TJT = +0500 TKT = +1300 -1100 TLT = +0900 TMT = +0500 TOST = +1400 TOT = +1300 TVT = +1200 UCT = +0000 ULAST = +0900 ULAT = +0800 UTC = +0000 UYST = -0200 UYT = -0300 UZT = +0500 VET = -0400 -0430 VLAST = +1100 VLAT = +1000 +1100 VOLST = +0400 VOLT = +0300 +0400 VOST = +0600 VUT = +1100 WAKT = +1200 WARST = -0300 WART = -0400 WAST = +0200 WAT = +0100 WEST = +0100 WET = +0000 WFT = +1200 WGST = -0200 WGT = -0300 WIB = +0700 WIT = +0900 WITA = +0800 WSDT = +1400 -1000 WST = +0800 +0900 +1300 -1100 YAKST = +1000 YAKT = +0900 +1000 YEKST = +0600 YEKT = +0500 +0600 # vim:ft=dosini i18nspector-0.25.5/data/tags0000644000000000000000000011142413147102065013744 0ustar0000000000000000[ancient-date] severity = normal certainty = certain description = The date refers to the time before the first GNU gettext release. As such, it's extremely unlikely to be correct. references = http://git.savannah.gnu.org/cgit/gettext.git/tree/ChangeLog.0#n1767 [arithmetic-error-in-plural-forms] severity = serious certainty = possible description = Computing a plural form value triggers division by zero or integer overflow. This normally indicates an error in the plural form expression. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [arithmetic-error-in-unused-plural-forms] severity = normal certainty = possible description = Computing a plural form value triggers division by zero or integer overflow. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [boilerplate-in-content-type] severity = important certainty = certain description = The Content-Type header field contains xgettext boilerplate. It should be in the form ``text/plain; charset=``\ *encoding*. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files [boilerplate-in-date] severity = normal certainty = certain description = The date header field contains xgettext boilerplate. The date format should be ``YYYY-MM-DD hh:mm+ZZzz``, e.g. ``2011-11-05 10:14+0100``. [boilerplate-in-initial-comments] severity = minor certainty = possible description = The initial comments contain xgettext or msginit boilerplate. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [boilerplate-in-language-team] severity = minor certainty = certain description = The Language-Team header field contains xgettext boilerplate. It should contain English name of the language, and the email address or homepage URL of the language team. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [boilerplate-in-last-translator] severity = normal certainty = certain description = The Last-Translator header field contains xgettext boilerplate. It should contain the last translator's name and email address. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [boilerplate-in-project-id-version] severity = minor certainty = certain description = The Project-Id-Version header field contains xgettext boilerplate. It should contain the name and the version of the package. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [boilerplate-in-report-msgid-bugs-to] severity = normal certainty = certain description = The Report-Msgid-Bugs-To header field contains xgettext boilerplate. It should contain an email address or URL where one can report bugs in the untranslated strings. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [broken-encoding] severity = serious certainty = possible description = Header fields and messages contained by this file couldn't be decoded to Unicode. The usual cause of this is incorrect or missing encoding declaration. . Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files https://tools.ietf.org/html/rfc2045#section-5 [c-format-string-argument-type-mismatch] severity = serious certainty = possible description = There's a type mismatch between a C format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a C format argument in ``msgstr`` and ``msgid``; or between a C format argument in ``msgstr[``\ *N*\ ``]`` and corresponding ``msgid`` or ``msgid_plural``. references = printf(3) https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [c-format-string-error] severity = serious certainty = possible description = A C format string could not be parsed. references = printf(3) [c-format-string-excess-arguments] severity = serious certainty = possible description = A C format string for ``msgid`` consumes more arguments than ``msgid_plural``; or ``msgstr`` consumes more arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes more arguments than corresponding ``msgid`` or ``msgid_plural``. references = printf(3) https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [c-format-string-missing-arguments] severity = serious certainty = possible description = A C format string for ``msgid`` consumes fewer arguments than ``msgid_plural``; or ``msgstr`` consumes fewer arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes fewer arguments than corresponding ``msgid`` or ``msgid_plural``. . Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: . . Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; . ... . msgid "one byte" . msgid_plural "%d bytes" . msgstr[0] "%d bajt" . msgstr[1] "%d bajta" . msgstr[2] "%d bajtova" . Here ``%d`` should not be replaced with the spelled-out form ``jedan``. Either ``%d`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: . . Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 . ... . msgid "one byte" . msgid_plural "%d bytes" . msgstr[0] "%d bajt" . msgstr[1] "%d bajta" . msgstr[2] "%d bajtova" . msgstr[3] "jedan bajt" references = printf(3) https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [c-format-string-non-portable-conversion] severity = pedantic certainty = possible description = A C format string uses a conversion specified or length modifier, for which a more portable replacement exists: . * For integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``), use the ``ll`` length modifier instead of ``L`` or ``q``. * For floating-point conversions (``%a``, ``%A``, ``%e``, ``%E``, ``%f``, ``%F``, ``%g``, and ``%G``), don't use the ``l`` length modifier. * Use the ``z`` length modifier instead of ``Z``. * Use ``%lc`` instead of ``%C``. * Use ``%ls`` instead of ``%S``. references = printf(3) [c-format-string-redundant-flag] severity = pedantic certainty = possible description = A C format string includes a redundant character flag. Either it's a duplicate, or it has no effect: . * The ``+`` flag overrides the *space* flag. * The ``-`` flag overrides the ``0`` flag. * If a precision is given, the ``0`` flag has no effect on integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``). references = printf(3) [codomain-error-in-plural-forms] severity = serious certainty = certain description = Either a plural form value is outside the declared range, or some values within the declared range can never be reached. This normally indicates an error in the plural form expression. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [codomain-error-in-unused-plural-forms] severity = normal certainty = certain description = Either a plural form value is outside the declared range, or some values within the declared range can never be reached. (But there are no translated messages which use plural forms.) This normally indicates an error in the plural form expression. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [conflict-marker-in-header-entry] severity = serious certainty = certain description = The header contains a conflict marker (``#-#-#-#-#`` *…* ``#-#-#-#-#``). The conflict will have to be resolved manually. references = https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia [conflict-marker-in-translation] severity = serious certainty = possible description = One of the translated messages appear to contain a conflict marker (``#-#-#-#-#`` *…* ``#-#-#-#-#``). The conflict will have to be resolved manually. references = https://www.gnu.org/software/gettext/manual/html_node/Creating-Compendia.html#Creating-Compendia [conflicting-message-flags] severity = important certainty = possible description = Two flags with conflicting meanings are associated with one of the messages. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [date-from-future] severity = normal certainty = certain description = The date refers to the future. As such, it's extremely unlikely to be correct. [distant-header-entry] severity = important certainty = certain description = The header entry in this file is preceded by other entries. The header entry should be always the first one. [duplicate-flag-for-header-entry] severity = minor certainty = certain description = Multiple identical flags are associated with the header entry. [duplicate-header-entry] severity = serious certainty = certain description = This file contains multiple header entries. [duplicate-header-field] severity = minor certainty = wild-guess description = This file contains multiple header fields of the same name. [duplicate-header-field-content-transfer-encoding] severity = pedantic certainty = certain description = This file contains multiple Content-Transfer-Encoding header fields. [duplicate-header-field-content-type] severity = serious certainty = certain description = This file contains multiple Content-Type header fields. [duplicate-header-field-date] severity = normal certainty = certain description = This file contains multiple date header fields of the same name. [duplicate-header-field-language] severity = important certainty = certain description = This file contains multiple Language header fields. [duplicate-header-field-language-team] severity = normal certainty = certain description = This file contains multiple Language-Team header fields. [duplicate-header-field-last-translator] severity = normal certainty = certain description = This file contains multiple Last-Translator header fields. [duplicate-header-field-mime-version] severity = pedantic certainty = certain description = This file contains multiple MIME-Version header fields. [duplicate-header-field-plural-forms] severity = serious certainty = certain description = This file contains multiple Plural-Forms header fields. [duplicate-header-field-project-id-version] severity = minor certainty = certain description = This file contains multiple Project-Id-Version header fields. [duplicate-header-field-report-msgid-bugs-to] severity = normal certainty = certain description = This file contains multiple Report-Msgid-Bugs-To header fields. [duplicate-header-field-x-poedit] severity = normal certainty = certain description = This file contains multiple X-Poedit-*\** header fields. [duplicate-message-definition] severity = serious certainty = certain description = This file contains multiple definitions of the same message. [duplicate-message-flag] severity = minor certainty = certain description = Multiple identical flags are associated with one of the messages. [empty-file] severity = normal certainty = certain description = This file doesn't contain any messages. [empty-msgid-message-with-plural-forms] severity = serious certainty = certain description = The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call ``ngettext("", …)``. [empty-msgid-message-with-source-code-references] severity = serious certainty = possible description = The message with empty msgid contains plural forms. Such messages are reserved by GNU gettext for header entries, and your code should not call ``gettext("")``. [encoding-in-language-header-field] severity = minor certainty = certain description = The language header field contains encoding declaration. Such information shouldn't be included in this field. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [fuzzy-header-entry] severity = pedantic certainty = certain description = The header entry is marked as fuzzy. For compatibility with very old (<< 0.11) **msgfmt**\ (1) versions, which didn't support fuzzy header entries, it shouldn't be marked as such. references = http://git.savannah.gnu.org/cgit/gettext.git/tree/NEWS?id=v0.11#n44 [inconsistent-leading-newlines] severity = important certainty = possible description = Some strings in an entry start with a newline, but some don't. Either all of them should start with a newline, or none of them should. [inconsistent-number-of-plural-forms] severity = serious certainty = certain description = Number of plural forms in a message definition doesn't match number of plural forms declared in another message definition. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [inconsistent-trailing-newlines] severity = important certainty = possible description = Some strings in an entry end with a newline, but some don't. Either all of them should end with a newline, or none of them should. [incorrect-number-of-plural-forms] severity = serious certainty = certain description = Number of plural forms in a message definition doesn't match number of plural forms declared in the header. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [invalid-content-transfer-encoding] severity = pedantic certainty = certain description = Value of the Content-Transfer-Encoding header field is invalid. It should be ``8bit``. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html https://tools.ietf.org/html/rfc2045#section-6.1 [invalid-content-type] severity = important certainty = possible description = Value of the Content-Type header field should is invalid. It should be in the form ``text/plain; charset=``\ *encoding*. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files https://tools.ietf.org/html/rfc2045#section-5 [invalid-date] severity = normal certainty = certain description = The date is invalid or in an invalid format. The format should be ``YYYY-MM-DD hh:mm+ZZzz``, e.g. ``2011-11-05 10:14+0100``. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [invalid-language] severity = important certainty = possible description = The Language header field couldn't be parsed, or it contains an unknown language. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [invalid-language-team] severity = normal certainty = possible description = The Language-Team header field contains an e-mail address that uses a reserved domain name, or a partially qualified domain name. references = https://tools.ietf.org/html/rfc2606 [invalid-last-translator] severity = normal certainty = possible description = The Last-Translator header field could neither be parsed as an e-mail, or the e-mail address uses a reserved domain name, or a partially qualified domain name. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html https://tools.ietf.org/html/rfc2606 [invalid-mime-version] severity = pedantic certainty = certain description = Value of the MIME-Version header field is invalid. It should be ``1.0``. references = https://tools.ietf.org/html/rfc2045#section-4 [invalid-mo-file] severity = serious certainty = certain description = This file couldn't be parsed a MO file. [invalid-range-flag] severity = important certainty = certain description = A ``range:`` flag couldn't be parsed, or the designated range contained fewer than two numbers. The syntax is ``range:``\ *min*\ ``..``\ *max*, where both values are non-negative integers. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [invalid-report-msgid-bugs-to] severity = normal certainty = possible description = The Report-Msgid-Bugs-To header field could neither be parsed as an e-mail nor as a URL, or the e-mail address uses a reserved domain name, or a partially qualified domain name. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html https://tools.ietf.org/html/rfc2606 [language-disparity] severity = normal certainty = possible description = Language of this file has been declared in multiple places, but the declarations don't match. [language-team-equal-to-last-translator] severity = minor certainty = possible description = Language-Team and Last-Translator header fields contain the same e-mail address. [language-variant-does-not-affect-translation] severity = minor certainty = possible description = The Language header field contains a variant designator that is not relevant for the message translation. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [leading-junk-in-plural-forms] severity = important certainty = certain description = The Plural-Forms header field contains unexpected text before the ``nplurals=`` string. . GNU gettext runtime ignores such leading junk, but other header parsers might be less liberal in what they accept. [malformed-xml] severity = serious certainty = possible description = The original string or the translated string contains an XML fragment, which is not well-formed. references = https://www.w3.org/TR/REC-xml/#sec-well-formed [no-content-transfer-encoding-header-field] severity = pedantic certainty = certain description = The Content-Transfer-Encoding header field doesn't exist. It should be set to ``8bit``. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html https://tools.ietf.org/html/rfc2045#section-6.1 [no-content-type-header-field] severity = important certainty = certain description = The Content-Type header field doesn't exist. It should be set to ``text/plain; charset=``\ *encoding*. . Note that in the absence of encoding declaration, i18nspector assumes ASCII encoding. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-of-PO-files https://tools.ietf.org/html/rfc2045#section-5 [no-date-header-field] severity = minor certainty = certain description = The date header field doesn't exist. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-language-header-field] severity = pedantic certainty = certain description = The Language header field doesn't exist. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-language-team-header-field] severity = pedantic certainty = certain description = The Language-Team header field does not exist. It should contain English name of the language, and the email address or homepage URL of the language team. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-last-translator-header-field] severity = normal certainty = certain description = The Last-Translator header field doesn't exist. It should contain the last translator's name and email address. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-mime-version-header-field] severity = pedantic certainty = certain description = The MIME-Version header field doesn't exist. It should be to set to ``1.0``. references = https://tools.ietf.org/html/rfc2045#section-4 [no-package-name-in-project-id-version] severity = minor certainty = possible description = The Project-Id-Version header field doesn't appear to contain any name. It should contain both the name and the version of the package. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-plural-forms-header-field] severity = minor certainty = certain description = The Plural-Forms header field does not exist, even though some of the messages use plural forms (although none of them have been translated). references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [no-project-id-version-header-field] severity = minor certainty = certain description = The Project-Id-Version header field does not exist. It should contain the name and the version of the package. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-report-msgid-bugs-to-header-field] severity = normal certainty = certain description = The Report-Msgid-Bugs-To header field does not exist or it is empty. It should contain an email address or URL where one can report bugs in the untranslated strings. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [no-required-plural-forms-header-field] severity = serious certainty = certain description = The Plural-Forms header field does not exist, even though some of the translated messages use plural forms. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [no-version-in-project-id-version] severity = pedantic certainty = possible description = The Project-Id-Version header field doesn't appear to contain any version. It should contain both the name and the version of the package. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html [non-ascii-compatible-encoding] severity = serious certainty = certain description = This file uses an encoding that is not compatible with ASCII. [non-portable-encoding] severity = important certainty = certain description = This file uses an encoding that is not widely supported by software. references = https://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#index-encoding-list [os-error] severity = serious certainty = certain description = An input/output error or another operating system error occurred while checking this file. [partially-translated-message] severity = serious certainty = possible description = Translation is missing for some plural forms of a message. [python-brace-format-string-argument-type-mismatch] severity = serious certainty = possible description = There's a type mismatch between a Python format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a Python format argument in ``msgstr`` and ``msgid``; or between a Python format argument in ``msgstr[``\ *N*\ ``]`` and ``msgid`` or ``msgid_plural``. references = https://docs.python.org/2/library/string.html#formatstrings [python-brace-format-string-error] severity = serious certainty = possible description = A Python format string could not be parsed. references = https://docs.python.org/2/library/string.html#formatstrings [python-brace-format-string-missing-argument] severity = serious certainty = possible description = A Python format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. . Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: . . Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; . ... . msgid "one byte" . msgid_plural "{n} bytes" . msgstr[0] "{n} bajt" . msgstr[1] "{n} bajta" . msgstr[2] "{n} bajtova" . Here ``{n}`` should not be replaced with the spelled-out form ``jedan``. Either ``{n}`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: . . Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 . ... . msgid "one byte" . msgid_plural "{n} bytes" . msgstr[0] "{n} bajt" . msgstr[1] "{n} bajta" . msgstr[2] "{n} bajtova" . msgstr[3] "jedan bajt" references = https://docs.python.org/2/library/string.html#formatstrings https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [python-brace-format-string-unknown-argument] severity = serious certainty = possible description = A Python format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. references = https://docs.python.org/2/library/string.html#formatstrings https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [python-format-string-argument-number-mismatch] severity = serious certainty = possible description = A Python format string for ``msgid`` consumes more arguments than ``msgid_plural``; or ``msgstr`` consumes more arguments than ``msgid``; or ``msgstr[``\ *N*\ ``]`` consumes more arguments than ``msgid`` or ``msgid_plural``. . Python, unlike C, requires that all unnamed arguments are consumed during conversion. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python [python-format-string-argument-type-mismatch] severity = serious certainty = possible description = There's a type mismatch between a Python format argument in ``msgid`` and the corresponding format argument in ``msgid_plural``; or between a Python format argument in ``msgstr`` and ``msgid``; or between a Python format argument in ``msgstr[``\ *N*\ ``]`` and ``msgid`` or ``msgid_plural``. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-error] severity = serious certainty = possible description = A Python format string could not be parsed. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-missing-argument] severity = serious certainty = possible description = A Python format string for ``msgid`` doesn't use a named argument that is used in ``msgid_plural``; or ``msgstr`` doesn't use a named argument that is used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` doesn't use a named argument that is used in corresponding ``msgid`` or ``msgid_plural``. . Note that in some languages, the commonly used Plural-Forms expression evaluates to the same value for n=1 and n=21, n=31, and so on. Take this Serbian translation for example:: . . Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; . ... . msgid "one byte" . msgid_plural "%(n)d bytes" . msgstr[0] "%(n)d bajt" . msgstr[1] "%(n)d bajta" . msgstr[2] "%(n)d bajtova" . Here ``%d`` should not be replaced with the spelled-out form ``jedan``. Either ``%d`` should be kept, or the Plural-Forms expression should be amended, so that there is a special case for n=1:: . . Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2 . ... . msgid "one byte" . msgid_plural "%(n)d bytes" . msgstr[0] "%(n)d bajt" . msgstr[1] "%(n)d bajta" . msgstr[2] "%(n)d bajtova" . msgstr[3] "jedan bajt" references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Translating-plural-forms.html [python-format-string-multiple-unnamed-arguments] severity = serious certainty = possible description = A Python format string uses multiple unnamed arguments (such as ``%d``). The translator might need to reorder the arguments to properly translate the message, but this is not possible with unnamed arguments. Named arguments (such as ``%(num)d``) should be used instead. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python [python-format-string-obsolete-conversion] severity = pedantic certainty = possible description = A Python format string uses an obsolete conversion specifier: . * Use ``%d`` instead of ``%u``. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-redundant-flag] severity = pedantic certainty = possible description = A Python format string includes a redundant character flag. Either it's a duplicate, or it has no effect: . * The ``+`` flag overrides the *space* flag. * The ``-`` flag overrides the ``0`` flag. * If a precision is given, the ``0`` flag has no effect on integer conversions (``%d``, ``%i``, ``%o``, ``%u``, ``%x``, and ``%X``). references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-redundant-length] severity = pedantic certainty = possible description = A Python format string includes a redundant length modifier. Length modifiers (``h``, ``l``, or ``L``) have no effect in Python. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-redundant-precision] severity = pedantic certainty = possible description = A C format string includes precision that has no effect on the conversion. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations [python-format-string-unknown-argument] severity = serious certainty = possible description = A Python format string for ``msgid`` uses a named argument that isn't used in ``msgid_plural``; or ``msgstr`` uses a named argument that isn't used in ``msgid``; or ``msgstr[``\ *N*\ ``]`` uses a named argument that isn't used in corresponding ``msgid`` or ``msgid_plural``. This indicates that the conversion would try to consume an argument that weren't supplied. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [python-format-string-unnamed-plural-argument] severity = wishlist certainty = possible description = A Python format string uses an unnamed arguments (such as ``%d``) in the context of plural forms. The translator might want not to use the numeric argument in the singular form; but this is not possible if the argument is unnamed, because python, unlike C, requires that all unnamed arguments are consumed during conversion. Named arguments (such as ``%(n)d``) should be used instead. references = https://docs.python.org/2/library/stdtypes.html#string-formatting-operations https://www.gnu.org/software/gettext/manual/html_node/Python.html#Python [qt-plural-format-mistaken-for-c-format] severity = important certainty = possible description = A ``c-format`` flag is associated with the message, but ``qt-plural-format`` should be used instead. . The only C format directive that the message uses is ``%n``. It is very atypical to use it alone in a C format string. references = http://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals printf(3) [range-flag-without-plural-string] severity = normal certainty = certain description = A ``range:`` flag is associated with a message that doesn't have plural string. ``range:`` flags only make sense for translations involving plural forms. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [redundant-message-flag] severity = pedantic certainty = certain description = A flag associated with one of the messages is redundant, because it's implied by another flag. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [stray-header-line] severity = important certainty = certain description = The header contains a line that does not belong to any header field. Note that RFC-822-style folding of long headers is not supported. references = https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00010.html [stray-previous-msgid] severity = minor certainty = certain description = The message entry contains annotations about previous untranslated string (``#| msgid``\ *...*), even though the message is not marked as fuzzy. These annotations are only useful for fuzzy messages, and should be removed when unfuzzying. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [syntax-error-in-plural-forms] severity = serious certainty = certain description = Value of the Plural-Forms header field could not be parsed. It should be in the form ``nplurals=``\ *n*\ ``; plural=``\ *expression*. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [syntax-error-in-po-file] severity = serious certainty = possible description = This file couldn't be parsed a PO file. In some rare cases this is due to incorrect or missing encoding declaration. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html https://bugs.debian.org/692283 [syntax-error-in-unused-plural-forms] severity = important certainty = certain description = Value of the Plural-Forms header field could not be parsed. (But there are no translated messages which use plural forms.) It should be in the form ``nplurals=``\ *n*\ ``; plural=``\ *expression*. references = https://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html [trailing-junk-in-plural-forms] severity = important certainty = certain description = The Plural-Forms header field contains unexpected text after the plural expression. . GNU gettext runtime ignores such trailing junk, but other header parsers might be less liberal in what they accept. [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 description = i18nspector was unable to determine language of this file. Absence of this information will prevent it from performing further checks. [unexpected-flag-for-header-entry] severity = normal certainty = possible description = An unexpected flag is associated with the header entry. The only flag that makes sense for the header entry is ``fuzzy``. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [unknown-encoding] severity = important certainty = possible description = This file declares an encoding that couldn't be recognized by i18nspector. It might be a typo. Absence of encoding information will prevent i18nspector from performing further checks. [unknown-file-type] severity = normal certainty = wild-guess description = File format of this file couldn't be recognized. It might be a bug in i18nspector. [unknown-header-field] severity = minor certainty = wild-guess description = The header field name is unknown to i18nspector. It might be a typo or a capitalization error (header field names are case-sensitive). references = https://lists.gnu.org/archive/html/bug-gettext/2012-12/msg00010.html [unknown-message-flag] severity = normal certainty = wild-guess description = An unknown flag is associated with one of the messages. It might be a typo. references = https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html [unknown-poedit-language] severity = minor certainty = wild-guess description = Language declared in X-Poedit-Language couldn't be recognized. It might be a bug in i18nspector. [unrepresentable-characters] severity = serious certainty = possible description = The declared encoding cannot represent all characters commonly used in this language. This is a strong indication that the declared encoding is incorrect. [unusual-character-in-header-entry] severity = important certainty = certain description = The header entry contains an unusual character. This is usually an indication of an encoding problem, such as: . * using ISO 2022 escape sequences, or * using UTF-8 despite declaring an 8-bit encoding. references = http://www.unicode.org/faq/utf_bom.html#bom6 [unusual-character-in-translation] severity = important certainty = possible description = One of the translated messages contains an unusual character. This is usually an indication of an encoding problem, such as: . * using ISO 2022 escape sequences, or * using UTF-8 despite declaring an 8-bit encoding. references = http://www.unicode.org/faq/utf_bom.html#bom6 [unusual-plural-forms] severity = serious certainty = possible description = The Plural-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. [unusual-unused-plural-forms] severity = normal certainty = possible description = The Plural-Forms declaration is incorrect (or unusual), according to i18nspector's linguistic data. (But there are no translated messages which use plural forms.) # vim:ft=dosini i18nspector-0.25.5/data/string-formats0000644000000000000000000000516113147102065015765 0ustar0000000000000000[formats] # = [example...] awk = %d # https://www.gnu.org/software/gawk/manual/html_node/Printf.html boost = %d # http://www.boost.org/doc/libs/release/libs/format/doc/format.html c = %d # http://man7.org/linux/man-pages/man3/printf.3.html csharp = {0} # https://msdn.microsoft.com/library/txafckwd%28v=vs.110%29.aspx elisp = %d # https://www.gnu.org/software/emacs/manual/html_node/elisp/Formatting-Strings.html gcc-internal = %d # https://www.gnu.org/software/gettext/manual/html_node/gcc_002dinternal_002dformat.html gfc-internal = %d # https://www.gnu.org/software/gettext/manual/html_node/gfc_002dinternal_002dformat.html java = {0} # https://docs.oracle.com/javase/7/docs/api/java/text/MessageFormat.html # https://ssl.icu-project.org/apiref/icu4j/com/ibm/icu/text/MessageFormat.html javascript = %d # https://www.gnu.org/software/gettext/manual/html_node/javascript_002dformat.html # https://nodejs.org/api/util.html#util_util_format_format kde = %1 # https://techbase.kde.org/Development/Tutorials/Localization/i18n kde-kuit = %1 # http://api.kde.org/frameworks-api/frameworks5-apidocs/ki18n/html/prg_guide.html librep = %d # http://librep.sourceforge.net/librep-manual.html#Formatted%20Output lisp = ~A # http://www.lispworks.com/documentation/HyperSpec/Body/22_c.htm lua = %d # http://www.lua.org/manual/5.2/manual.html#pdf-string.format objc = %d # https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html object-pascal = %d # https://www.freepascal.org/docs-html/rtl/sysutils/format.html perl = %d # http://perldoc.perl.org/functions/sprintf.html perl-brace = {var} # https://metacpan.org/pod/Locale::TextDomain php = %d # https://secure.php.net/manual/en/function.sprintf.php python = %d # https://docs.python.org/2/library/stdtypes.html#string-formatting-operations # https://docs.python.org/3/library/stdtypes.html#old-string-formatting python-brace = {0} {var} # https://docs.python.org/2/library/string.html#formatstrings # https://docs.python.org/3/library/string.html#formatstrings qt = %1 # http://doc.qt.io/qt-5/qstring.html#arg qt-plural = %n # http://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals scheme = ~A # https://people.csail.mit.edu/jaffer/slib/Format-Specification.html sh = $var # https://www.gnu.org/software/gettext/manual/html_node/sh_002dformat.html smalltalk = %1 # https://www.gnu.org/software/smalltalk/manual-base/html_node/CharacterArray_002dstring-processing.html tcl = %d # https://www.tcl.tk/man/tcl8.6/TclCmd/format.htm ycp = %1 # https://doc.opensuse.org/projects/YaST/SLES11/tdg/sformat.html # vim:ft=dosini i18nspector-0.25.5/data/languages0000644000000000000000000010145313147102065014755 0ustar0000000000000000# This file should describe only the languages that fall into one of the # following categories: # - languages that have an ISO 639-1 two-letter code; # - languages recognized by poedit; # - languages for which real-world PO files exist. # ISO 639-2 codes for collections of languages # should normally not be added here. # See: http://www-01.sil.org/iso639-3/scope.asp#C [aa] names = Afar [ab] names = Abkhazian characters = а б в г ӷ д е ж з ӡ и к қ ҟ л м н о п ԥ р с т ҭ у ф х ҳ ц ҵ ч ҷ ҽ ҿ ш ы ҩ џ ь ә А Б В Г Ӷ Д Е Ж З Ӡ И К Қ Ҟ Л М Н О П Ԥ Р С Т Ҭ У Ф Х Ҳ Ц Ҵ Ч Ҷ Ҽ Ҿ Ш Ы Ҩ Џ Ь Ә [ace] names = Achinese principal-territory = ID [ach] names = Acoli [ady] names = Adyghe Adygei characters = а б в г д е (ё) ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э (ю) я А Б В Г Д Е (Ё) Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э (Ю) Я Ӏ [ae] names = Avestan [af] names = Afrikaans principal-territory = ZA plural-forms = nplurals=2; plural=n != 1; [ak] names = Akan principal-territory = GH [am] names = Amharic characters = ሀ ሁ ሂ ሃ ሄ ህ ሆ ለ ሉ ሊ ላ ሌ ል ሎ ሏ ሐ ሑ ሒ ሓ ሔ ሕ ሖ ሗ መ ሙ ሚ ማ ሜ ም ሞ ሟ ሠ ሡ ሢ ሣ ሤ ሥ ሦ ሧ ረ ሩ ሪ ራ ሬ ር ሮ ሯ ሰ ሱ ሲ ሳ ሴ ስ ሶ ሷ ሸ ሹ ሺ ሻ ሼ ሽ ሾ ሿ ቀ ቁ ቂ ቃ ቄ ቅ ቆ ቈ ቊ ቋ ቌ ቍ በ ቡ ቢ ባ ቤ ብ ቦ ቧ ቨ ቩ ቪ ቫ ቬ ቭ ቮ ቯ ተ ቱ ቲ ታ ቴ ት ቶ ቷ ቸ ቹ ቺ ቻ ቼ ች ቾ ቿ ኀ ኁ ኂ ኃ ኄ ኅ ኆ ኈ ኊ ኋ ኌ ኍ ነ ኑ ኒ ና ኔ ን ኖ ኗ ኘ ኙ ኚ ኛ ኜ ኝ ኞ ኟ አ ኡ ኢ ኣ ኤ እ ኦ ኧ ከ ኩ ኪ ካ ኬ ክ ኮ ኰ ኲ ኳ ኴ ኵ ኸ ኹ ኺ ኻ ኼ ኽ ኾ ወ ዉ ዊ ዋ ዌ ው ዎ ዐ ዑ ዒ ዓ ዔ ዕ ዖ ዘ ዙ ዚ ዛ ዜ ዝ ዞ ዟ ዠ ዡ ዢ ዣ ዤ ዥ ዦ ዧ የ ዩ ዪ ያ ዬ ይ ዮ ደ ዱ ዲ ዳ ዴ ድ ዶ ዷ ጀ ጁ ጂ ጃ ጄ ጅ ጆ ጇ ገ ጉ ጊ ጋ ጌ ግ ጎ ጐ ጒ ጓ ጔ ጕ ጠ ጡ ጢ ጣ ጤ ጥ ጦ ጧ ጨ ጩ ጪ ጫ ጬ ጭ ጮ ጯ ጰ ጱ ጲ ጳ ጴ ጵ ጶ ጷ ጸ ጹ ጺ ጻ ጼ ጽ ጾ ጿ ፀ ፁ ፂ ፃ ፄ ፅ ፆ ፈ ፉ ፊ ፋ ፌ ፍ ፎ ፏ ፐ ፑ ፒ ፓ ፔ ፕ ፖ ፗ plural-forms = nplurals=2; plural=n > 1; principal-territory = ET [an] names = Aragonese principal-territory = ES [ang] names = Old English principal-territory = GB [ar] names = Arabic characters = ا ب ت ث ج ح خ د ذ ر ز س ش ص ض ط ظ ع غ ف ق ك ل م ن ه و ي [as] names = Assamese characters = অ আ ই ঈ উ ঊ ঋ ৠ ঌ ৡ এ ঐ ও ঔ ক খ গ ঘ ঙ চ ছ জ ঝ ঞ ট ঠ ড ঢ ণ ত ৎ থ দ ধ ন প ফ ব ভ ম য ৰ ল ৱ শ ষ স হ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [ast] names = Asturian Bable Leonese Asturleonese characters = á é í ñ ó ú (ü) Á É Í Ñ Ó Ú (Ü) plural-forms = nplurals=2; plural=n != 1; principal-territory = ES [av] names = Avaric principal-territory = RU [ay] names = Aymara [az] names = Azerbaijani ç ə ğ ı i ö ş ü Ç Ə Ğ I İ Ö Ş Ü principal-territory = AZ [ba] names = Bashkir [bal] names = Baluchi [be] names = Belarusian characters = а б в г д е ё ж з і й к л м н о п р с т у ў ф х ц ч ш ы ь э ю я А Б В Г Д Е Ё Ж З І Й К Л М Н О П Р С Т У Ў Ф Х Ц Ч Ш Ы Ь Э Ю Я characters@latin = ć č ł ń ś š ŭ ź ž Ć Č Ł Ń Ś Š Ŭ Ź Ž plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = BY [bem] names = Bemba principal-territory = ZM [bg] names = Bulgarian characters = а б в г д е ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ь ю я А Б В Г Д Е Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ь Ю Я plural-forms = nplurals=2; plural=n != 1; principal-territory = BG [bho] names = Bhojpuri principal-territory = IN [bi] names = Bislama [bm] names = Bambara principal-territory = ML [bn] names = Bengali characters = অ আ ই ঈ উ ঊ ঋ এ ঐ ও ঔ ক খ গ ঘ ঙ চ ছ জ ঝ ঞ ট ঠ ড ঢ ণ ত থ দ ধ ন প ফ ব ভ ম য র ল শ ষ স হ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [bo] names = Tibetan principal-territory = CN [br] names = Breton characters = â ê î ô û ù ü ñ Â Ê Î Ô Û Ù Ü Ñ plural-forms = nplurals=2; plural=n > 1; principal-territory = FR [bs] names = Bosnian characters = đ ž ć č š Đ Ž Ć Č Š plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = BA [byn] names = Blin Bilin [ca] names = Catalan Valencian characters = à é è í ï ó ò ú ü ç À É È Í Ï Ó Ò Ú Ü Ç plural-forms = nplurals=2; plural=n != 1; principal-territory = ES [ce] names = Chechen principal-territory = RU [ceb] names = Cebuano principal-territory = PH [ch] names = Chamorro [co] names = Corsican characters = à è ì ï ò ù ü À È Ì Ï Ò Ù Ü principal-territory = FR [cr] names = Cree principal-territory = CA [crh] names = Crimean Tatar Crimean Turkish characters = â ç ğ ı i ñ ö ş ü Â Ç Ğ I İ Ñ Ö Ş Ü [cs] names = Czech characters = á č ď é ě í ň ó ř š ť ú ů ý ž Á Č Ď É Ě Í Ň Ó Ř Š Ť Ú Ů Ý Ž plural-forms = nplurals=3; plural=n==1 ? 0 : (n>=2 && n<=4) ? 1 : 2; principal-territory = CZ [csb] names = Kashubian characters = ą ã é ë ł ń ò ó ô ù ż Ą Ã É Ë Ł Ń Ò Ó Ô Ù Ż principal-territory = PL [cu] names = Church Slavic Church Slavonic Old Bulgarian Old Church Slavonic Old Slavonic [cv] names = Chuvash [cy] names = Welsh characters = â ê î ô û ŵ ŷ Â Ê Î Ô Û Ŵ Ŷ principal-territory = GB [da] names = Danish characters = æ ø å Æ Ø Å plural-forms = nplurals=2; plural=n != 1; principal-territory = DK [de] names = German characters = ä ö ü ß Ä Ö Ü plural-forms = nplurals=2; plural=n != 1; principal-territory = DE [doi] names = Dogri principal-territory = IN [dv] names = Dhivehi Divehi Maldivian principal-territory = MV [dz] names = Dzongkha # for simplicity, only consonants are included here; # they should be sufficient for i18nspector purposes: characters = ཀ ཁ ག ང ཅ ཆ ཇ ཉ ཏ ཐ ད ན པ ཕ བ མ ཙ ཚ ཛ ཝ ཞ ཟ འ ཡ ར ལ ཤ ས ཧ ཨ principal-territory = BT [ee] names = Ewe principal-territory = GH [el] names = Greek characters = α β γ δ ε ζ η θ ι κ λ μ ν ξ ο π ρ σ ς τ υ φ χ ψ ω Α Β Γ Δ Ε Ζ Η Θ Ι Κ Λ Μ Ν Ξ Ο Π Ρ Σ Τ Υ Φ Χ Ψ Ω plural-forms = nplurals=2; plural=n != 1; principal-territory = GR [en] names = English characters@quot = ‘ ’ characters@boldquot = ‘ ’ characters@shaw = 𐑐 𐑑 𐑒 𐑓 𐑔 𐑕 𐑖 𐑗 𐑘 𐑙 𐑚 𐑛 𐑜 𐑝 𐑞 𐑟 𐑠 𐑡 𐑢 𐑣 𐑤 𐑥 𐑦 𐑧 𐑨 𐑩 𐑪 𐑫 𐑬 𐑭 𐑮 𐑯 𐑰 𐑱 𐑲 𐑳 𐑴 𐑵 𐑶 𐑷 𐑸 𐑹 𐑺 𐑻 𐑼 𐑽 𐑾 𐑿 plural-forms = nplurals=2; plural=n != 1; [en_AU] names = Australian English [en_CA] names = Canadian English [en_GB] names = British English [en_US] names = American English [eo] names = Esperanto characters = ĉ ĝ ĥ ĵ ŝ ŭ Ĉ Ĝ Ĥ Ĵ Ŝ Ŭ plural-forms = nplurals=2; plural=n != 1; [es] names = Spanish characters = á é í ñ ó ú (ü) Á É Í Ñ Ó Ú (Ü) plural-forms = nplurals=2; plural=n != 1; principal-territory = ES [et] names = Estonian characters = (š) (ž) õ ä ö ü (Š) (Ž) Õ Ä Ö Ü plural-forms = nplurals=2; plural=n != 1; principal-territory = EE [eu] names = Basque characters = (ç) ñ (Ç) Ñ plural-forms = nplurals=2; plural=n != 1; [fa] names = Persian characters = ا ب پ ت ث ج چ ح خ د ذ ر ز ژ س ش ص ض ط ظ ع غ ف ق ک گ ل م ن و ه ی plural-forms = nplurals=1; plural=0; principal-territory = IR [ff] names = Fulah [fi] names = Finnish characters = (š) (ž) å ä ö (Š) (Ž) Å Ä Ö plural-forms = nplurals=2; plural=n != 1; principal-territory = FI [fil] names = Filipino Pilipino principal-territory = PH [fj] names = Fijian principal-territory = FJ [fo] names = Faroese characters = á ð í ó ú ý æ ø Á Ð Í Ó Ú Ý Æ Ø plural-forms = nplurals=2; plural=n != 1; principal-territory = FO [fr] names = French characters = à â (æ) ç é è ê ë î ï ô (œ) ù û ü ÿ À  (Æ) Ç É È Ê Ë Î Ï Ô (Œ) Ù Û Ü (Ÿ) plural-forms = nplurals=2; plural=n > 1; principal-territory = FR [fur] names = Friulian principal-territory = IT [fy] names = Frisian Western Frisian characters = â ê é ô û ú Â Ê É Ô Û Ú plural-forms = nplurals=2; plural=n != 1; principal-territory = NL [ga] names = Irish characters = á é í ó ú Á É Í Ó Ú # plural-forms = nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2; principal-territory = IE [gaa] names = Ga [gd] names = Gaelic Scottish Gaelic characters = à è ì ò ù À È Ì Ò Ù principal-territory = GB [gez] names = Geez characters = ሀ ሁ ሂ ሃ ሄ ህ ሆ ለ ሉ ሊ ላ ሌ ል ሎ ሏ ሐ ሑ ሒ ሓ ሔ ሕ ሖ ሗ መ ሙ ሚ ማ ሜ ም ሞ ሟ ፙ ሠ ሡ ሢ ሣ ሤ ሥ ሦ ሧ ረ ሩ ሪ ራ ሬ ር ሮ ሯ ፘ ሰ ሱ ሲ ሳ ሴ ስ ሶ ሷ ቀ ቁ ቂ ቃ ቄ ቅ ቆ ቋ በ ቡ ቢ ባ ቤ ብ ቦ ቧ ተ ቱ ቲ ታ ቴ ት ቶ ቷ ኀ ኁ ኂ ኃ ኄ ኅ ኆ ኋ ነ ኑ ኒ ና ኔ ን ኖ ኗ አ ኡ ኢ ኣ ኤ እ ኦ ኧ ከ ኩ ኪ ካ ኬ ክ ኮ ኳ ወ ዉ ዊ ዋ ዌ ው ዎ ዐ ዑ ዒ ዓ ዔ ዕ ዖ ዘ ዙ ዚ ዛ ዜ ዝ ዞ ዟ የ ዩ ዪ ያ ዬ ይ ዮ ደ ዱ ዲ ዳ ዴ ድ ዶ ዷ ገ ጉ ጊ ጋ ጌ ግ ጎ ጓ ጠ ጡ ጢ ጣ ጤ ጥ ጦ ጧ ጰ ጱ ጲ ጳ ጴ ጵ ጶ ጷ ጸ ጹ ጺ ጻ ጼ ጽ ጾ ጿ ፀ ፁ ፂ ፃ ፄ ፅ ፆ ፈ ፉ ፊ ፋ ፌ ፍ ፎ ፏ ፚ ፐ ፑ ፒ ፓ ፔ ፕ ፖ ፗ [gl] names = Galician characters = á é í ñ ó ú Á É Í Ñ Ó Ú plural-forms = nplurals=2; plural=n != 1; [gn] names = Guarani [gu] names = Gujarati characters = અ આ ઇ ઈ ઉ ઊ ઋ એ ઐ ઓ ઔ ક ખ ગ ઘ ઙ ચ છ જ ઝ ઞ ટ ઠ ડ ઢ ણ ત થ દ ધ ન પ ફ બ ભ મ ય ર લ વ શ ષ સ હ ળ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [gv] names = Manx [ha] names = Hausa [haw] names = Hawaiian [he] names = Hebrew characters = א ב ג ד ה ו ז ח ט י כ ל מ נ ס ע פ צ ק ר ש ת plural-forms = nplurals=2; plural=n != 1; principal-territory = IL [hi] names = Hindi characters = अ आ इ ई उ ऊ ए ऐ ओ औ क ख ख़ ग ग॒ ग़ घ ङ च छ ज ज॒ ज़ झ ञ ट ठ ड ड॒ ड़ ढ ढ़ ण त थ द ध न प फ फ़ ब ब॒ भ म य र ल व श ष स ह plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [ho] names = Hiri Motu [hr] names = Croatian characters = đ ž ć č š Đ Ž Ć Č Š plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = HR [ht] names = Haitian Haitian Creole principal-territory = HT [hu] names = Hungarian characters = á é í ó ö ő ú ü ű Á É Í Ó Ö Ő Ú Ü Ű plural-forms = nplurals=1; plural=0; nplurals=2; plural=n != 1; principal-territory = HU [hy] names = Armenian characters = ա բ գ դ ե զ է ը թ ժ ի լ խ ծ կ հ ձ ղ ճ մ յ ն շ ո չ պ ջ ռ ս վ տ ր ց ւ փ ք և օ ֆ Ա Բ Գ Դ Ե Զ Է Ը Թ Ժ Ի Լ Խ Ծ Կ Հ Ձ Ղ Ճ Մ Յ Ն Շ Ո Չ Պ Ջ Ռ Ս Վ Տ Ր Ց Ւ Փ Ք Օ Ֆ principal-territory = AM [hz] names = Herero [ia] names = Interlingua plural-forms = nplurals=2; plural=n != 1; [id] names = Indonesian plural-forms = nplurals=1; plural=0; principal-territory = ID [ie] names = Interlingue Occidental [ig] names = Igbo principal-territory = NG [ii] names = Nuosu Sichuan Yi principal-territory = CN [ik] names = Inupiaq [ilo] names = Iloko principal-territory = PH [io] names = Ido [is] names = Icelandic characters = á ð é í ó ú ý þ æ ö Á Ð É Í Ó Ú Ý Þ Æ Ö principal-territory = IS [it] names = Italian characters = à è é ì í î ò ó ù ú À È É Ì Í Î Ò Ó Ù Ú plural-forms = nplurals=2; plural=n != 1; principal-territory = IT [iu] names = Inuktitut [ja] names = Japanese characters = # Hiragana: あ い う え お か き く け こ さ し す せ そ た ち つ て と な に ぬ ね の は ひ ふ へ ほ ま み む め も や ゆ よ ら り る れ ろ わ ゐ ゑ を ん # Katakana: ア イ ウ エ オ カ キ ク ケ コ サ シ ス セ ソ タ チ ツ テ ト ナ ニ ヌ ネ ノ ハ ヒ フ ヘ ホ マ ミ ム メ モ ヤ ユ ヨ ラ リ ル レ ロ ワ ヰ ヱ ヲ ン # Kanji (the list of ideograms is incomplete; # only the 100 most often used ones are included here): 以 一 下 化 加 可 解 開 外 確 間 起 検 見 現 後 効 更 行 合 込 再 最 在 作 削 使 始 指 字 時 次 示 自 失 実 者 取 終 集 出 書 除 小 上 場 情 新 数 成 正 生 切 設 先 選 前 全 続 存 他 大 択 値 置 中 追 通 定 的 度 動 読 内 日 入 認 能 敗 発 必 表 不 付 分 文 変 保 報 方 無 名 明 有 用 要 利 理 了 力 plural-forms = nplurals=1; plural=0; principal-territory = JP [jbo] names = Lojban [jv] names = Javanese principal-territory = ID [ka] names = Georgian characters = ა ბ გ დ ე ვ ზ (ჱ) თ ი კ ლ მ ნ (ჲ) ო პ ჟ რ ს ტ (ჳ) უ ფ ქ ღ ყ შ ჩ ც ძ წ ჭ ხ (ჴ) ჯ ჰ (ჵ) (ჶ) (ჷ) (ჺ) (ჸ) (ჹ) plural-forms = nplurals=1; plural=0; principal-territory = GE [kab] names = Kabyle principal-territory = DZ [kg] names = Kongo principal-territory = CD [ki] names = Gikuyu Kikuyu [kj] names = Kuanyama Kwanyama [kk] names = Kazakh characters = а ә б в г ғ д е ё ж з и й к қ л м н ң о ө п р с т у ұ ү ф х һ ц ч ш щ ъ ы і ь э ю я А Ә Б В Г Ғ Д Е Ё Ж З И Й К Қ Л М Н Ң О Ө П Р С Т У Ұ Ү Ф Х Һ Ц Ч Ш Щ Ъ Ы І Ь Э Ю Я plural-forms = nplurals=1; plural=0; principal-territory = KZ [kl] names = Greenlandic Kalaallisut principal-territory = GL [km] names = Central Khmer Khmer # for simplicity, only consonants are included here; # they should be sufficient for i18nspector purposes: characters = ក ខ គ ឃ ង ច ឆ ជ ឈ ញ ដ ឋ ឌ ឍ ណ ត ថ ទ ធ ន ប ផ ព ភ ម យ រ ល វ ឝ ឞ ស ហ ឡ អ plural-forms = nplurals=1; plural=0; principal-territory = KH [kn] names = Kannada characters = ಅ ಆ ಇ ಈ ಉ ಊ ಋ ೠ ಌ ೡ ಎ ಏ ಐ ಒ ಓ ಔ ಕ ಖ ಗ ಘ ಙ ಚ ಛ ಜ ಝ ಞ ಟ ಠ ಡ ಢ ಣ ತ ಥ ದ ಧ ನ ಪ ಫ ಬ ಭ ಮ ಯ ರ ಱ ಲ ವ ಶ ಷ ಸ ಹ ಳ ೞ principal-territory = IN [ko] names = Korean characters = # The list of Hangul syllables is incomplete; # only the 100 most often used ones are included here. 가 경 고 과 구 그 기 나 는 니 다 대 데 도 동 되 된 드 디 라 러 력 로 록 류 를 름 리 마 만 면 명 모 목 미 바 보 부 비 사 상 서 선 설 성 소 수 스 습 시 실 십 아 않 어 없 에 여 오 용 우 원 위 으 은 을 음 의 이 인 일 입 있 자 작 장 재 저 전 정 제 주 중 지 추 치 크 택 터 트 파 표 프 하 한 할 합 해 행 화 plural-forms = nplurals=1; plural=0; principal-territory = KR [kok] names = Konkani principal-territory = IN [kos] names = Kosraean [kr] names = Kanuri principal-territory = NG [ks] names = Kashmiri [ku] names = Kurdish characters = ç ê î ş û Ç Ê Î Ş Û plural-forms = nplurals=2; plural=n != 1; [kv] names = Komi [kw] names = Cornish [ky] names = Kirghiz Kyrgyz characters = а б в г д е ё ж з и й к л м н ң о ө п р с т у ү ф х ц ч ш щ ъ ы ь э ю я А Б В Г Д Е Ё Ж З И Й К Л М Н Ң О Ө П Р С Т У Ү Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я [la] names = Latin [lb] names = Letzeburgesch Luxembourgish [lg] names = Ganda principal-territory = UG [li] names = Limburgan principal-territory = BE [ln] names = Lingala [lo] names = Lao principal-territory = LA [lt] names = Lithuanian characters = ą č ę ė į š ų ū ž Ą Č Ę Ė Į Š Ų Ū Ž plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = LT [lu] names = Luba-Katanga principal-territory = CD [lv] names = Latvian characters = ā č ē ģ ī ķ ļ ņ š ū ž Ā Č Ē Ģ Ī Ķ Ļ Ņ Š Ū Ž plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2; principal-territory = LV [mai] names = Maithili plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [mg] names = Malagasy characters = à â é è ê ë ì î ï ñ ô À Â É È Ê Ë Ì Î Ï Ñ Ô plural-forms = nplurals=2; plural=n > 1; principal-territory = MG [mh] names = Marshall Marshallese [mi] names = Maori characters = ā ē ī ō ū Ā Ē Ī Ō Ū principal-territory = NZ [mk] names = Macedonian characters = а б в г д ѓ е ж з ѕ и ј к л љ м н њ о п р с т ќ у ф х ц ч џ ш А Б В Г Д Ѓ Е Ж З Ѕ И Ј К Л Љ М Н Њ О П Р С Т Ќ У Ф Х Ц Ч Џ Ш principal-territory = MK [ml] names = Malayalam characters = അ ആ ഇ ഈ ഉ ഊ ഋ എ ഏ ഐ ഒ ഓ ഔ ക ഖ ഗ ഘ ങ ച ഛ ജ ഝ ഞ ട ഠ ഡ ഢ ണ ത ഥ ദ ധ ന പ ഫ ബ ഭ മ യ ര ല വ ശ ഷ സ ഹ ള ഴ റ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [mn] names = Mongolian characters = а б в г д е ё ж з и й к л м н о ө п р с т у ү ф х ц ч ш щ ъ ы ь э ю я А Б В Г Д Е Ё Ж З И Й К Л М Н О Ө П Р С Т У Ү Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я plural-forms = nplurals=2; plural=n != 1; principal-territory = MN [mni] names = Manipuri principal-territory = IN [mr] names = Marathi characters = अ आ इ ई उ ऊ ऋ ऌ ए ऐ ऑ ओ औ क ख ग घ ङ च छ ज झ ञ ट ठ ड ढ ण त थ द ध न प फ ब भ म य र ल व श ष स ह ळ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [ms] names = Malay principal-territory = MY [mt] names = Maltese principal-territory = MT [mus] names = Creek [my] names = Burmese characters = က ခ ဂ ဃ င စ ဆ ဇ ဈ ဉ ည ဋ ဌ ဍ ဎ ဏ တ ထ ဒ ဓ န ပ ဖ ဗ ဘ မ ယ ရ လ ဝ သ ဟ ဠ principal-territory = MM [na] names = Nauru principal-territory = NR [nap] names = Neapolitan principal-territory = IT [nb] names = Norwegian Bokmål characters = æ ø å Æ Ø Å plural-forms = nplurals=2; plural=n != 1; principal-territory = NO [nd] names = North Ndebele [nds] names = Low German Low Saxon characters = ä ö ü ß Ä Ö Ü plural-forms = nplurals=2; plural=n != 1; principal-territory = DE [ne] names = Nepali characters = अ आ इ ई उ ऊ ऋ ए ऐ ओ औ क ख ग घ ङ च छ ज झ ञ ट ठ ड ढ ण त थ द ध न प फ ब भ म य र ल व श ष स ह plural-forms = nplurals=2; plural=n != 1; principal-territory = NP [ng] names = Ndonga [nl] names = Dutch Flemish characters = ä ë ï (ij) ö ü Ä Ë Ï (IJ) Ö Ü plural-forms = nplurals=2; plural=n != 1; principal-territory = NL [nn] names = Norwegian Nynorsk characters = æ ø å Æ Ø Å plural-forms = nplurals=2; plural=n != 1; principal-territory = NO [no] names = Norwegian characters = æ ø å Æ Ø Å macrolanguage = nb nn plural-forms = nplurals=2; plural=n != 1; principal-territory = NO [nr] names = South Ndebele principal-territory = ZA [nso] names = Pedi Sepedi Northern Sotho principal-territory = ZA [nv] names = Navaho Navajo [ny] names = Chichewa Chewa Nyanja [oc] names = Occitan characters = à á ç è é í ï ò ó ú ü À Á Ç È É Í Ï Ò Ó Ú Ü plural-forms = nplurals=2; plural=n > 1; principal-territory = FR [oj] names = Ojibwa principal-territory = CA [om] names = Oromo [or] names = Oriya characters = ଅ ଆ ଇ ଈ ଉ ଊ ଋ ଏ ଐ ଓ ଔ କ ଖ ଗ ଘ ଙ ଚ ଛ ଜ ଝ ଞ ଟ ଠ ଡ ଢ ଣ ତ ଥ ଦ ଧ ନ ପ ଫ ବ ଭ ମ ଯ ର ଲ ଳ ଶ ଷ ସ ହ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [os] names = Ossetian Ossetic characters = a ӕ б в г д дж дз е з и й к л м н о п р с т у ф х ц ч ы ъ А Ӕ Б В Г Д ДЖ ДЗ Е З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ы Ъ [pa] names = Panjabi Punjabi characters = ੴ ੳ ਉ ਊ ਓ ਅ ਆ ਐ ਔ ੲ ਇ ਈ ਏ ਸ ਹ ਕ ਖ ਗ ਘ ਙ ਚ ਛ ਜ ਝ ਞ ਟ ਠ ਡ ਢ ਣ ਤ ਥ ਦ ਧ ਨ ਪ ਫ ਬ ਭ ਮ ਯ ਰ ਲ ਵ ੜ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [pap] names = Papiamento [pi] names = Pali [pl] names = Polish characters = ą ć ę ó ł ń ó ś ż ź Ą Ć Ę Ó Ł Ń Ó Ś Ż Ź plural-forms = nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = PL [ps] names = Pashto Pushto characters = آ آ ب پ ت ټ ث ج چ ح خ څ ځ د ډ ﺫ ﺭ ړ ﺯ ژ ږ س ش ښ ص ض ط ظ ع غ ف ق ک ګ ل م ن ڼ و ه ي ې ی ۍ ئ plural-forms = nplurals=2; plural=n != 1; principal-territory = AF [pt] names = Portuguese characters = á â ã à ç é ê í ó ô õ ú Á  à À Ç É Ê Í Ó Ô Õ Ú plural-forms = nplurals=2; plural=n != 1; principal-territory = PT [pt_BR] names = Brazilian Brazilian Portuguese plural-forms = nplurals=2; plural=n > 1; [qu] names = Quechua [rm] names = Rhaeto-Romance Romansh principal-territory = CH [rn] names = Rundi principal-territory = BI [ro] names = Romanian characters = ă â î ș ț Ă Â Î Ș Ț plural-forms = nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2; principal-territory = RO [ro_MD] names = Moldavian Moldovan plural-forms = nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2; [ru] names = Russian characters = а б в г д е ё ж з и й к л м н о п р с т у ф х ц ч ш щ ъ ы ь э ю я А Б В Г Д Е Ё Ж З И Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = RU [rw] names = Kinyarwanda plural-forms = nplurals=2; plural=n != 1; [sa] names = Sanskrit principal-territory = IN [sat] names = Santali principal-territory = IN [sc] names = Sardinian principal-territory = IT [sco] names = Scots [sd] names = Sindhi characters = جھ ڄ ج پ ث ٺ ٽ ٿ ت ڀ ٻ ب ا ڙ ر ذ ڍ ڊ ڏ ڌ د خ ح ڇ چ ڃ ق ڦ ف غ ع ظ ط ض ص ش س ز ڙھ ي ه و ڻ ن م ل ڱ گھ ڳ گ ک ڪ characters@devanagari = अ आ इ ई उ ऊ ए ऐ ओ औ क ख ख़ ग ग॒ ग़ घ ङ च छ ज ज॒ ज़ झ ञ ट ठ ड ड॒ ड़ ढ ढ़ ण त थ द ध न प फ फ़ ब ब॒ भ म य र ल व श ष स ह [se] names = Northern Sami characters = á č đ ŋ š ŧ ž Á Č Đ Ŋ Š Ŧ Ž [sg] names = Sango Sangro principal-territory = CF [shn] names = Shan principal-territory = MM [si] names = Sinhala Sinhalese # for simplicity, only consonants are included here; # they should be sufficient for i18nspector purposes: characters = ක ග (ච) ජ ට ඩ ණ ත ද න ප බ ම ය ර ල ව ස හ ළ plural-forms = nplurals=2; plural=n != 1; principal-territory = LK [sk] names = Slovak characters = á ä č ď ž é í ĺ ľ ň ó ô ŕ š ť ú ý ž Á Ä Č Ď Ž É Í Ĺ Ľ Ň Ó Ô Ŕ Š Ť Ú Ý Ž # plural-forms = nplurals=3; plural=n==1 ? 0 : (n>=2 && n<=4) ? 1 : 2; principal-territory = SK [sl] names = Slovenian characters = č š ž Č Š Ž # plural-forms = nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3; # https://savannah.gnu.org/bugs/?45591 principal-territory = SI [sm] names = Samoan [sn] names = Shona [so] names = Somali principal-territory = SO [sq] names = Albanian characters = ç ë Ç Ë plural-forms = nplurals=2; plural=n != 1; principal-territory = AL [sr] names = Serbian characters = а б в г д ђ е ж з и ј к л љ м н њ о п р с т ћ у ф х ц ч џ ш А Б В Г Д Ђ Е Ж З И Ј К Л Љ М Н Њ О П Р С Т Ћ У Ф Х Ц Ч Џ Ш characters@latin = đ ž ć č š Đ Ž Ć Č Š characters@ijekavianlatin = đ ž ć č š Đ Ž Ć Č Š plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = RS [ss] names = Swati Siswati [st] names = Sesotho Southern Sotho [su] names = Sundanese [sv] names = Swedish characters = å ä ö Å Ä Ö plural-forms = nplurals=2; plural=n != 1; principal-territory = SE [sw] names = Swahili [ta] names = Tamil characters = அ ஆ இ ஈ உ ஊ எ ஏ ஐ ஒ ஓ ஔ க ங ச ஞ ட ண த ந ப ம ய ர ல வ ழ ள ற ன ஜ ஶ ஷ ஸ ஹ plural-forms = nplurals=2; plural=n != 1; [te] names = Telugu characters = అ ఆ ఇ ఈ ఉ ఊ ఋ ౠ ఎ ఏ ఐ ఒ ఓ ఔ క ఖ గ ఘ ఙ చ ఛ జ ఝ ఞ ట ఠ డ ఢ ణ త థ ద ధ న ప ఫ బ భ మ య ర ఱ ల వ శ ష స హ ళ plural-forms = nplurals=2; plural=n != 1; principal-territory = IN [tet] names = Tetum principal-territory = ID [tg] names = Tajik characters = а б в г ғ д е ё ж з и ӣ й к қ л м н о п р с т у ӯ ф х ҳ ч ҷ ш ъ э ю я А Б В Г Ғ Д Е Ё Ж З И Ӣ Й К Қ Л М Н О П Р С Т У Ӯ Ф Х Ҳ Ч Ҷ Ш Ъ Э Ю Я plural-forms = nplurals=2; plural=n != 1; principal-territory = TJ [th] names = Thai characters = ก ข ฃ ค ฅ ฆ ง จ ฉ ช ซ ฌ ญ ฎ ฏ ฐ ฑ ฒ ณ ด ต ถ ท ธ น บ ป ผ ฝ พ ฟ ภ ม ย ร ล ว ศ ษ ส ห ฬ อ ฮ plural-forms = nplurals=1; plural=0; principal-territory = TH [ti] names = Tigrinya characters = ሀ ሁ ሂ ሃ ሄ ህ ሆ ለ ሉ ሊ ላ ሌ ል ሎ ሐ ሑ ሒ ሓ ሔ ሕ ሖ መ ሙ ሚ ማ ሜ ም ሞ ሠ ሡ ሢ ሣ ሤ ሥ ሦ ረ ሩ ሪ ራ ሬ ር ሮ ሰ ሱ ሲ ሳ ሴ ስ ሶ ሸ ሹ ሺ ሻ ሼ ሽ ሾ ቀ ቁ ቂ ቃ ቄ ቅ ቆ ቈ ቊ ቋ ቌ ቍ ቐ ቑ ቒ ቓ ቔ ቕ ቖ ቘ ቚ ቛ ቜ ቝ በ ቡ ቢ ባ ቤ ብ ቦ ቨ ቩ ቪ ቫ ቬ ቭ ቮ ተ ቱ ቲ ታ ቴ ት ቶ ቸ ቹ ቺ ቻ ቼ ች ቾ ኀ ኁ ኂ ኃ ኄ ኅ ኆ ኈ ኊ ኋ ኌ ኍ ነ ኑ ኒ ና ኔ ን ኖ ኘ ኙ ኚ ኛ ኜ ኝ ኞ አ ኡ ኢ ኣ ኤ እ ኦ ከ ኩ ኪ ካ ኬ ክ ኮ ኰ ኲ ኳ ኴ ኵ ኸ ኹ ኺ ኻ ኼ ኽ ኾ ዀ ዂ ዃ ዄ ዅ ወ ዉ ዊ ዋ ዌ ው ዎ ዐ ዑ ዒ ዓ ዔ ዕ ዖ ዘ ዙ ዚ ዛ ዜ ዝ ዞ ዠ ዡ ዢ ዣ ዤ ዥ ዦ የ ዩ ዪ ያ ዬ ይ ዮ ደ ዱ ዲ ዳ ዴ ድ ዶ ጀ ጁ ጂ ጃ ጄ ጅ ጆ ገ ጉ ጊ ጋ ጌ ግ ጎ ጐ ጒ ጓ ጔ ጕ ጠ ጡ ጢ ጣ ጤ ጥ ጦ ጨ ጩ ጪ ጫ ጬ ጭ ጮ ጰ ጱ ጲ ጳ ጴ ጵ ጶ ጸ ጹ ጺ ጻ ጼ ጽ ጾ ፀ ፁ ፂ ፃ ፄ ፅ ፆ ፈ ፉ ፊ ፋ ፌ ፍ ፎ ፐ ፑ ፒ ፓ ፔ ፕ ፖ [tig] names = Tigre characters = ሀ ሁ ሂ ሃ ሄ ህ ሆ ለ ሉ ሊ ላ ሌ ል ሎ ሐ ሑ ሒ ሓ ሔ ሕ ሖ መ ሙ ሚ ማ ሜ ም ሞ ረ ሩ ሪ ራ ሬ ር ሮ ሰ ሱ ሲ ሳ ሴ ስ ሶ ሸ ሹ ሺ ሻ ሼ ሽ ሾ ቀ ቁ ቂ ቃ ቄ ቅ ቆ ቈ ቊ ቋ ቌ ቍ በ ቡ ቢ ባ ቤ ብ ቦ ተ ቱ ቲ ታ ቴ ት ቶ ቸ ቹ ቺ ቻ ቼ ች ቾ ኀ ኁ ኂ ኃ ኄ ኅ ኆ ኈ ኊ ኋ ኌ ኍ ነ ኑ ኒ ና ኔ ን ኖ አ ኡ ኢ ኣ ኤ እ ኦ ከ ኩ ኪ ካ ኬ ክ ኮ ኰ ኲ ኳ ኴ ኵ ወ ዉ ዊ ዋ ዌ ው ዎ ዐ ዑ ዒ ዓ ዔ ዕ ዖ ዘ ዙ ዚ ዛ ዜ ዝ ዞ ዠ ዡ ዢ ዣ ዤ ዥ ዦ የ ዩ ዪ ያ ዬ ይ ዮ ደ ዱ ዲ ዳ ዴ ድ ዶ ጀ ጁ ጂ ጃ ጄ ጅ ጆ ገ ጉ ጊ ጋ ጌ ግ ጎ ጐ ጒ ጓ ጔ ጕ ጠ ጡ ጢ ጣ ጤ ጥ ጦ ጨ ጩ ጪ ጫ ጬ ጭ ጮ ጰ ጱ ጲ ጳ ጴ ጵ ጶ ጸ ጹ ጺ ጻ ጼ ጽ ጾ ፈ ፉ ፊ ፋ ፌ ፍ ፎ ፐ ፑ ፒ ፓ ፔ ፕ ፖ [tk] names = Turkmen principal-territory = TM [tl] names = Tagalog characters = (ñ) (Ñ) plural-forms = nplurals=2; plural=n > 1; principal-territory = PH [tlh] names = Klingon tlhIngan-Hol [tn] names = Setswana Tswana [to] names = Tonga principal-territory = TO [tpi] names = Tok Pisin [tr] names = Turkish Türkçe characters = ç ğ ı i ö ş ü Ç Ğ I İ Ö Ş Ü plural-forms = nplurals=1; plural=0; nplurals=2; plural=n != 1; principal-territory = TR [ts] names = Tsonga [tt] names = Tatar characters = а ә б в г д е ё ж җ з и й к л м н ң о ө п р с т у ү ф х һ ц ч ш щ ъ ы ь э ю я А Ә Б В Г Д Е Ё Ж Җ З И Й К Л М Н Ң О Ө П Р С Т У Ү Ф Х Һ Ц Ч Ш Щ Ъ Ы Ь Э Ю Я characters@iqtelif = ç ğ ı í ñ ö ş ü Ç Ğ İ Í Ñ Ö Ş Ü [tvl] names = Tuvalu [tw] names = Twi [ty] names = Tahitian [tyv] names = Tuvinian characters = а б в г д е ё ж з и й к л м н ң о ө п р с т у ү ф х ц ч ш щ ъ ы ь э ю я А Б В Г Д Е Ё Ж З И Й К Л М Н Ң О Ө П Р С Т У Ү Ф Х Ц Ч Ш Щ Ъ Ы Ь Э Ю Я [ug] names = Uighur Uyghur characters = ا ە ب پ ت ج چ خ د ر ز ژ س ش غ ف ق ك گ ڭ ل م ن ھ و ۇ ۆ ۈ ۋ ې ى ي plural-forms = nplurals=1; plural=0; principal-territory = CN [uk] names = Ukrainian characters = а б в г ґ д е є ж з и і ї й к л м н о п р с т у ф х ц ч ш щ ь ю я А Б В Г Ґ Д Е Є Ж З И І Ї Й К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Ь Ю Я plural-forms = nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2; principal-territory = UA [ur] names = Urdu characters = ا ب پ ت ٹ ث ج چ ح خ د ڈ ذ ر ڑ ز ژ س ش ص ض ط ظ ع غ ف ق ک گ ل م ن و ہ ھ ء ی ے plural-forms = nplurals=2; plural=n != 1; principal-territory = PK [uz] names = Uzbek characters = oʻ gʻ ʼ Oʻ Gʻ characters@cyrillic = а б д е э ф г ҳ и ж к л м н о п қ р с т у в х й з ў ғ ш ч ъ ё ю я А Б Д Е Э Ф Г Ҳ И Ж К Л М Н О П Қ Р С Т У В Х Й З Ў Ғ Ш Ч Ё Ю Я principal-territory = UZ [ve] names = Venda principal-territory = ZA [vi] names = Vietnamese characters = à ả ã á ạ ă ằ ẳ ẵ ắ ặ â ầ ẩ ẫ ấ ậ đ è ẻ ẽ é ẹ ê ề ể ễ ế ệ ì ỉ ĩ í ị ò ỏ õ ó ọ ô ồ ổ ỗ ố ộ ơ ờ ở ỡ ớ ợ ù ủ ũ ú ụ ư ừ ử ữ ứ ự ỳ ỷ ỹ ý ỵ À Ả à Á Ạ Ă Ằ Ẳ Ẵ Ắ Ặ  Ầ Ẩ Ẫ Ấ Ậ Đ È Ẻ Ẽ É Ẹ Ê Ề Ể Ễ Ế Ệ Ì Ỉ Ĩ Í Ị Ò Ỏ Õ Ó Ọ Ô Ồ Ổ Ỗ Ố Ộ Ơ Ờ Ở Ỡ Ớ Ợ Ù Ủ Ũ Ú Ụ Ư Ừ Ử Ữ Ứ Ự Ỳ Ỷ Ỹ Ý Ỵ plural-forms = nplurals=1; plural=0; principal-territory = VN [vo] names = Volapük characters = ä ö ü Ä Ö Ü [wa] names = Walloon characters = â å ç è é ê î ô û Â Å Ç È É Ê Î Ô Û principal-territory = BE [wal] names = Wolaitta Wolaytta principal-territory = ET [wo] names = Wolof [xh] names = Xhosa plural-forms = nplurals=2; plural=n != 1; [yi] names = Yiddish [yo] names = Yoruba [za] names = Chuang Zhuang [zh] names = Chinese # The list of Chinese ideograms is incomplete; # only the 100 most often used ones are included here. characters = 保 被 本 表 不 部 查 成 程 出 除 此 存 大 到 的 地 定 度 多 法 方 分 改 格 更 工 果 行 和 或 加 件 建 接 可 了 理 列 面 名 模 目 能 您 其 器 前 取 全 如 入 上 生 失 使 始 式 是 示 所 它 提 通 外 位 未 文 系 下 小 效 新 型 需 序 要 一 移 以 已 用 有 在 找 者 正 支 知 值 指 制 置 中 重 主 字 自 最 作 [zh_CN] names = Chinese (simplified) [zh_HK] names = Chinese (Hong Kong) [zh_TW] names = Chinese (traditional) [zu] names = Zulu # vim:ft=dosini i18nspector-0.25.5/data/iso-codes0000644000000000000000000001105513147102065014672 0ustar0000000000000000# This file has been generated automatically by private/update-iso-codes. # Do not edit. # iso-codes version: 3.66 # Last update: 2016-03-19 [language-codes] aar = aa abk = ab ace = ach = ada = ady = afh = afr = af ain = aka = ak akk = alb = sq ale = alt = amh = am ang = anp = ara = ar arc = arg = an arm = hy arn = arp = arw = asm = as ast = ava = av ave = ae awa = aym = ay aze = az bak = ba bal = bam = bm ban = baq = eu bas = bej = bel = be bem = ben = bn bho = bik = bin = bis = bi bla = bod = bo bos = bs bra = bre = br bua = bug = bul = bg bur = my byn = cad = car = cat = ca ceb = ces = cs cha = ch chb = che = ce chg = chi = zh chk = chm = chn = cho = chp = chr = chu = cu chv = cv chy = cop = cor = kw cos = co cre = cr crh = csb = cym = cy cze = cs dak = dan = da dar = del = den = deu = de dgr = din = div = dv doi = dsb = dua = dum = dut = nl dyu = dzo = dz efi = egy = eka = ell = el elx = eng = en enm = epo = eo est = et eus = eu ewe = ee ewo = fan = fao = fo fas = fa fat = fij = fj fil = fin = fi fon = fra = fr fre = fr frm = fro = frr = frs = fry = fy ful = ff fur = gaa = gay = gba = geo = ka ger = de gez = gil = gla = gd gle = ga glg = gl glv = gv gmh = goh = gon = gor = got = grb = grc = gre = el grn = gn gsw = guj = gu gwi = hai = hat = ht hau = ha haw = heb = he her = hz hil = hin = hi hit = hmn = hmo = ho hrv = hr hsb = hun = hu hup = hye = hy iba = ibo = ig ice = is ido = io iii = ii iku = iu ile = ie ilo = ina = ia ind = id inh = ipk = ik isl = is ita = it jav = jv jbo = jpn = ja jpr = jrb = kaa = kab = kac = kal = kl kam = kan = kn kas = ks kat = ka kau = kr kaw = kaz = kk kbd = kha = khm = km kho = kik = ki kin = rw kir = ky kmb = kok = kom = kv kon = kg kor = ko kos = kpe = krc = krl = kru = kua = kj kum = kur = ku kut = lad = lah = lam = lao = lo lat = la lav = lv lez = lim = li lin = ln lit = lt lol = loz = ltz = lb lua = lub = lu lug = lg lui = lun = luo = lus = mac = mk mad = mag = mah = mh mai = mak = mal = ml man = mao = mi mar = mr mas = may = ms mdf = mdr = men = mga = mic = min = mkd = mk mlg = mg mlt = mt mnc = mni = moh = mon = mn mos = mri = mi msa = ms mus = mwl = mwr = mya = my myv = nap = nau = na nav = nv nbl = nr nde = nd ndo = ng nds = nep = ne new = nia = niu = nld = nl nno = nn nob = nb nog = non = nor = no nqo = nso = nwc = nya = ny nym = nyn = nyo = nzi = oci = oc oji = oj ori = or orm = om osa = oss = os ota = pag = pal = pam = pan = pa pap = pau = peo = per = fa phn = pli = pi pol = pl pon = por = pt pro = pus = ps que = qu raj = rap = rar = roh = rm rom = ron = ro rum = ro run = rn rup = rus = ru sad = sag = sg sah = sam = san = sa sas = sat = scn = sco = sel = sga = shn = sid = sin = si slk = sk slo = sk slv = sl sma = sme = se smj = smn = smo = sm sms = sna = sn snd = sd snk = sog = som = so sot = st spa = es sqi = sq srd = sc srn = srp = sr srr = ssw = ss suk = sun = su sus = sux = swa = sw swe = sv syc = syr = tah = ty tam = ta tat = tt tel = te tem = ter = tet = tgk = tg tgl = tl tha = th tib = bo tig = tir = ti tiv = tkl = tlh = tli = tmh = tog = ton = to tpi = tsi = tsn = tn tso = ts tuk = tk tum = tur = tr tvl = twi = tw tyv = udm = uga = uig = ug ukr = uk umb = urd = ur uzb = uz vai = ven = ve vie = vi vol = vo vot = wal = war = was = wel = cy wln = wa wol = wo xal = xho = xh yao = yap = yid = yi yor = yo zap = zbl = zen = zha = za zho = zh zul = zu zun = zza = [territory-codes] AD = AE = AF = AG = AI = AL = AM = AO = AQ = AR = AS = AT = AU = AW = AX = AZ = BA = BB = BD = BE = BF = BG = BH = BI = BJ = BL = BM = BN = BO = BQ = BR = BS = BT = BV = BW = BY = BZ = CA = CC = CD = CF = CG = CH = CI = CK = CL = CM = CN = CO = CR = CU = CV = CW = CX = CY = CZ = DE = DJ = DK = DM = DO = DZ = EC = EE = EG = EH = ER = ES = ET = FI = FJ = FK = FM = FO = FR = GA = GB = GD = GE = GF = GG = GH = GI = GL = GM = GN = GP = GQ = GR = GS = GT = GU = GW = GY = HK = HM = HN = HR = HT = HU = ID = IE = IL = IM = IN = IO = IQ = IR = IS = IT = JE = JM = JO = JP = KE = KG = KH = KI = KM = KN = KP = KR = KW = KY = KZ = LA = LB = LC = LI = LK = LR = LS = LT = LU = LV = LY = MA = MC = MD = ME = MF = MG = MH = MK = ML = MM = MN = MO = MP = MQ = MR = MS = MT = MU = MV = MW = MX = MY = MZ = NA = NC = NE = NF = NG = NI = NL = NO = NP = NR = NU = NZ = OM = PA = PE = PF = PG = PH = PK = PL = PM = PN = PR = PS = PT = PW = PY = QA = RE = RO = RS = RU = RW = SA = SB = SC = SD = SE = SG = SH = SI = SJ = SK = SL = SM = SN = SO = SR = SS = ST = SV = SX = SY = SZ = TC = TD = TF = TG = TH = TJ = TK = TL = TM = TN = TO = TR = TT = TV = TW = TZ = UA = UG = UM = US = UY = UZ = VA = VC = VE = VG = VI = VN = VU = WF = WS = YE = YT = ZA = ZM = ZW = # vim:ft=dosini i18nspector-0.25.5/data/header-fields0000644000000000000000000000065513147102065015505 0ustar0000000000000000# This file has been generated automatically by # private/update-header-fields. Do not edit. # # The following string extraction tools have been used: # * pygettext.py (xgettext for Python) 1.5 # * xgettext (GNU gettext-tools) 0.19.5.1 Content-Transfer-Encoding Content-Type Generated-By Language Language-Team Last-Translator MIME-Version PO-Revision-Date POT-Creation-Date Plural-Forms Project-Id-Version Report-Msgid-Bugs-To i18nspector-0.25.5/data/encodings0000644000000000000000000000176313147102065014763 0ustar0000000000000000[portable-encodings] # PO files should use only character encodings that are supported by both GNU # libc and GNU libiconv. This section lists all of them. Unfortunately, some of # these encodings are not supported by Python. These are marked as "not-python". # http://git.savannah.gnu.org/cgit/gettext.git/tree/gettext-tools/src/po-charset.c?id=v0.18.3#n57 ASCII = US-ASCII = ANSI_X3.4-1968 = ISO-8859-1 = ISO-8859-2 = ISO-8859-3 = ISO-8859-4 = ISO-8859-5 = ISO-8859-6 = ISO-8859-7 = ISO-8859-8 = ISO-8859-9 = ISO-8859-13 = ISO-8859-14 = ISO-8859-15 = KOI8-R = KOI8-U = KOI8-T = not-python CP850 = CP866 = CP874 = CP932 = CP949 = CP950 = CP1250 = CP1251 = CP1252 = CP1253 = CP1254 = CP1255 = CP1256 = CP1257 = GB2312 = EUC-JP = EUC-KR = EUC-TW = not-python BIG5 = BIG5-HKSCS = GBK = GB18030 = SHIFT_JIS = JOHAB = TIS-620 = VISCII = not-python GEORGIAN-PS = not-python UTF-8 = [extra-encodings] # encodings that are used by real-world PO/MO files, # but are not known to Python KOI8-RU = # vim:ft=dosini i18nspector-0.25.5/data/control-characters0000644000000000000000000000113313147102065016576 0ustar0000000000000000[c0] 00 = NUL 01 = SOH 02 = STX 03 = ETX 04 = EOT 05 = ENQ 06 = ACK 07 = BEL 08 = BS 09 = HT 0a = LF 0b = VT 0c = FF 0d = CR 0e = SO 0f = SI 10 = DLE 11 = DC1 12 = DC2 13 = DC3 14 = DC4 15 = NAK 16 = SYN 17 = ETB 18 = CAN 19 = EM 1a = SUB 1b = ESC 1c = FS 1d = GS 1e = RS 1f = US [del] 7f = DEL [c1] 80 = PAD 81 = HOP 82 = BPH 83 = NBH 84 = IND 85 = NEL 86 = SSA 87 = ESA 88 = HTS 89 = HTJ 8a = VTS 8b = PLD 8c = PLU 8d = RI 8e = SS2 8f = SS3 90 = DCS 91 = PU1 92 = PU2 93 = STS 94 = CCH 95 = MW 96 = SPA 97 = EPA 98 = SOS 99 = SGC 9a = SCI 9b = CSI 9c = ST 9d = OSC 9e = PM 9f = APC # vim:ft=dosini i18nspector-0.25.5/data/charmaps/0000755000000000000000000000000013147102065014656 5ustar0000000000000000i18nspector-0.25.5/data/charmaps/VISCII0000644000000000000000000000074013147102065015570 0ustar0000000000000000ẲẴẪ ỶỸỴ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ẠẮẰẶẤẦẨẬẼẸẾỀỂỄỆỐỒỔỖỘỢỚỜỞỊỎỌỈỦŨỤỲÕắằặấầẩậẽẹếềểễệốồổỗỠƠộờởịỰỨỪỬơớƯÀÁÂÃẢĂẳẵÈÉÊẺÌÍĨỳĐứÒÓÔạỷừửÙÚỹỵÝỡưàáâãảăữẫèéêẻìíĩỉđựòóôõỏọụùúũủýợỮi18nspector-0.25.5/data/charmaps/KOI8-T0000644000000000000000000000064413147102065015520 0ustar0000000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~қғ‚Ғ„…†‡￾‰ҳ‹ҲҷҶ￾Қ‘’“”•–—￾™￾›￾￾￾￾￾ӯӮё¤ӣ¦§￾￾￾«¬­®￾°±²Ё￾Ӣ¶·￾№￾»￾￾￾©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪi18nspector-0.25.5/data/charmaps/KOI8-RU0000644000000000000000000000065513147102065015645 0ustar0000000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓“■∙”—№™ »®«·¤═║╒ёє╔ії╗╘╙╚╛ґў╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪ҐЎ©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪi18nspector-0.25.5/data/charmaps/GEORGIAN-PS0000644000000000000000000000066613147102065016324 0ustar0000000000000000  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿აბგდევზჱთიკლმნჲოპჟრსტჳუფქღყშჩცძწჭხჴჯჰჵæçèéêëìíîïðñòóôõö÷øùúûüýþÿi18nspector-0.25.5/Makefile0000644000000000000000000000415013147102065013607 0ustar0000000000000000# Copyright © 2012-2016 Jakub Wilk # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the “Software”), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. PYTHON = python3 INSTALL = install PREFIX = /usr/local DESTDIR = exe = i18nspector bindir = $(PREFIX)/bin basedir = $(PREFIX)/share/$(exe) mandir = $(PREFIX)/share/man .PHONY: all all: ; .PHONY: install install: # binary: $(INSTALL) -d -m755 $(DESTDIR)$(bindir) python_exe=$$($(PYTHON) -c 'import sys; print(sys.executable)') && \ sed \ -e "1 s@^#!.*@#!$$python_exe@" \ -e "s#^basedir_fallback = .*#basedir_fallback = '$(basedir)/'#" \ $(exe) > $(DESTDIR)$(bindir)/$(exe) chmod 0755 $(DESTDIR)$(bindir)/$(exe) # library + data: ( find lib data -type f ! -name '*.py[co]' ) \ | xargs -t -I {} $(INSTALL) -p -D -m644 {} $(DESTDIR)$(basedir)/{} ifeq "$(wildcard .git doc/$(exe).1)" ".git" # run "make -C doc" to build the manpage else # manual page: $(INSTALL) -p -D -m644 doc/$(exe).1 $(DESTDIR)$(mandir)/man1/$(exe).1 endif .PHONY: test test: $(PYTHON) ./tests/run-tests -v .PHONY: clean clean: find . -type f -name '*.py[co]' -delete find . -type d -name '__pycache__' -delete # vim:ts=4 sts=4 sw=4 noet i18nspector-0.25.5/.pylintrc0000644000000000000000000000131713147102065014016 0ustar0000000000000000[MESSAGES CONTROL] disable = bad-builtin, bad-continuation, duplicate-code, fixme, invalid-name, len-as-condition, locally-disabled, locally-enabled, no-else-return, no-self-use, redefined-variable-type, superfluous-parens, too-few-public-methods, too-many-arguments, too-many-branches, too-many-instance-attributes, too-many-lines, too-many-locals, too-many-nested-blocks, too-many-public-methods, too-many-return-statements, too-many-statements, [REPORTS] reports = no msg-template = {C}: {path}:{line}: {symbol} [{obj}] {msg} [FORMAT] max-line-length = 140 expected-line-ending-format = LF # vim:ft=dosini ts=4 sts=4 sw=4 et i18nspector-0.25.5/.coveragerc0000644000000000000000000000032413147102065014267 0ustar0000000000000000[run] branch = true [report] show_missing = true exclude_lines = # no coverage \A\s+raise misc[.]DataIntegrityError\b \A\s+raise NotImplementedError\b \A\s+pass\Z # vim:ft=dosini ts=4 sts=4 sw=4 et