Пример #1
0
 def test_lang_code(self):
     component = Component()
     component.filemask = 'Solution/Project/Resources.*.resx'
     self.assertEqual(
         component.get_lang_code('Solution/Project/Resources.es-mx.resx'),
         'es-mx'
     )
     self.assertEqual(
         component.get_lang_code('Solution/Project/Resources.resx'),
         ''
     )
     self.assertRaisesMessage(
         ValidationError,
         'Got empty language code for '
         'Solution/Project/Resources.resx, please check filemask!',
         component.clean_lang_codes,
         [
             'Solution/Project/Resources.resx',
             'Solution/Project/Resources.de.resx',
             'Solution/Project/Resources.es.resx',
             'Solution/Project/Resources.es-mx.resx',
             'Solution/Project/Resources.fr.resx',
             'Solution/Project/Resources.fr-fr.resx',
         ]
     )
Пример #2
0
 def test_lang_code_template(self):
     component = Component(project=Project())
     component.filemask = 'Solution/Project/Resources.*.resx'
     component.template = 'Solution/Project/Resources.resx'
     self.assertEqual(
         component.get_lang_code('Solution/Project/Resources.resx'),
         'en'
     )
Пример #3
0
 def test_lang_code_double(self):
     component = Component()
     component.filemask = 'path/*/resources/MessagesBundle_*.properties'
     self.assertEqual(
         component.get_lang_code(
             'path/pt/resources/MessagesBundle_pt_BR.properties'
         ),
         'pt_BR'
     )
     self.assertEqual(
         component.get_lang_code(
             'path/el/resources/MessagesBundle_el.properties'
         ),
         'el'
     )
Пример #4
0
    def form_valid(self, form):
        if self.stage != 'init':
            return super(CreateFromZip, self).form_valid(form)

        # Create fake component (needed to calculate path)
        fake = Component(
            project=form.cleaned_data['project'],
            slug=form.cleaned_data['slug'],
            name=form.cleaned_data['name'],
        )

        # Create repository
        try:
            LocalRepository.from_zip(fake.full_path,
                                     form.cleaned_data['zipfile'])
        except BadZipfile:
            form.add_error('zipfile', _('Failed to parse uploaded ZIP file.'))
            return self.form_invalid(form)

        # Move to discover phase
        self.stage = 'discover'
        self.initial = form.cleaned_data
        self.initial['vcs'] = 'local'
        self.initial['repo'] = 'local:'
        self.initial.pop('zipfile')
        self.request.method = 'GET'
        return self.get(self, self.request)
Пример #5
0
def validate_render_component(value, translation=None, **kwargs):
    from weblate.trans.models import Project, Component, Translation
    from weblate.lang.models import Language
    component = Component(
        project=Project(
            name='project',
            slug='project',
            id=-1,
        ),
        name='component',
        slug='component',
        branch='master',
        vcs='git',
        id=-1,
    )
    if translation:
        kwargs['translation'] = Translation(
            id=-1,
            component=component,
            language_code='xx',
            language=Language(name='xxx', code='xx'),
        )
    else:
        kwargs['component'] = component
    validate_render(value, **kwargs)
Пример #6
0
 def check_unit(self, nplurals=3, template=None, source_info=None, **kwargs):
     if nplurals == 3:
         formula = "n==0 ? 0 : n==1 ? 1 : 2"
     else:
         formula = "0"
     lang = Language.objects.create(code="zz")
     plural = Plural.objects.create(language=lang, number=nplurals, formula=formula)
     project = Project(slug="test", source_language=Language.objects.get(code="en"))
     component = Component(
         slug="comp", project=project, file_format="xliff", template=template
     )
     translation = Translation(language=lang, component=component, plural=plural)
     # Fake file format to avoid need for actual files
     translation.store = EmptyFormat(BytesIOMode("", b""))
     unit = Unit(translation=translation, id_hash=-1, **kwargs)
     if source_info:
         for key, value in source_info.items():
             setattr(unit, key, value)
         unit.__dict__["all_comments"] = [
             Comment(comment="Weblate translator comment")
         ]
         unit.__dict__["suggestions"] = [
             Suggestion(target="Weblate translator suggestion")
         ]
     else:
         unit.__dict__["all_comments"] = []
     exporter = self.get_exporter(lang, translation=translation)
     exporter.add_unit(unit)
     return self.check_export(exporter)
