예제 #1
0
 def test_copy_message_replaces_string(self):
     old_message = Message("id", string="a", locations=[("file1", "2")])
     new_message = copy_message(old_message, string="b")
     expected_message = Message("id",
                                string="b",
                                locations=[("file1", "2")])
     assert_messages_deeply_equal(new_message, expected_message)
예제 #2
0
파일: test_l10n.py 프로젝트: tekd/noi2
def test_checker_works():
    m = Message(id=u'hello', string=u'hello %(num)d')
    errors = [err for err in m.check()]
    eq_(len(errors), 1)
    eq_(
        str(errors[0]), 'Translation contains named placeholder but '
        'source doesn\'t: hello %(num)d')
예제 #3
0
 def test_find_corresponding_message_exists(self):
     catalog = Catalog()
     catalog.add("id", string="Text")
     corresponding = find_corresponding_message(catalog, Message("id"))
     self.assertTrue(corresponding)
     assert_messages_deeply_equal(corresponding, catalog.get("id"))
     self.assertEqual(find_corresponding_string(catalog, Message("id")),
                      "Text")
예제 #4
0
 def test_find_corresponding_message_not_exists(self):
     catalog = Catalog()
     catalog.add("id", string="Text")
     corresponding = find_corresponding_message(catalog,
                                                Message("other id"))
     self.assertIsNone(corresponding)
     self.assertIsNone(
         find_corresponding_string(catalog, Message("other id")))
예제 #5
0
파일: pofile.py 프로젝트: Liu0330/zufang
 def _add_message(self):
     """
     Add a message to the catalog based on the current parser state and
     clear the state ready to process the next message.
     """
     self.translations.sort()
     if len(self.messages) > 1:
         msgid = tuple([m.denormalize() for m in self.messages])
     else:
         msgid = self.messages[0].denormalize()
     if isinstance(msgid, (list, tuple)):
         string = ['' for _ in range(self.catalog.num_plurals)]
         for idx, translation in self.translations:
             if idx >= self.catalog.num_plurals:
                 self._invalid_pofile("", self.offset, "msg has more translations than num_plurals of catalog")
                 continue
             string[idx] = translation.denormalize()
         string = tuple(string)
     else:
         string = self.translations[0][1].denormalize()
     if self.context:
         msgctxt = self.context.denormalize()
     else:
         msgctxt = None
     message = Message(msgid, string, list(self.locations), set(self.flags),
                       self.auto_comments, self.user_comments, lineno=self.offset + 1,
                       context=msgctxt)
     if self.obsolete:
         if not self.ignore_obsolete:
             self.catalog.obsolete[msgid] = message
     else:
         self.catalog[msgid] = message
     self.counter += 1
     self._reset_message_state()
예제 #6
0
파일: 04_pot.py 프로젝트: sveetch/Optimus
def test_build_pot(minimal_i18n_settings, temp_builds_dir, fixtures_settings):
    """
    Force to rebuild POT file
    """
    basepath = temp_builds_dir.join("i18n_build_pot")

    # Copy sample project to temporary dir
    samplename = "minimal_i18n"
    samplepath = os.path.join(fixtures_settings.fixtures_path, samplename)
    destination = os.path.join(basepath.strpath, samplename)
    shutil.copytree(samplepath, destination)

    # Get settings
    settings = minimal_i18n_settings(destination)

    manager = I18NManager(settings)

    pot = manager.build_pot(force=True)

    assert pot.header_comment == ("""# Translations template for """
                                  """minimal_i18n project"""
                                  """\n# Created by Optimus""")

    assert ("Hello World!" in pot) is True

    assert pot["Hello World!"] == Message("Hello World!")
예제 #7
0
파일: 04_pot.py 프로젝트: sveetch/Optimus
def test_pot_attribute_getter(minimal_i18n_settings, temp_builds_dir,
                              fixtures_settings):
    """
    Reach the pot attribute that may trigger the build_pot when
    POT does not allready exists
    """
    basepath = temp_builds_dir.join("i18n_pot_attribute_getter")

    # Copy sample project to temporary dir
    samplename = "minimal_i18n"
    samplepath = os.path.join(fixtures_settings.fixtures_path, samplename)
    destination = os.path.join(basepath.strpath, samplename)
    shutil.copytree(samplepath, destination)

    # Get settings
    settings = minimal_i18n_settings(destination)

    manager = I18NManager(settings)

    # Remove locale dir so the POT doesnt exists anymore
    shutil.rmtree(settings.LOCALES_DIR)

    # Recreate just locale base dir
    os.makedirs(settings.LOCALES_DIR)

    # Access pot through pot attribute
    pot = manager.pot

    assert pot.header_comment == ("""# Translations template for """
                                  """minimal_i18n project"""
                                  """\n# Created by Optimus""")

    assert ("Hello World!" in pot) is True

    assert pot["Hello World!"] == Message("Hello World!")
