예제 #1
0
    def testSemiIdenticalCliques(self):
        messages = [
            tclib.Message(
                text='Hello USERNAME',
                placeholders=[tclib.Placeholder('USERNAME', '$1', 'Joi')]),
            tclib.Message(
                text='Hello USERNAME',
                placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi')]),
        ]
        self.failUnless(messages[0].GetId() == messages[1].GetId())

        # Both of the above would share a translation.
        translation = tclib.Translation(
            id=messages[0].GetId(),
            text='Bonjour USERNAME',
            placeholders=[tclib.Placeholder('USERNAME', '$1', 'Joi')])

        factory = clique.UberClique()
        cliques = [factory.MakeClique(msg) for msg in messages]

        for clq in cliques:
            clq.AddTranslation(translation, 'fr')

        self.failUnless(cliques[0].MessageForLanguage('fr').GetRealContent() ==
                        'Bonjour $1')
        self.failUnless(cliques[1].MessageForLanguage('fr').GetRealContent() ==
                        'Bonjour %s')
예제 #2
0
    def Callback(id, structure):
      if id not in self.cliques_:
        if debug: print "Ignoring translation #%s" % id
        return

      if debug: print "Adding translation #%s" % id

      # We fetch placeholder information from the original message (the XTB file
      # only contains placeholder names).
      original_msg = self.BestClique(id).GetMessage()

      translation = tclib.Translation(id=id)
      for is_ph,text in structure:
        if not is_ph:
          translation.AppendText(text)
        else:
          found_placeholder = False
          for ph in original_msg.GetPlaceholders():
            if ph.GetPresentation() == text:
              translation.AppendPlaceholder(tclib.Placeholder(
                ph.GetPresentation(), ph.GetOriginal(), ph.GetExample()))
              found_placeholder = True
              break
          if not found_placeholder:
            raise exception.MismatchingPlaceholders(
              'Translation for message ID %s had <ph name="%s%/>, no match\n'
              'in original message' % (id, text))
      self.FindCliqueAndAddTranslation(translation, lang)
예제 #3
0
 def testValidate(self):
   factory = clique.UberClique()
   msg = tclib.Message(text='Bingo bongo')
   c = factory.MakeClique(msg)
   c.SetCustomType(filename.WindowsFilename())
   translation = tclib.Translation(id=msg.GetId(), text='Bilingo bolongo:')
   c.AddTranslation(translation, 'fr')
   self.failUnless(c.MessageForLanguage('fr').GetRealContent() == 'Bilingo bolongo ')
예제 #4
0
    def testAll(self):
        text = u'Howdie USERNAME'
        phs = [tclib.Placeholder(u'USERNAME', u'%s', 'Joi')]
        msg = tclib.Message(text=text, placeholders=phs)
        self.failUnless(msg.GetPresentableContent() == 'Howdie USERNAME')

        trans = tclib.Translation(text=text, placeholders=phs)
        self.failUnless(trans.GetPresentableContent() == 'Howdie USERNAME')
        self.failUnless(
            isinstance(trans.GetPresentableContent(), types.StringTypes))
예제 #5
0
    def testClique(self):
        factory = clique.UberClique()
        msg = tclib.Message(
            text='Hello USERNAME, how are you?',
            placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi')])
        c = factory.MakeClique(msg)

        self.failUnless(c.GetMessage() == msg)
        self.failUnless(c.GetId() == msg.GetId())

        msg_fr = tclib.Translation(
            text='Bonjour USERNAME, comment ca va?',
            id=msg.GetId(),
            placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi')])
        msg_de = tclib.Translation(
            text='Guten tag USERNAME, wie geht es dir?',
            id=msg.GetId(),
            placeholders=[tclib.Placeholder('USERNAME', '%s', 'Joi')])

        c.AddTranslation(msg_fr, 'fr')
        factory.FindCliqueAndAddTranslation(msg_de, 'de')

        # sort() sorts lists in-place and does not return them
        for lang in ('en', 'fr', 'de'):
            self.failUnless(lang in c.clique)

        self.failUnless(
            c.MessageForLanguage('fr').GetRealContent() ==
            msg_fr.GetRealContent())

        try:
            c.MessageForLanguage('zh-CN', False)
            self.fail('Should have gotten exception')
        except:
            pass

        self.failUnless(c.MessageForLanguage('zh-CN', True) != None)

        rex = re.compile('fr|de|bingo')
        self.failUnless(len(c.AllMessagesThatMatch(rex, False)) == 2)
        self.failUnless(
            c.AllMessagesThatMatch(rex, True)[pseudo.PSEUDO_LANG] is not None)
예제 #6
0
    def AddTranslation(self, translation, language):
        '''Add a translation to this clique.  The translation must have the same
    ID as the message that is the source for this clique.

    If this clique is not translateable, the function just returns.

    Args:
      translation: tclib.Translation()
      language: 'en'

    Throws:
      grit.exception.InvalidTranslation if the translation you're trying to add
      doesn't have the same message ID as the source message of this clique.
    '''
        if not self.translateable:
            return
        if translation.GetId() != self.GetId():
            raise exception.InvalidTranslation(
                'Msg ID %s, transl ID %s' %
                (self.GetId(), translation.GetId()))

        if language in self.clique:
            print(self.GetId())
        assert not language in self.clique

        # Because two messages can differ in the original content of their
        # placeholders yet share the same ID (because they are otherwise the
        # same), the translation we are getting may have different original
        # content for placeholders than our message, yet it is still the right
        # translation for our message (because it is for the same ID).  We must
        # therefore fetch the original content of placeholders from our original
        # English message.
        #
        # See grit.clique_unittest.MessageCliqueUnittest.testSemiIdenticalCliques
        # for a concrete explanation of why this is necessary.

        original = self.MessageForLanguage(self.source_language, False)
        if len(original.GetPlaceholders()) != len(
                translation.GetPlaceholders()):
            print("ERROR: '%s' translation of message id %s does not match" %
                  (language, translation.GetId()))
            assert False

        transl_msg = tclib.Translation(
            id=self.GetId(),
            text=translation.GetPresentableContent(),
            placeholders=original.GetPlaceholders())

        if (self.custom_type and
                not self.custom_type.ValidateAndModify(language, transl_msg)):
            print "WARNING: %s translation failed validation: %s" % (
                language, transl_msg.GetId())

        self.clique[language] = transl_msg
예제 #7
0
 def testRegressionTranslationInherited(self):
     '''Regression tests a bug that was caused by grit.tclib.Translation
 inheriting from the translation console's Translation object
 instead of only owning an instance of it.
 '''
     msg = tclib.Message(text=u"BLA1\r\nFrom: BLA2 \u00fe BLA3",
                         placeholders=[
                             tclib.Placeholder('BLA1', '%s', '%s'),
                             tclib.Placeholder('BLA2', '%s', '%s'),
                             tclib.Placeholder('BLA3', '%s', '%s')
                         ])
     transl = tclib.Translation(text=msg.GetPresentableContent(),
                                placeholders=msg.GetPlaceholders())
     content = transl.GetContent()
     self.failUnless(isinstance(content[3], types.UnicodeType))
예제 #8
0
def update_translation(options, resources, translations, entry):
    comments = [x.strip() for x in entry.comment.splitlines()]

    arguments = dict([x.split(":", 1) for x in comments if ":" in x])
    if VIVALDI_FILE not in arguments:
        return

    if arguments[VIVALDI_FILE].strip().split(".")[-1] != options.vivaldi_file:
        return

    if TRANSLATIONID not in arguments:
        return

    translation = entry.msgstr

    tid = arguments[TRANSLATIONID].strip()
    desc = arguments.get(DESCRIPTION, "").strip()

    if tid in handled_translations:
        return
    handled_translations.add(tid)

    if tid in translations:
        if "translation" in translations[tid]:
            translations[tid]["translation"].parts = [translation]
            translations[tid]["translation"].placeholders = []
        else:
            if "node" in translations[tid]:
                desc = translations[tid]["node"].attrs.get("desc", desc)
            item = tclib.Translation(id=tid,
                                     text=translation,
                                     description=desc)
            translations[tid]["translations"] = item
    else:
        item = tclib.Translation(id=tid, text=translation, description=desc)
        translations.setdefault(tid, {})["translations"] = item
예제 #9
0
def ToTranslation(tree, placeholders):
  """Converts the tree back to a translation, substituting the placeholders
  back in as required.
  """
  text = tree.ToString()
  assert text.count(PLACEHOLDER_STRING) == len(placeholders)
  transl = tclib.Translation()
  for placeholder in placeholders:
    index = text.find(PLACEHOLDER_STRING)
    if index > 0:
      transl.AppendText(text[:index])
    text = text[index + len(PLACEHOLDER_STRING):]
    transl.AppendPlaceholder(placeholder)
  if text:
    transl.AppendText(text)
  return transl
예제 #10
0
def PseudoRTLMessage(message):
    '''Returns a pseudo-RTL (aka Fake-Bidi) translation of the provided message.

  Args:
    message: tclib.Message()

  Return:
    tclib.Translation()
  '''
    transl = tclib.Translation()
    for part in message.GetContent():
        if isinstance(part, tclib.Placeholder):
            transl.AppendPlaceholder(part)
        else:
            transl.AppendText(PseudoRTLString(part))

    return transl
예제 #11
0
  def testCustomTypes(self):
    factory = clique.UberClique()
    message = tclib.Message(text='Bingo bongo')
    c = factory.MakeClique(message)
    try:
      c.SetCustomType(DummyCustomType())
      self.fail()
    except:
      pass  # expected case - 'Bingo bongo' does not start with 'jjj'

    message = tclib.Message(text='jjjBingo bongo')
    c = factory.MakeClique(message)
    c.SetCustomType(util.NewClassInstance(
      'grit.clique_unittest.DummyCustomType', clique.CustomType))
    translation = tclib.Translation(id=message.GetId(), text='Bilingo bolongo')
    c.AddTranslation(translation, 'fr')
    self.failUnless(c.MessageForLanguage('fr').GetRealContent().startswith('jjj'))
예제 #12
0
class MessageClique(object):
  '''A message along with all of its translations.  Also code to bring
  translations together with their original message.'''

  # change this to the language code of Messages you add to cliques_.
  # TODO(joi) Actually change this based on the <grit> node's source language
  source_language = 'en'

  # A constant translation we use when asked for a translation into the
  # special language constants.CONSTANT_LANGUAGE.
  CONSTANT_TRANSLATION = tclib.Translation(text='TTTTTT')

  def __init__(self, uber_clique, message, translateable=True, custom_type=None):
    '''Create a new clique initialized with just a message.

    Args:
      uber_clique: Our uber-clique (collection of cliques)
      message: tclib.Message()
      translateable: True | False
      custom_type: instance of clique.CustomType interface
    '''
    # Our parent
    self.uber_clique = uber_clique
    # If not translateable, we only store the original message.
    self.translateable = translateable
    # A mapping of language identifiers to tclib.BaseMessage and its
    # subclasses (i.e. tclib.Message and tclib.Translation).
    self.clique = { MessageClique.source_language : message }
    # A list of the "shortcut groups" this clique is
    # part of.  Within any given shortcut group, no shortcut key (e.g. &J)
    # must appear more than once in each language for all cliques that
    # belong to the group.
    self.shortcut_groups = []
    # An instance of the CustomType interface, or None.  If this is set, it will
    # be used to validate the original message and translations thereof, and
    # will also get a chance to modify translations of the message.
    self.SetCustomType(custom_type)

  def GetMessage(self):
    '''Retrieves the tclib.Message that is the source for this clique.'''
    return self.clique[MessageClique.source_language]

  def GetId(self):
    '''Retrieves the message ID of the messages in this clique.'''
    return self.GetMessage().GetId()

  def IsTranslateable(self):
    return self.translateable

  def AddToShortcutGroup(self, group):
    self.shortcut_groups.append(group)

  def SetCustomType(self, custom_type):
    '''Makes this clique use custom_type for validating messages and
    translations, and optionally modifying translations.
    '''
    self.custom_type = custom_type
    if custom_type and not custom_type.Validate(self.GetMessage()):
      raise exception.InvalidMessage(self.GetMessage().GetRealContent())

  def MessageForLanguage(self, lang, pseudo_if_no_match=True, fallback_to_english=False):
    '''Returns the message/translation for the specified language, providing
    a pseudotranslation if there is no available translation and a pseudo-
    translation is requested.

    The translation of any message whatsoever in the special language
    'x_constant' is the message "TTTTTT".

    Args:
      lang: 'en'
      pseudo_if_no_match: True
      fallback_to_english: False

    Return:
      tclib.BaseMessage
    '''
    if not self.translateable:
      return self.GetMessage()

    if lang == constants.CONSTANT_LANGUAGE:
      return self.CONSTANT_TRANSLATION

    for msglang in self.clique.keys():
      if lang == msglang:
        return self.clique[msglang]

    if lang == constants.FAKE_BIDI:
      return pseudo_rtl.PseudoRTLMessage(self.GetMessage())

    if fallback_to_english:
      self.uber_clique._AddMissingTranslation(lang, self, is_error=False)
      return self.GetMessage()

    # If we're not supposed to generate pseudotranslations, we add an error
    # report to a list of errors, then fail at a higher level, so that we
    # get a list of all messages that are missing translations.
    if not pseudo_if_no_match:
      self.uber_clique._AddMissingTranslation(lang, self, is_error=True)

    return pseudo.PseudoMessage(self.GetMessage())

  def AllMessagesThatMatch(self, lang_re, include_pseudo = True):
    '''Returns a map of all messages that match 'lang', including the pseudo
    translation if requested.

    Args:
      lang_re: re.compile('fr|en')
      include_pseudo: True

    Return:
      { 'en' : tclib.Message,
        'fr' : tclib.Translation,
        pseudo.PSEUDO_LANG : tclib.Translation }
    '''
    if not self.translateable:
      return [self.GetMessage()]

    matches = {}
    for msglang in self.clique:
      if lang_re.match(msglang):
        matches[msglang] = self.clique[msglang]

    if include_pseudo:
      matches[pseudo.PSEUDO_LANG] = pseudo.PseudoMessage(self.GetMessage())

    return matches

  def AddTranslation(self, translation, language):
    '''Add a translation to this clique.  The translation must have the same
    ID as the message that is the source for this clique.

    If this clique is not translateable, the function just returns.

    Args:
      translation: tclib.Translation()
      language: 'en'

    Throws:
      grit.exception.InvalidTranslation if the translation you're trying to add
      doesn't have the same message ID as the source message of this clique.
    '''
    if not self.translateable:
      return
    if translation.GetId() != self.GetId():
      raise exception.InvalidTranslation(
        'Msg ID %s, transl ID %s' % (self.GetId(), translation.GetId()))

    assert not language in self.clique

    # Because two messages can differ in the original content of their
    # placeholders yet share the same ID (because they are otherwise the
    # same), the translation we are getting may have different original
    # content for placeholders than our message, yet it is still the right
    # translation for our message (because it is for the same ID).  We must
    # therefore fetch the original content of placeholders from our original
    # English message.
    #
    # See grit.clique_unittest.MessageCliqueUnittest.testSemiIdenticalCliques
    # for a concrete explanation of why this is necessary.

    original = self.MessageForLanguage(self.source_language, False)
    if len(original.GetPlaceholders()) != len(translation.GetPlaceholders()):
      print ("ERROR: '%s' translation of message id %s does not match" %
             (language, translation.GetId()))
      assert False

    transl_msg = tclib.Translation(id=self.GetId(),
                                   text=translation.GetPresentableContent(),
                                   placeholders=original.GetPlaceholders())

    if self.custom_type and not self.custom_type.ValidateAndModify(language, transl_msg):
      print "WARNING: %s translation failed validation: %s" % (
        language, transl_msg.GetId())

    self.clique[language] = transl_msg