Пример #7
0
 def check_unit(self, nplurals=3, **kwargs):
     if nplurals == 3:
         equation = 'n==0 ? 0 : n==1 ? 1 : 2'
     else:
         equation = '0'
     lang = Language.objects.create(
         code='zz',
     )
     plural = Plural.objects.create(
         language=lang,
         number=nplurals,
         equation=equation
     )
     project = Project(
         slug='test',
         source_language=Language.objects.get(code='en'),
     )
     component = Component(slug='comp', project=project)
     unit = Unit(
         translation=Translation(
             language=lang,
             component=component,
             plural=plural,
         ),
         id_hash=-1,
         **kwargs
     )
     exporter = self.get_exporter(lang)
     exporter.add_unit(unit)
     return self.check_export(exporter)
Пример #8
0
    def form_valid(self, form):
        if self.stage != "init":
            return super().form_valid(form)

        # Create fake component (needed to calculate path)
        fake = Component(
            project=form.cleaned_data["project"],
            slug=form.cleaned_data["slug"],
            name=form.cleaned_data["name"],
        )

        # Create repository
        try:
            LocalRepository.from_zip(fake.full_path,
                                     form.cleaned_data["zipfile"])
        except BadZipfile:
            form.add_error("zipfile", _("Failed to parse uploaded ZIP file."))
            return self.form_invalid(form)

        # Move to discover phase
        self.stage = "discover"
        self.initial = form.cleaned_data
        self.initial["vcs"] = "local"
        self.initial["repo"] = "local:"
        self.initial.pop("zipfile")
        self.request.method = "GET"
        return self.get(self, self.request)
Пример #9
0
 def check_unit(self, nplurals=3, template=None, **kwargs):
     if nplurals == 3:
         equation = 'n==0 ? 0 : n==1 ? 1 : 2'
     else:
         equation = '0'
     lang = Language.objects.create(
         code='zz',
     )
     plural = Plural.objects.create(
         language=lang,
         number=nplurals,
         equation=equation
     )
     project = Project(
         slug='test',
         source_language=Language.objects.get(code='en'),
     )
     component = Component(
         slug='comp',
         project=project,
         file_format='xliff',
         template=template
     )
     translation = Translation(
         language=lang,
         component=component,
         plural=plural,
     )
     # Fake file format to avoid need for actual files
     translation.store = EmptyFormat(BytesIOMode('', b''))
     unit = Unit(translation=translation, id_hash=-1, **kwargs)
     exporter = self.get_exporter(lang, translation=translation)
     exporter.add_unit(unit)
     return self.check_export(exporter)
Пример #10
0
    def form_valid(self, form):
        if self.stage != "init":
            return super().form_valid(form)

        # Create fake component (needed to calculate path)
        fake = Component(
            project=form.cleaned_data["project"],
            slug=form.cleaned_data["slug"],
            name=form.cleaned_data["name"],
        )

        # Create repository
        uploaded = form.cleaned_data["docfile"]
        ext = os.path.splitext(os.path.basename(uploaded.name))[1]
        filename = "{}/{}{}".format(
            form.cleaned_data["slug"],
            form.cleaned_data["project"].source_language.code,
            ext,
        )
        LocalRepository.from_files(fake.full_path, {filename: uploaded.read()})

        # Move to discover phase
        self.stage = "discover"
        self.initial = form.cleaned_data
        self.initial["vcs"] = "local"
        self.initial["repo"] = "local:"
        self.initial.pop("docfile")
        self.request.method = "GET"
        return self.get(self, self.request)