예제 #8
0
def validate(message: Message, catalog: Catalog) -> List[str]:
    errors = _validate_fuzzy(message)
    errors.extend([f'    {str(err)}' for err in message.check(catalog)])
    if message.python_format and not message.pluralizable and message.string:
        errors.extend(_validate_cfmt(message.id, message.string))

    return errors
예제 #9
0
    def test_po_with_multiline_obsolete_message(self):
        catalog = Catalog()
        catalog.add(u'foo', u'Voh', locations=[('main.py', 1)])
        msgid = r"""Here's a message that covers
multiple lines, and should still be handled
correctly.
"""
        msgstr = r"""Here's a message that covers
multiple lines, and should still be handled
correctly.
"""
        catalog.obsolete[msgid] = Message(msgid, msgstr,
                                          locations=[('utils.py', 3)])
        buf = BytesIO()
        pofile.write_po(buf, catalog, omit_header=True)
        self.assertEqual(b'''#: main.py:1
msgid "foo"
msgstr "Voh"

#~ msgid ""
#~ "Here's a message that covers\\n"
#~ "multiple lines, and should still be handled\\n"
#~ "correctly.\\n"
#~ msgstr ""
#~ "Here's a message that covers\\n"
#~ "multiple lines, and should still be handled\\n"
#~ "correctly.\\n"''', buf.getvalue().strip())
예제 #10
0
 def _add_message():
     translations.sort()
     if len(messages) > 1:
         msgid = tuple([denormalize(m) for m in messages])
     else:
         msgid = denormalize(messages[0])
     if isinstance(msgid, (list, tuple)):
         string = []
         for idx in range(catalog.num_plurals):
             try:
                 string.append(translations[idx])
             except IndexError:
                 string.append((idx, ''))
         string = tuple([denormalize(t[1]) for t in string])
     else:
         string = denormalize(translations[0][1])
     if context:
         msgctxt = denormalize('\n'.join(context))
     else:
         msgctxt = None
     message = Message(msgid, string, list(locations), set(flags),
                       auto_comments, user_comments, lineno=offset[0] + 1,
                       context=msgctxt)
     if obsolete[0]:
         if not ignore_obsolete:
             catalog.obsolete[msgid] = message
     else:
         catalog[msgid] = message
     del messages[:]; del translations[:]; del context[:]; del locations[:];
     del flags[:]; del auto_comments[:]; del user_comments[:];
     obsolete[0] = False
     counter[0] += 1
예제 #11
0
    def test_add_or_update_message_update(self):
        target_catalog = Catalog()
        target_catalog.add("id1", string="Text1")

        add_or_update_message(target_catalog, Message("id1", string="Text2"))

        expected_catalog = Catalog()
        expected_catalog.add("id1", string="Text2")

        assert_catalogs_deeply_equal(target_catalog, expected_catalog)
예제 #12
0
def xgettext_yaml(filelist, outputfilename):
    output = open(outputfilename, 'wb')
    print output, outputfilename
    cat = Catalog()
    for f in open(filelist, 'rb').readlines():
        f = f.strip()
        assert os.path.isfile(f), f
        for s, lineno in yield_translatable_yaml_strings(f):
            cat[s] = Message(s, locations=[(f, lineno)])
    write_po(output, cat, width=None, sort_by_file=True)
