Пример #1
0
 def _handle_pairs_of_parts_and_bodies(self):
   try:
     locales_to_bodies = {}
     locales_to_fields = {}
     locale = self.doc._locale_kwarg
     default_locale = None
     split_content = Format.split_front_matter(self.content)
     for part, body in utils.every_two(split_content):
       fields = utils.load_yaml(part, pod=self.doc.pod)
       if '$locale' in fields and '$locales' in fields:
         text = 'You must specify either $locale or $locales, not both.'
         raise BadFormatError(text)
       if '$locales' in fields:
         doc_locales = fields['$locales']
       else:
         doc_locales = [fields.get('$locale', default_locale)]
       for doc_locale in doc_locales:
         locales_to_fields[doc_locale] = fields
         locales_to_bodies[doc_locale] = body
     fields = locales_to_fields.get(default_locale)
     if locale in locales_to_fields:
       localized_fields = locales_to_fields[locale]
       if fields is None:
         fields = {}
       fields.update(localized_fields)
     default_body = locales_to_bodies.get(default_locale)
     self.body = locales_to_bodies.get(locale, default_body)
     self.body = self.body.strip() if self.body is not None else None
     self.fields = fields
   except (yaml.composer.ComposerError, yaml.scanner.ScannerError) as e:
     message = 'Error parsing {}: {}'.format(self.doc.pod_path, e)
     logging.exception(message)
     raise BadFormatError(message)
Пример #2
0
 def _load_yaml(self, part):
     try:
         return utils.load_yaml(part, doc=self.doc, pod=self.doc.pod)
     except (yaml.parser.ParserError, yaml.composer.ComposerError,
             yaml.scanner.ScannerError) as e:
         message = 'Error parsing {}: {}'.format(self.doc.pod_path, e)
         raise BadFormatError(message)
Пример #3
0
 def _load_yaml(self, part):
     try:
         return utils.load_yaml(part, doc=self.doc, pod=self.doc.pod)
     except (yaml.parser.ParserError,
             yaml.composer.ComposerError,
             yaml.scanner.ScannerError) as e:
         message = 'Error parsing {}: {}'.format(self.doc.pod_path, e)
         raise BadFormatError(message)
Пример #4
0
 def load(self):
   try:
     if not self.has_front_matter:
       self.fields = utils.load_yaml(self.content, pod=self.doc.pod)
       self.body = self.content
       return
     self._handle_pairs_of_parts_and_bodies()
   except (yaml.composer.ComposerError, yaml.scanner.ScannerError) as e:
     message = 'Error parsing {}: {}'.format(self.doc.pod_path, e)
     logging.exception(message)
     raise BadFormatError(message)
Пример #5
0
 def load(self):
     try:
         if self._has_front_matter:
             self._handle_pairs_of_parts_and_bodies()
         else:
             self.body = self.content
             self.fields = utils.load_yaml(
                 self.content, doc=self.doc, pod=self.doc.pod) or {}
     except (yaml.composer.ComposerError, yaml.scanner.ScannerError) as e:
         message = 'Error parsing {}: {}'.format(self.doc.pod_path, e)
         logging.exception(message)
         raise BadFormatError(message)
Пример #6
0
 def load(self):
   if not self.has_front_matter:
     self.fields = utils.load_yaml(self.content, pod=self.doc.pod)
     self.body = self.content
     return
   locales_to_fields = {}
   locales_to_bodies = {}
   locale = str(self.doc.locale)
   default_locale = str(self.doc.default_locale)
   for part in Format.split_front_matter(self.content):
     fields = utils.load_yaml(part, pod=self.doc.pod)
     doc_locale = fields.get('$locale', default_locale)
     locales_to_fields[doc_locale] = fields
     locales_to_bodies[doc_locale] = part
   fields = locales_to_fields.get(default_locale)
   if locale in locales_to_fields:
     localized_fields = locales_to_fields[locale]
     if fields is None:
       fields = {}
     fields.update(localized_fields)
   self.body = locales_to_bodies.get(locale, locales_to_bodies.get(default_locale))
   self.body = self.body.strip() if self.body is not None else None
   self.fields = fields