Пример #11
0
 def test_lang_code(self):
     project = Project(language_aliases="xx:cs")
     component = Component(project=project)
     component.filemask = "Solution/Project/Resources.*.resx"
     # Pure extraction
     self.assertEqual(
         component.get_lang_code("Solution/Project/Resources.es-mx.resx"),
         "es-mx")
     # No match
     self.assertEqual(
         component.get_lang_code("Solution/Project/Resources.resx"), "")
     # Language aliases
     self.assertEqual(
         component.get_lang_code("Solution/Project/Resources.xx.resx"),
         "xx")
     self.assertEqual(component.get_language_alias("xx"), "cs")
     self.assertRaisesMessage(
         ValidationError,
         "The language code for "
         "Solution/Project/Resources.resx"
         " was empty, please check the filemask.",
         component.clean_lang_codes,
         [
             "Solution/Project/Resources.resx",
             "Solution/Project/Resources.de.resx",
             "Solution/Project/Resources.es.resx",
             "Solution/Project/Resources.es-mx.resx",
             "Solution/Project/Resources.fr.resx",
             "Solution/Project/Resources.fr-fr.resx",
         ],
     )
Пример #12
0
    def clone_repo(self, path):

        return self._class.clone(
            self.format_local_path(getattr(self, '{0}_repo_path'.format(self._vcs))),
            path,
            component=Component(
                slug='test', name='Test', project=Project(name='Test', slug='test')
            ),
        )
Пример #13
0
 def clone_repo(self, path):
     return self._class.clone(
         self.get_remote_repo_url(),
         path,
         self._remote_branch,
         component=Component(slug="test",
                             name="Test",
                             project=Project(name="Test", slug="test")),
     )
Пример #14
0
    def clone_repo(self, path):

        return self._class.clone(
            self.format_local_path(getattr(self, "{0}_repo_path".format(self._vcs))),
            path,
            component=Component(
                slug="test", name="Test", project=Project(name="Test", slug="test")
            ),
        )
Пример #15
0
def check_manage_units(translation: Translation, component: Component) -> bool:
    # Check if adding is generally allowed
    if not component.manage_units or translation.is_readonly:
        return False
    source = translation.is_source
    template = component.has_template()
    # Add to source in monolingual and to translations in bilingual
    if (source and not template) or (not source and template):
        return False
    return True
Пример #16
0
 def test_lang_code(self):
     component = Component()
     component.filemask = 'Solution/Project/Resources.*.resx'
     self.assertEqual(
         component.get_lang_code('Solution/Project/Resources.es-mx.resx'),
         'es-mx')
     self.assertEqual(
         component.get_lang_code('Solution/Project/Resources.resx'), '')
     self.assertRaisesMessage(
         ValidationError, 'Got empty language code for '
         'Solution/Project/Resources.resx, please check filemask!',
         component.clean_lang_codes, [
             'Solution/Project/Resources.resx',
             'Solution/Project/Resources.de.resx',
             'Solution/Project/Resources.es.resx',
             'Solution/Project/Resources.es-mx.resx',
             'Solution/Project/Resources.fr.resx',
             'Solution/Project/Resources.fr-fr.resx',
         ])
Пример #17
0
def check_manage_units(translation: Translation, component: Component) -> bool:
    source = translation.is_source
    template = component.has_template()
    # Add only to source in monolingual
    if not source and template:
        return False
    # Check if adding is generally allowed
    if not component.manage_units or (template
                                      and not component.edit_template):
        return False
    return True
Пример #18
0
 def setUp(self):
     self.unit = Unit(translation=Translation(
         component=Component(
             project=Project(source_language=Language(), slug="p",
                             name="p"),
             slug="c",
             name="c",
         ),
         language=Language(),
     ))
     self.profile = Profile()