예제 #13
0
    def test_po_with_obsolete_message_ignored(self):
        catalog = Catalog()
        catalog.add(u'foo', u'Voh', locations=[('main.py', 1)])
        catalog.obsolete['bar'] = Message(u'bar', u'Bahr',
                                          locations=[('utils.py', 3)],
                                          user_comments=['User comment'])
        buf = BytesIO()
        pofile.write_po(buf, catalog, omit_header=True, ignore_obsolete=True)
        self.assertEqual(b'''#: main.py:1
msgid "foo"
msgstr "Voh"''', buf.getvalue().strip())
예제 #14
0
def test_overwrite_po_success(minimal_i18n_settings, temp_builds_dir,
                              fixtures_settings):
    """
    safe_write_po usage for overwritting file
    """
    basepath = temp_builds_dir.join("i18n_overwrite_po_success")

    # Copy sample project to temporary dir
    samplename = "minimal_i18n"
    samplepath = os.path.join(fixtures_settings.fixtures_path, samplename)
    destination = os.path.join(basepath.strpath, samplename)
    shutil.copytree(samplepath, destination)

    dummy_name = "dummy_pot.pot"
    dummy_pot = os.path.join(destination, dummy_name)

    # Get manager with settings
    settings = minimal_i18n_settings(destination)
    manager = I18NManager(settings)

    # Create a dummy catalog to write
    catalog = Catalog(header_comment="# Foobar")
    catalog.add("foo %(name)s", locations=[("main.py", 1)], flags=("fuzzy", ))

    # Write it
    manager.safe_write_po(catalog, dummy_pot)

    # Check it
    with io.open(dummy_pot, "rb") as f:
        dummy_catalog = read_po(f)

    assert dummy_catalog.header_comment == "# Foobar"

    # New dummy catalog to overwrite previous one
    catalog = Catalog(header_comment="# Zob")
    catalog.add("ping", string="pong", locations=[("nope.py", 42)])

    # Write it
    manager.safe_write_po(catalog, dummy_pot)

    # List existing pot file at root
    pots = [item for item in os.listdir(destination) if item.endswith(".pot")]
    # No other pot file
    assert pots == [dummy_name]

    # Check it again
    with io.open(dummy_pot, "rb") as f:
        dummy_catalog = read_po(f)

    assert dummy_catalog.header_comment == "# Zob"
    assert dummy_catalog["ping"] == Message("ping", string="pong")
예제 #15
0
def copy_message(message: Message, **kwargs) -> Message:
    """Copies a message, replacing any of its attributes given in kwargs"""
    return Message(
        **{
            "id": kwargs.get("id", message.id),
            "context": kwargs.get("context", message.context),
            "string": kwargs.get("string", message.string),
            "flags": kwargs.get("flags", message.flags),
            "locations": kwargs.get("locations", message.locations),
            "user_comments": kwargs.get("user_comments",
                                        message.user_comments),
            "auto_comments": kwargs.get("auto_comments",
                                        message.auto_comments),
        })
예제 #16
0
 def test_sign_in(self):
     fake_msg = Message('Email address verification - Liberapay', 'Vous avez du pain ?')
     LOCALES['fr'].catalog[fake_msg.id].string = fake_msg.string
     r = self.sign_in(HTTP_ACCEPT_LANGUAGE='fr')
     assert r.code == 302, r.text
     assert SESSION in r.headers.cookie
     # Check that an email was sent, in the user's preferred language
     Participant.dequeue_emails()
     last_email = self.get_last_email()
     username = good_data['sign-in.username']
     assert last_email['subject'] == fake_msg.string
     # Check that the new user has an avatar
     p = Participant.from_username(username)
     assert p.avatar_url
예제 #17
0
 def _add_message(self):
     """
     Add a message to the catalog based on the current parser state and
     clear the state ready to process the next message.
     """
     self.translations.sort()
     if len(self.messages) > 1:
         msgid = tuple([denormalize(m) for m in self.messages])
     else:
         msgid = denormalize(self.messages[0])
     if isinstance(msgid, (list, tuple)):
         string = []
         for idx in range(self.catalog.num_plurals):
             try:
                 string.append(self.translations[idx])
             except IndexError:
                 string.append((idx, ''))
         string = tuple([denormalize(t[1]) for t in string])
     else:
         string = denormalize(self.translations[0][1])
     if self.context:
         msgctxt = denormalize('\n'.join(self.context))
     else:
         msgctxt = None
     message = Message(msgid,
                       string,
                       list(self.locations),
                       set(self.flags),
                       self.auto_comments,
                       self.user_comments,
                       lineno=self.offset + 1,
                       context=msgctxt)
     if self.obsolete:
         if not self.ignore_obsolete:
             self.catalog.obsolete[msgid] = message
     else:
         self.catalog[msgid] = message
     del self.messages[:]
     del self.translations[:]
     del self.context[:]
     del self.locations[:]
     del self.flags[:]
     del self.auto_comments[:]
     del self.user_comments[:]
     self.obsolete = False
     self.counter += 1
예제 #18
0
    def test_po_with_obsolete_message(self):
        catalog = Catalog()
        catalog.add(u('foo'), u('Voh'), locations=[('main.py', 1)])
        catalog.obsolete['bar'] = Message(u('bar'),
                                          u('Bahr'),
                                          locations=[('utils.py', 3)],
                                          user_comments=['User comment'])
        buf = BytesIO()
        pofile.write_po(buf, catalog, omit_header=True)
        self.assertEqual(
            b('''#: main.py:1
msgid "foo"
msgstr "Voh"

# User comment
#~ msgid "bar"
#~ msgstr "Bahr"'''),
            buf.getvalue().strip())