Пример #7
0
 def _load_yaml(self, raw_yaml):
     try:
         return utils.load_yaml(
             raw_yaml, doc=self._doc, pod=self._doc.pod,
             untag_params={
                 'env': untag.UntagParamRegex(self._doc.pod.env.name),
                 'locale': untag.UntagParamLocaleRegex.from_pod(
                     self._doc.pod, self._doc.collection),
             })
     except (yaml.composer.ComposerError,
             yaml.parser.ParserError,
             yaml.reader.ReaderError,
             yaml.scanner.ScannerError) as error:
         message = 'Error parsing {}: {}'.format(self._doc.pod_path, error)
         raise BadFormatError(message)
Пример #8
0
 def _handle_pairs_of_parts_and_bodies(self):
   locales_to_bodies = {}
   locales_to_fields = {}
   locale = str(self.doc.locale)
   default_locale = str(self.doc.default_locale)
   for part, body in utils.every_two(Format.split_front_matter(self.content)):
     fields = utils.load_yaml(part, pod=self.doc.pod)
     doc_locale = fields.get('$locale', default_locale)
     locales_to_fields[doc_locale] = fields
     locales_to_bodies[doc_locale] = body
   fields = locales_to_fields.get(default_locale)
   if locale in locales_to_fields:
     localized_fields = locales_to_fields[locale]
     if fields is None:
       fields = {}
     fields.update(localized_fields)
   self.body = locales_to_bodies.get(locale, locales_to_bodies.get(default_locale))
   self.body = self.body.strip() if self.body is not None else None
   self.fields = fields
Пример #9
0
 def raw_data(self):
     if not self._raw_front_matter:
         return {}
     return utils.load_yaml(
         self._raw_front_matter, doc=self._doc, pod=self._doc.pod)