Пример #19
0
def create_component_from_zip(data):
    # Create fake component (needed to calculate path)
    fake = Component(
        project=data["project"],
        slug=data["slug"],
        name=data["name"],
    )

    # Create repository
    LocalRepository.from_zip(fake.full_path, data["zipfile"])
    return fake
Пример #20
0
 def handle(self, *args, **options):
     """List installed add-ons."""
     fake_addon = Addon(component=Component(project=Project(pk=-1), pk=-1))
     for _unused, obj in sorted(ADDONS.items()):
         self.stdout.write(f".. _addon-{obj.name}:")
         self.stdout.write("\n")
         self.stdout.write(obj.verbose)
         self.stdout.write("-" * len(obj.verbose))
         self.stdout.write("\n")
         self.stdout.write(f":Add-on ID: ``{obj.name}``")
         if obj.settings_form:
             form = obj(fake_addon).get_settings_form(None)
             table = [(f"``{name}``", str(field.label),
                       self.get_help_text(field, name))
                      for name, field in form.fields.items()]
             prefix = ":Configuration: "
             name_width = max(
                 len(name) for name, _label, _help_text in table)
             label_width = max(
                 len(label) for _name, label, _help_text in table)
             help_text_width = max(
                 max(len(line) for line in help_text) if help_text else 0
                 for _name, _label, help_text in table)
             name_row = "-" * (name_width + 2)
             label_row = "-" * (label_width + 2)
             help_text_row = "-" * (help_text_width + 2)
             for name, label, help_text in table:
                 if not prefix.isspace():
                     self.stdout.write(
                         f"{prefix}+{name_row}+{label_row}+{help_text_row}+"
                     )
                     prefix = "                "
                 if not help_text:
                     line = ""
                     self.stdout.write(
                         f"{prefix}| {name:<{name_width}s} | {label:<{label_width}s} | {line:<{help_text_width}s} |"
                     )
                 for pos, line in enumerate(help_text):
                     if pos > 0:
                         name = label = ""
                     self.stdout.write(
                         f"{prefix}| {name:<{name_width}s} | {label:<{label_width}s} | {line:<{help_text_width}s} |"
                     )
                 self.stdout.write(
                     f"{prefix}+{name_row}+{label_row}+{help_text_row}+")
         else:
             self.stdout.write(
                 ":Configuration: `This add-on has no configuration.`")
         events = ", ".join(EVENT_NAMES[event] for event in obj.events)
         self.stdout.write(f":Triggers: {events}")
         self.stdout.write("\n")
         self.stdout.write("\n".join(wrap(obj.description, 79)))
         self.stdout.write("\n")
Пример #21
0
 def test_lang_code(self):
     component = Component()
     component.filemask = "Solution/Project/Resources.*.resx"
     self.assertEqual(
         component.get_lang_code("Solution/Project/Resources.es-mx.resx"), "es-mx"
     )
     self.assertEqual(component.get_lang_code("Solution/Project/Resources.resx"), "")
     self.assertRaisesMessage(
         ValidationError,
         "The language code for "
         "Solution/Project/Resources.resx"
         " was empty, please check the filemask.",
         component.clean_lang_codes,
         [
             "Solution/Project/Resources.resx",
             "Solution/Project/Resources.de.resx",
             "Solution/Project/Resources.es.resx",
             "Solution/Project/Resources.es-mx.resx",
             "Solution/Project/Resources.fr.resx",
             "Solution/Project/Resources.fr-fr.resx",
         ],
     )
Пример #22
0
 def test_description(self):
     unit = Unit(
         source="string",
         target="I have two two lemons lemons",
         translation=Translation(
             language=Language("cs"),
             component=Component(source_language=Language("en")),
         ),
     )
     check = Check(unit=unit)
     self.assertEqual(
         self.check.get_description(check),
         "Text contains the same word twice in a row: lemons, two",
     )