예제 #19
0
    def test_po_with_obsolete_message(self):
        catalog = Catalog()
        catalog.add(u'foo', u'Voh', locations=[('main.py', 1)])
        catalog.obsolete['bar'] = Message(u'bar', u'Bahr',
                                          locations=[('utils.py', 3)],
                                          flags=['fuzzy'],
                                          extracted_comments=['Developer Comment'],
                                          translator_comments=['User comment'],
                                          previous_id=u'foo',
                                          previous_context='previous context',
                                          context='context')
        buf = BytesIO()
        pofile.write_po(buf, catalog, omit_header=True)
        self.assertEqual(b'''#: main.py:1
msgid "foo"
msgstr "Voh"

# User comment
#. Developer Comment
#: utils.py:3
#, fuzzy
#~ msgctxt "context"
#~ msgid "bar"
#~ msgstr "Bahr"''', buf.getvalue().strip())

        buf = BytesIO()
        pofile.write_po(buf, catalog, omit_header=True, include_previous=True)
        self.assertEqual(b'''#: main.py:1
msgid "foo"
msgstr "Voh"

# User comment
#. Developer Comment
#: utils.py:3
#, fuzzy
#| msgctxt "previous context"
#| msgid "foo"
#~ msgctxt "context"
#~ msgid "bar"
#~ msgstr "Bahr"''', buf.getvalue().strip())
예제 #20
0
def test_clone_pot(minimal_i18n_settings, temp_builds_dir, fixtures_settings):
    """
    Check POT cloning
    """
    basepath = temp_builds_dir.join("i18n_clone_pot")

    # Copy sample project to temporary dir
    samplename = "minimal_i18n"
    samplepath = os.path.join(fixtures_settings.fixtures_path, samplename)
    destination = os.path.join(basepath.strpath, samplename)
    shutil.copytree(samplepath, destination)

    # Get manager with settings
    settings = minimal_i18n_settings(destination)
    manager = I18NManager(settings)
    manager.build_pot(force=True)

    cloned = manager.clone_pot()

    assert cloned.header_comment == ("""# Translations template for """
                                     """minimal_i18n project"""
                                     """\n# Created by Optimus""")
    assert ("Hello World!" in cloned) is True
    assert cloned["Hello World!"] == Message("Hello World!")
예제 #21
0
파일: test_l10n.py 프로젝트: GovLab/noi2
def test_checker_works():
    m = Message(id=u'hello', string=u'hello %(num)d')
    errors = [err for err in m.check()]
    eq_(len(errors), 1)
    eq_(str(errors[0]), 'Translation contains named placeholder but '
                        'source doesn\'t: hello %(num)d')
예제 #22
0
 def test_message_unique_identifier_with_context(self):
     self.assertEqual(
         message_unique_identifier(
             Message("id", string="Text", context="ctxt")),
         ("id", "ctxt"),
     )
예제 #23
0
 def test_message_unique_identifier_no_context(self):
     self.assertEqual(
         message_unique_identifier(Message("id", string="Text")), "id")
예제 #24
0
def read_mo(fileobj):
    """Read a binary MO file from the given file-like object and return a
    corresponding `Catalog` object.

    :param fileobj: the file-like object to read the MO file from

    :note: The implementation of this function is heavily based on the
           ``GNUTranslations._parse`` method of the ``gettext`` module in the
           standard library.
    """
    catalog = Catalog()
    headers = {}

    filename = getattr(fileobj, 'name', '')

    buf = fileobj.read()
    buflen = len(buf)
    unpack = struct.unpack

    # Parse the .mo file header, which consists of 5 little endian 32
    # bit words.
    magic = unpack('<I', buf[:4])[0]  # Are we big endian or little endian?
    if magic == LE_MAGIC:
        version, msgcount, origidx, transidx = unpack('<4I', buf[4:20])
        ii = '<II'
    elif magic == BE_MAGIC:
        version, msgcount, origidx, transidx = unpack('>4I', buf[4:20])
        ii = '>II'
    else:
        raise IOError(0, 'Bad magic number', filename)

    # Now put all messages from the .mo file buffer into the catalog
    # dictionary
    for i in range_type(0, msgcount):
        mlen, moff = unpack(ii, buf[origidx:origidx + 8])
        mend = moff + mlen
        tlen, toff = unpack(ii, buf[transidx:transidx + 8])
        tend = toff + tlen
        if mend < buflen and tend < buflen:
            msg = buf[moff:mend]
            tmsg = buf[toff:tend]
        else:
            raise IOError(0, 'File is corrupt', filename)

        # See if we're looking at GNU .mo conventions for metadata
        if mlen == 0:
            # Catalog description
            lastkey = key = None
            for item in tmsg.splitlines():
                item = item.strip()
                if not item:
                    continue
                if b':' in item:
                    key, value = item.split(b':', 1)
                    lastkey = key = key.strip().lower()
                    headers[key] = value.strip()
                elif lastkey:
                    headers[lastkey] += b'\n' + item

        if b'\x04' in msg:  # context
            ctxt, msg = msg.split(b'\x04')
        else:
            ctxt = None

        if b'\x00' in msg:  # plural forms
            msg = msg.split(b'\x00')
            tmsg = tmsg.split(b'\x00')
            if catalog.charset:
                msg = [x.decode(catalog.charset) for x in msg]
                tmsg = [x.decode(catalog.charset) for x in tmsg]
        else:
            if catalog.charset:
                msg = msg.decode(catalog.charset)
                tmsg = tmsg.decode(catalog.charset)
        catalog[msg] = Message(msg, tmsg, context=ctxt)

        # advance to next entry in the seek tables
        origidx += 8
        transidx += 8

    catalog.mime_headers = headers.items()
    return catalog