Пример #10
0
    def extract(self, include_obsolete=False, localized=False, paths=None,
                include_header=False, locales=None, use_fuzzy_matching=False):
        env = self.pod.get_jinja_env()

        all_locales = set(list(self.pod.list_locales()))
        message_ids_to_messages = {}
        paths_to_messages = collections.defaultdict(set)
        paths_to_locales = collections.defaultdict(set)

        comment_tags = [
            ':',
        ]
        options = {
            'extensions': ','.join(env.extensions.keys()),
            'silent': 'false',
        }

        # Extract from content files.
        def callback(doc, item, key, unused_node):
            # Verify that the fields we're extracting are fields for a document
            # that's in the default locale. If not, skip the document.
            _handle_field(doc.pod_path, item, key, unused_node)

        def _add_existing_message(msgid, locations, auto_comments=None,
                                  context=None, path=None):
            existing_message = message_ids_to_messages.get(msgid)
            auto_comments = [] if auto_comments is None else auto_comments
            if existing_message:
                message_ids_to_messages[msgid].locations.extend(locations)
                paths_to_messages[path].add(existing_message)
            else:
                message = catalog.Message(
                    msgid,
                    None,
                    auto_comments=auto_comments,
                    context=context,
                    locations=locations)
                paths_to_messages[path].add(message)
                message_ids_to_messages[message.id] = message

        def _handle_field(path, item, key, node):
            if (not key
                    or not isinstance(item, basestring)
                    or not isinstance(key, basestring)
                    or not key.endswith('@')):
                return
            # Support gettext "extracted comments" on tagged fields. This is
            # consistent with extracted comments in templates, which follow
            # the format "{#: Extracted comment. #}". An example:
            #   field@: Message.
            #   field@#: Extracted comment for field@.
            auto_comments = []
            if isinstance(node, dict):
                auto_comment = node.get('{}#'.format(key))
                if auto_comment:
                    auto_comments.append(auto_comment)
            locations = [(path, 0)]
            _add_existing_message(
                msgid=item,
                auto_comments=auto_comments,
                locations=locations,
                path=path)

        for collection in self.pod.list_collections():
            text = 'Extracting collection: {}'.format(collection.pod_path)
            self.pod.logger.info(text)
            # Extract from blueprint.
            utils.walk(collection.tagged_fields, lambda *args: callback(collection, *args))
            # Extract from docs in collection.
            for doc in collection.docs(include_hidden=True):
                if not self._should_extract_as_babel(paths, doc.pod_path):
                    continue
                tagged_fields = doc.get_tagged_fields()
                utils.walk(tagged_fields, lambda *args: callback(doc, *args))
                paths_to_locales[doc.pod_path].update(doc.locales)
                all_locales.update(doc.locales)

        # Extract from podspec.
        config = self.pod.get_podspec().get_config()
        podspec_path = '/podspec.yaml'
        if self._should_extract_as_babel(paths, podspec_path):
            self.pod.logger.info('Extracting podspec: {}'.format(podspec_path))
            utils.walk(config, lambda *args: _handle_field(podspec_path, *args))

        # Extract from content and views.
        pod_files = [os.path.join('/views', path)
                     for path in self.pod.list_dir('/views/')]
        pod_files += [os.path.join('/content', path)
                      for path in self.pod.list_dir('/content/')]
        pod_files += [os.path.join('/data', path)
                      for path in self.pod.list_dir('/data/')]
        for pod_path in pod_files:
            if self._should_extract_as_csv(paths, pod_path):
                rows = utils.get_rows_from_csv(self.pod, pod_path)
                self.pod.logger.info('Extracting: {}'.format(pod_path))
                for row in rows:
                    for i, parts in enumerate(row.iteritems()):
                        key, val = parts
                        if key.endswith('@'):
                            locations = [(pod_path, i)]
                            _add_existing_message(
                                msgid=val,
                                locations=locations,
                                path=pod_path)
            elif self._should_extract_as_babel(paths, pod_path):
                if pod_path.startswith('/data') and pod_path.endswith(('.yaml', '.yml')):
                    self.pod.logger.info('Extracting: {}'.format(pod_path))
                    content = self.pod.read_file(pod_path)
                    fields = utils.load_yaml(content, pod=self.pod)
                    utils.walk(fields, lambda *args: _handle_field(pod_path, *args))
                    continue

                pod_locales = paths_to_locales.get(pod_path)
                if pod_locales:
                    text = 'Extracting: {} ({} locales)'
                    text = text.format(pod_path, len(pod_locales))
                    self.pod.logger.info(text)
                else:
                    self.pod.logger.info('Extracting: {}'.format(pod_path))
                fp = self.pod.open_file(pod_path)
                try:
                    all_parts = extract.extract(
                        'jinja2.ext.babel_extract', fp, options=options,
                        comment_tags=comment_tags)
                    for parts in all_parts:
                        lineno, string, comments, context = parts
                        locations = [(pod_path, lineno)]
                        _add_existing_message(
                            msgid=string,
                            auto_comments=comments,
                            context=context,
                            locations=locations,
                            path=pod_path)
                except tokenize.TokenError:
                    self.pod.logger.error('Problem extracting: {}'.format(pod_path))
                    raise

        # Localized message catalogs.
        if localized:
            for locale in all_locales:
                if locales and locale not in locales:
                    continue
                localized_catalog = self.get(locale)
                if not include_obsolete:
                    localized_catalog.obsolete = babel_util.odict()
                    for message in list(localized_catalog):
                        if message.id not in message_ids_to_messages:
                            localized_catalog.delete(message.id, context=message.context)

                catalog_to_merge = catalog.Catalog()
                for path, message_items in paths_to_messages.iteritems():
                    locales_with_this_path = paths_to_locales.get(path)
                    if locales_with_this_path and locale not in locales_with_this_path:
                        continue
                    for message in message_items:
                        translation = None
                        existing_message = localized_catalog.get(message.id)
                        if existing_message:
                            translation = existing_message.string
                        catalog_to_merge.add(
                            message.id, translation, locations=message.locations,
                            auto_comments=message.auto_comments, flags=message.flags,
                            user_comments=message.user_comments, context=message.context,
                            lineno=message.lineno, previous_id=message.previous_id)

                localized_catalog.update_using_catalog(
                    catalog_to_merge, use_fuzzy_matching=use_fuzzy_matching)
                localized_catalog.save(include_header=include_header)
                missing = localized_catalog.list_untranslated()
                num_messages = len(localized_catalog)
                num_translated = num_messages - len(missing)
                text = 'Saved: /{path} ({num_translated}/{num_messages})'
                self.pod.logger.info(
                    text.format(path=localized_catalog.pod_path,
                                num_translated=num_translated,
                                num_messages=num_messages))
            return

        # Global (or missing, specified by -o) message catalog.
        template_path = self.template_path
        catalog_obj, _ = self._get_or_create_catalog(template_path)
        if not include_obsolete:
            catalog_obj.obsolete = babel_util.odict()
            for message in list(catalog_obj):
                catalog_obj.delete(message.id, context=message.context)
        for message in message_ids_to_messages.itervalues():
            if message.id:
                catalog_obj.add(message.id, None, locations=message.locations,
                                auto_comments=message.auto_comments)
        return self.write_template(
            template_path, catalog_obj, include_obsolete=include_obsolete,
            include_header=include_header)