Пример #23
0
 def handle(self, *args, **options):
     """List installed add-ons."""
     fake_addon = Addon(component=Component(project=Project()))
     for _unused, obj in sorted(ADDONS.items()):
         self.stdout.write(f".. _addon-{obj.name}:")
         self.stdout.write("\n")
         self.stdout.write(obj.verbose)
         self.stdout.write("-" * len(obj.verbose))
         self.stdout.write("\n")
         if obj.settings_form:
             form = obj(fake_addon).get_settings_form(None)
             params = ", ".join(f"``{key}``" for key in form.fields.keys())
         else:
             params = "`This add-on has no configuration.`"
         self.stdout.write(PARAMS_TABLE.format(obj.name, params))
         self.stdout.write("\n")
         self.stdout.write("\n".join(wrap(obj.description, 79)))
         self.stdout.write("\n")
Пример #24
0
 def test_description(self):
     unit = Unit(
         source="{0}''s brush is {1} centimeters tall",
         target="{0}'s brush is {1} centimeters tall",
         extra_flags="java-messageformat",
         translation=Translation(
             component=Component(
                 file_format="auto",
                 source_language=Language("en"),
             ),
             language=Language("cs"),
         ),
     )
     check = Check(unit=unit)
     self.assertEqual(
         self.check.get_description(check),
         "You need to pair up an apostrophe with another one.",
     )
Пример #25
0
def scratch_create_component(project, name, slug, file_format):
    format_cls = FILE_FORMATS[file_format]
    template = '{}.{}'.format(project.source_language.code,
                              format_cls.extension())
    fake = Component(project=project, slug=slug, name=name)
    # Create VCS with empty file
    LocalRepository.from_files(fake.full_path,
                               {template: format_cls.new_translation})
    # Create component
    return Component.objects.create(
        file_format=file_format,
        filemask='*.{}'.format(format_cls.extension()),
        template=template,
        vcs='local',
        repo='local:',
        project=project,
        name=name,
        slug=slug,
    )
Пример #26
0
def create_component_from_doc(data):
    # Calculate filename
    uploaded = data["docfile"]
    ext = os.path.splitext(os.path.basename(uploaded.name))[1]
    filemask = "{}/{}{}".format(data["slug"], "*", ext)
    filename = filemask.replace(
        "*",
        data["source_language"].code if "source_language" in data else "en")
    # Create fake component (needed to calculate path)
    fake = Component(
        project=data["project"],
        slug=data["slug"],
        name=data["name"],
        template=filename,
        filemask=filemask,
    )
    # Create repository
    LocalRepository.from_files(fake.full_path, {filename: uploaded.read()})
    return fake
Пример #27
0
 def check_unit(self,
                nplurals=3,
                template=None,
                source_info=None,
                **kwargs):
     if nplurals == 3:
         equation = 'n==0 ? 0 : n==1 ? 1 : 2'
     else:
         equation = '0'
     lang = Language.objects.create(code='zz', )
     plural = Plural.objects.create(language=lang,
                                    number=nplurals,
                                    equation=equation)
     project = Project(
         slug='test',
         source_language=Language.objects.get(code='en'),
     )
     component = Component(slug='comp',
                           project=project,
                           file_format='xliff',
                           template=template)
     translation = Translation(
         language=lang,
         component=component,
         plural=plural,
     )
     # Fake file format to avoid need for actual files
     translation.store = EmptyFormat(BytesIOMode('', b''))
     unit = Unit(translation=translation, id_hash=-1, **kwargs)
     if source_info:
         for key, value in source_info.items():
             setattr(unit, key, value)
         unit.get_comments = fake_get_comments
         unit.__dict__['suggestions'] = [
             Suggestion(target='Weblate translator suggestion')
         ]
     else:
         unit.get_comments = empty_get_comments
     exporter = self.get_exporter(lang, translation=translation)
     exporter.add_unit(unit)
     return self.check_export(exporter)