예제 #25
0
    def test_po_with_multiline_obsolete_message(self):
        catalog = Catalog()
        catalog.add(u'foo', u'Voh', locations=[('main.py', 1)])
        msgid = r"""Here's a message that covers
multiple lines, and should still be handled
correctly.
"""
        msgstr = r"""Here's a message that covers
multiple lines, and should still be handled
correctly.
"""
        extracted_comment = r"""Here's a developer comment that covers
multiple lines, and should still be handled
correctly.
"""
        translator_comment = r"""Here's a user comment that covers
multiple lines, and should still be handled
correctly.
"""
        previous_id = r"""Here's a previous message that covers
multiple lines, and should still be handled
correctly.
"""
        previous_context = r"""Here's a previous context that covers
multiple lines, and should still be handled
correctly.
"""
        context = r"""Here's a context that covers
multiple lines, and should still be handled
correctly.
"""
        catalog.obsolete[msgid] = Message(msgid, msgstr,
                                          locations=[('utils.py', 3)],
                                          flags=['fuzzy'],
                                          extracted_comments=[extracted_comment],
                                          translator_comments=[translator_comment],
                                          previous_id=previous_id,
                                          previous_context=previous_context,
                                          context=context)
        buf = BytesIO()
        pofile.write_po(buf, catalog, omit_header=True)
        self.assertEqual(b'''#: main.py:1
msgid "foo"
msgstr "Voh"

# Here's a user comment that covers multiple lines, and should still be
# handled correctly.
#. Here's a developer comment that covers multiple lines, and should still be
#. handled correctly.
#: utils.py:3
#, fuzzy
#~ msgctxt ""
#~ "Here's a context that covers\\n"
#~ "multiple lines, and should still be handled\\n"
#~ "correctly.\\n"
#~ msgid ""
#~ "Here's a message that covers\\n"
#~ "multiple lines, and should still be handled\\n"
#~ "correctly.\\n"
#~ msgstr ""
#~ "Here's a message that covers\\n"
#~ "multiple lines, and should still be handled\\n"
#~ "correctly.\\n"''', buf.getvalue().strip())

        buf = BytesIO()
        pofile.write_po(buf, catalog, omit_header=True, include_previous=True)
        self.assertEqual(b'''#: main.py:1
msgid "foo"
msgstr "Voh"

# Here's a user comment that covers multiple lines, and should still be
# handled correctly.
#. Here's a developer comment that covers multiple lines, and should still be
#. handled correctly.
#: utils.py:3
#, fuzzy
#| msgctxt ""
#| "Here's a previous context that covers\\n"
#| "multiple lines, and should still be handled\\n"
#| "correctly.\\n"
#| msgid ""
#| "Here's a previous message that covers\\n"
#| "multiple lines, and should still be handled\\n"
#| "correctly.\\n"
#~ msgctxt ""
#~ "Here's a context that covers\\n"
#~ "multiple lines, and should still be handled\\n"
#~ "correctly.\\n"
#~ msgid ""
#~ "Here's a message that covers\\n"
#~ "multiple lines, and should still be handled\\n"
#~ "correctly.\\n"
#~ msgstr ""
#~ "Here's a message that covers\\n"
#~ "multiple lines, and should still be handled\\n"
#~ "correctly.\\n"''', buf.getvalue().strip())