Пример #28
0
 def handle(self, *args, **options):
     """List installed add-ons."""
     fake_addon = Addon(component=Component(project=Project()))
     for _unused, obj in sorted(ADDONS.items()):
         self.stdout.write(f".. _addon-{obj.name}:")
         self.stdout.write("\n")
         self.stdout.write(obj.verbose)
         self.stdout.write("-" * len(obj.verbose))
         self.stdout.write("\n")
         self.stdout.write(f":Add-on ID: ``{obj.name}``")
         if obj.settings_form:
             form = obj(fake_addon).get_settings_form(None)
             table = [
                 (f"``{name}``", str(field.label), str(field.help_text))
                 for name, field in form.fields.items()
             ]
             prefix = ":Configuration: "
             name_width = max(len(row[0]) for row in table)
             label_width = max(len(row[1]) for row in table)
             help_text_width = max(len(row[2]) for row in table)
             name_row = "-" * (name_width + 2)
             label_row = "-" * (label_width + 2)
             help_text_row = "-" * (help_text_width + 2)
             for name, label, help_text in table:
                 if not prefix.isspace():
                     self.stdout.write(
                         f"{prefix}+{name_row}+{label_row}+{help_text_row}+"
                     )
                     prefix = "                "
                 self.stdout.write(
                     f"{prefix}| {name:<{name_width}s} | {label:<{label_width}s} | {help_text:<{help_text_width}s} |"
                 )
                 self.stdout.write(
                     f"{prefix}+{name_row}+{label_row}+{help_text_row}+"
                 )
         else:
             self.stdout.write(":Configuration: `This add-on has no configuration.`")
         self.stdout.write("\n")
         self.stdout.write("\n".join(wrap(obj.description, 79)))
         self.stdout.write("\n")
Пример #29
0
def create_component_from_doc(data):
    # Calculate filename
    uploaded = data["docfile"]
    guess_filemask_from_doc(data)
    filemask = data["filemask"]
    filename = filemask.replace(
        "*",
        data["source_language"].code
        if "source_language" in data
        else settings.DEFAULT_LANGUAGE,
    )
    # Create fake component (needed to calculate path)
    fake = Component(
        project=data["project"],
        slug=data["slug"],
        name=data["name"],
        template=filename,
        filemask=filemask,
    )
    # Create repository
    LocalRepository.from_files(fake.full_path, {filename: uploaded.read()})
    return fake
Пример #30
0
def validate_render_component(value, translation=None, **kwargs):
    from weblate.lang.models import Language
    from weblate.trans.models import Component, Project, Translation

    component = Component(
        project=Project(name="project", slug="project", id=-1),
        name="component",
        slug="component",
        branch="main",
        vcs="git",
        id=-1,
    )
    if translation:
        kwargs["translation"] = Translation(
            id=-1,
            component=component,
            language_code="xx",
            language=Language(name="xxx", code="xx"),
        )
    else:
        kwargs["component"] = component
    validate_render(value, **kwargs)
Пример #31
0
 def test_lang_code_template(self):
     component = Component(project=Project())
     component.filemask = 'Solution/Project/Resources.*.resx'
     component.template = 'Solution/Project/Resources.resx'
     self.assertEqual(
         component.get_lang_code('Solution/Project/Resources.resx'), 'en')
Пример #32
0
 def test_lang_code_template(self):
     component = Component(project=Project())
     component.filemask = "Solution/Project/Resources.*.resx"
     component.template = "Solution/Project/Resources.resx"
     self.assertEqual(
         component.get_lang_code("Solution/Project/Resources.resx"), "en")
Пример #33
0
    def handle(self, *args, **options):
        """Automatic import of components."""
        # Get project
        try:
            project = Project.objects.get(slug=options['project'])
        except Project.DoesNotExist:
            raise CommandError('Project does not exist!')

        # Get main component
        main_component = None
        if options['main_component']:
            try:
                main_component = Component.objects.get(
                    project=project,
                    slug=options['main_component']
                )
            except Component.DoesNotExist:
                raise CommandError('Main component does not exist!')

        try:
            data = json.load(options['json-file'])
        except ValueError:
            raise CommandError('Failed to parse JSON file!')
        finally:
            options['json-file'].close()

        for item in data:
            if ('filemask' not in item or
                    'name' not in item):
                raise CommandError('Missing required fields in JSON!')

            if 'slug' not in item:
                item['slug'] = slugify(item['name'])

            if 'repo' not in item:
                if main_component is None:
                    raise CommandError(
                        'No main component and no repository URL!'
                    )
                item['repo'] = main_component.get_repo_link_url()

            item['project'] = project

            try:
                component = Component.objects.get(
                    slug=item['slug'], project=item['project']
                )
                self.stderr.write(
                    'Component {0} already exists'.format(component)
                )
                if options['ignore']:
                    continue
                if options['update']:
                    for key in item:
                        if key in ('project', 'slug'):
                            continue
                        setattr(component, key, item[key])
                    component.save()
                    continue
                raise CommandError(
                    'Component already exists, use --ignore or --update!'
                )

            except Component.DoesNotExist:
                component = Component(**item)
                try:
                    component.full_clean()
                except ValidationError as error:
                    for key, value in error.message_dict.items():
                        self.stderr.write(
                            'Error in {}: {}'.format(key, ', '.join(value))
                        )
                    raise CommandError('Component failed validation!')
                component.save(force_insert=True)
                self.stdout.write(
                    'Imported {0} with {1} translations'.format(
                        component,
                        component.translation_set.count()
                    )
                )
Пример #34
0
    def handle(self, *args, **options):  # noqa: C901
        """Automatic import of components."""
        # Get project
        try:
            project = Project.objects.get(slug=options['project'])
        except Project.DoesNotExist:
            raise CommandError('Project does not exist!')

        # Get main component
        main_component = None
        if options['main_component']:
            try:
                main_component = Component.objects.get(
                    project=project, slug=options['main_component'])
            except Component.DoesNotExist:
                raise CommandError('Main component does not exist!')

        try:
            data = json.load(options['json-file'])
        except ValueError:
            raise CommandError('Failed to parse JSON file!')
        finally:
            options['json-file'].close()

        allfields = {
            field.name
            for field in Component._meta.get_fields()
            if field.editable and not field.is_relation
        }

        # Handle dumps from API
        if 'results' in data:
            data = data['results']

        for item in data:
            if 'filemask' not in item or 'name' not in item:
                raise CommandError('Missing required fields in JSON!')

            if 'slug' not in item:
                item['slug'] = slugify(item['name'])

            if 'repo' not in item:
                if main_component is None:
                    raise CommandError(
                        'No main component and no repository URL!')
                item['repo'] = main_component.get_repo_link_url()

            try:
                component = Component.objects.get(slug=item['slug'],
                                                  project=project)
                self.stderr.write(
                    'Component {0} already exists'.format(component))
                if options['ignore']:
                    continue
                if options['update']:
                    for key in item:
                        if key not in allfields or key == 'slug':
                            continue
                        setattr(component, key, item[key])
                    component.save()
                    continue
                raise CommandError(
                    'Component already exists, use --ignore or --update!')

            except Component.DoesNotExist:
                params = {key: item[key] for key in allfields if key in item}
                component = Component(project=project, **params)
                try:
                    component.full_clean()
                except ValidationError as error:
                    for key, value in error.message_dict.items():
                        self.stderr.write('Error in {}: {}'.format(
                            key, ', '.join(value)))
                    raise CommandError('Component failed validation!')
                component.save(force_insert=True)
                self.stdout.write('Imported {0} with {1} translations'.format(
                    component, component.translation_set.count()))