/// <summary>   Place where query handling happens. </summary>
        /// <param name="query">    This is the query instance. </param>
        /// <returns>
        ///     You have to return something from the query execution. Of course you can return
        ///     <c>null</c> as well if you will.
        /// </returns>
        public IEnumerable <LocalizationResource> Execute(GetAllResources.Query query)
        {
            var all = new List <LocalizationResource>();

            using (var uow = _dataService.StartUnitOfWork())
            {
                var compound = uow.TranslationRepository.GetAllCompound();

                // ReSharper disable once IteratorMethodResultIsIgnored
                foreach (var entity in compound)
                {
                    var resource = new LocalizationResource(entity.Resource.ResourceKey)
                    {
                        Id               = entity.Resource.Id,
                        Author           = entity.Resource.Author,
                        FromCode         = entity.Resource.FromCode,
                        IsHidden         = entity.Resource.IsHidden,
                        IsModified       = entity.Resource.IsModified,
                        ModificationDate = entity.Resource.ModificationDate
                    };
                    resource.Translations = new List <LocalizationResourceTranslation>(entity.Translations.Select(t =>
                                                                                                                  new LocalizationResourceTranslation
                    {
                        Id                   = t.Id,
                        Language             = t.Language,
                        LocalizationResource = resource,
                        ResourceId           = resource.Id,
                        Value                = t.Value
                    }));
                    all.Add(resource);
                }
            }

            return(all);
        }
示例#2
0
        private LocalizationResourceApiModel PrepareViewModel()
        {
            var availableLanguagesQuery = new AvailableLanguages.Query {
                IncludeInvariant = true
            };
            var languages = availableLanguagesQuery.Execute();

            var getResourcesQuery = new GetAllResources.Query(true);
            var resources         = getResourcesQuery.Execute().OrderBy(r => r.ResourceKey).ToList();

            var user    = Request.HttpContext.User;
            var isAdmin = false;

            if (user != null)
            {
                isAdmin = user.Identity.IsAuthenticated && _config.AuthorizedAdminRoles.Any(r => user.IsInRole(r));
            }

            var result = new LocalizationResourceApiModel(resources, languages, _config.MaxResourceKeyPopupTitleLength, _config.MaxResourceKeyDisplayLength)
            {
                Options =
                {
                    AdminMode            = isAdmin,
                    ShowInvariantCulture = _config.ShowInvariantCulture,
                    ShowHiddenResources  = _config.ShowHiddenResources
                }
            };

            return(result);
        }
示例#3
0
        public JObject GetJson(string resourceClassName, string languageName, bool camelCase = false)
        {
            var resources         = new GetAllResources.Query().Execute();
            var filteredResources = resources.Where(r => r.ResourceKey.StartsWith(resourceClassName, StringComparison.InvariantCultureIgnoreCase)).ToList();

            return(Convert(filteredResources, languageName, ConfigurationContext.Current.EnableInvariantCultureFallback, camelCase));
        }
        public IEnumerable <LocalizationResource> Execute(SyncResources.Query query)
        {
            ConfigurationContext.Current.Logger?.Debug("Starting to sync resources...");
            var sw = new Stopwatch();

            sw.Start();

            var discoveredResources = query.DiscoveredResources;
            var discoveredModels    = query.DiscoveredModels;

            ResetSyncStatus();

            var allResources = new GetAllResources.Query(true).Execute();

            Parallel.Invoke(() => RegisterDiscoveredResources(discoveredResources, allResources),
                            () => RegisterDiscoveredResources(discoveredModels, allResources));

            var result = MergeLists(allResources, discoveredResources.ToList(), discoveredModels.ToList());

            sw.Stop();

            ConfigurationContext.Current.Logger?.Debug($"Resource synchronization took: {sw.ElapsedMilliseconds}ms");

            return(result);
        }
示例#5
0
        private LocalizationResourceApiModel PrepareViewModel()
        {
            var context = UiConfigurationContext.Current;
            var availableLanguagesQuery = new AvailableLanguages.Query {
                IncludeInvariant = context.ShowInvariantCulture
            };
            var languages = availableLanguagesQuery.Execute();

            var getResourcesQuery = new GetAllResources.Query(true);
            var resources         = getResourcesQuery.Execute().OrderBy(r => r.ResourceKey).ToList();

            var user    = RequestContext.Principal;
            var isAdmin = false;

            if (user != null)
            {
                isAdmin = user.Identity.IsAuthenticated && context.AuthorizedAdminRoles.Any(r => user.IsInRole(r));
            }

            return(new LocalizationResourceApiModel(resources, languages)
            {
                AdminMode = isAdmin,
                HideDeleteButton = context.HideDeleteButton,
                IsRemoveTranslationButtonDisabled = UiConfigurationContext.Current.DisableRemoveTranslationButton
            });
        }
示例#6
0
        /// <summary>   Discover and register. </summary>
        public void DiscoverAndRegister()
        {
            if (!ConfigurationContext.Current.DiscoverAndRegisterResources)
            {
                return;
            }

            var discoveredTypes = TypeDiscoveryHelper.GetTypes(
                t => t.GetCustomAttribute <LocalizedResourceAttribute>() != null,
                t => t.GetCustomAttribute <LocalizedModelAttribute>() != null);

            var discoveredResources = discoveredTypes[0];
            var discoveredModels    = discoveredTypes[1];
            var foreignResources    = ConfigurationContext.Current.ForeignResources;

            if (foreignResources != null && foreignResources.Any())
            {
                discoveredResources.AddRange(foreignResources.Select(x => x.ResourceType));
            }

            ResetSyncStatus();
            var allResources = new GetAllResources.Query().Execute().ToList();

            RegisterDiscoveredResources(discoveredResources, allResources);
            RegisterDiscoveredResources(discoveredModels, allResources);

            if (ConfigurationContext.Current.PopulateCacheOnStartup)
            {
                PopulateCache();
            }
        }
 public IEnumerable <LocalizationResource> Execute(GetAllResources.Query query)
 {
     using (var db = new LanguageEntities())
     {
         return(db.LocalizationResources.Include(r => r.Translations).ToList());
     }
 }
示例#8
0
        public void DiscoverAndRegister()
        {
            if (!ConfigurationContext.Current.DiscoverAndRegisterResources)
            {
                return;
            }

            var discoveredTypes = TypeDiscoveryHelper.GetTypes(t => t.GetCustomAttribute <LocalizedResourceAttribute>() != null,
                                                               t => t.GetCustomAttribute <LocalizedModelAttribute>() != null);

            var discoveredResources = discoveredTypes[0];
            var discoveredModels    = discoveredTypes[1];
            var foreignResources    = ConfigurationContext.Current.ForeignResources;

            if (foreignResources != null && foreignResources.Any())
            {
                discoveredResources.AddRange(foreignResources.Select(x => x.ResourceType));
            }

            // initialize db structures first (issue #53)
            using (var ctx = new LanguageEntities())
            {
                var tmp = ctx.LocalizationResources.FirstOrDefault();
            }

            ResetSyncStatus();
            var allResources = new GetAllResources.Query(true).Execute();

            Parallel.Invoke(() => RegisterDiscoveredResources(discoveredResources, allResources),
                            () => RegisterDiscoveredResources(discoveredModels, allResources));

            StoreKnownResourcesAndPopulateCache();
        }
        public string GetJson(string filename, HttpContext context, string languageName, bool debugMode)
        {
            // for us - filename it's actually root namespace of the resource key to retrieve
            var resources         = new GetAllResources.Query().Execute();
            var filteredResources = _filter.GetResourcesWithStartingKey(resources, filename);

            return(JsonConvert.SerializeObject(_converter.Convert(filteredResources, languageName), debugMode ? Formatting.Indented : Formatting.None));
        }
        public object Import(IEnumerable <LocalizationResource> newResources, bool importOnlyNewContent)
        {
            var count = 0;

            // if we are overwriting old content - we need to get rid of resources first
            if (!importOnlyNewContent)
            {
                new DeleteAllResources.Command().Execute();
            }

            var allCurrentResources = new GetAllResources.Query(true).Execute().ToDictionary(r => r.ResourceKey);
            var newInserts          = new List <LocalizationResource>();

            foreach (var localizationResource in newResources)
            {
                if (importOnlyNewContent)
                {
                    // look for existing resource
                    allCurrentResources.TryGetValue(localizationResource.ResourceKey, out var existingResource);

                    if (existingResource == null)
                    {
                        // resource with this key does not exist - so we can just add it
                        newInserts.Add(localizationResource);
                        //new CreateNewResource.Command(localizationResource).Execute();
                        count++;
                    }
                    else
                    {
                        // there is a resource with this key - looking for missing translations
                        foreach (var translation in localizationResource.Translations)
                        {
                            new CreateOrUpdateTranslation.Command(existingResource.ResourceKey, new CultureInfo(translation.Language), translation.Value).Execute();
                        }
                    }
                }
                else
                {
                    // don't care about state in DB
                    // if we are importing all resources once again - all will be gone anyway
                    //new CreateNewResource.Command(localizationResource).Execute();
                    newInserts.Add(localizationResource);
                    count++;
                }
            }

            new CreateNewResources.Command(newInserts).Execute();

            var c = new ClearCache.Command();

            c.Execute();

            return($"Import successful. Imported {count} resources");
        }
示例#11
0
        public string GetJson(string filename, HttpContext context, string languageName, bool debugMode)
        {
            // for us - filename it's actually root namespace of the resource key to retrieve
            var resources         = new GetAllResources.Query().Execute();
            var filteredResources = _filter.GetResourcesWithStartingKey(resources, filename);

            // we need to process key names and supported tested classes with "+" symbols in keys -> so we replace those wiyh dots to have proper object nesting on client side
            filteredResources.ForEach(r => r.ResourceKey = r.ResourceKey.Replace("+", "."));

            return(JsonConvert.SerializeObject(_converter.Convert(filteredResources, languageName), debugMode ? Formatting.Indented : Formatting.None));
        }
        public FileResult OnGetExport(string format = "json")
        {
            var exporter  = ConfigurationContext.Current.Export.Providers.FindById(format);
            var resources = new GetAllResources.Query().Execute();
            var result    = exporter.Export(resources.ToList(), null);

            return(new FileContentResult(Encoding.UTF8.GetBytes(result.SerializedData), result.FileMimeType)
            {
                FileDownloadName = result.FileName
            });
        }
示例#13
0
        /// <summary>   Populate cache. </summary>
        // ReSharper disable once MemberCanBeMadeStatic.Local
        private void PopulateCache()
        {
            new ClearCache.Command().Execute();
            var allResources = new GetAllResources.Query().Execute();

            foreach (var resource in allResources)
            {
                var key = CacheKeyHelper.BuildKey(resource.ResourceKey);
                ConfigurationContext.Current.CacheManager.Insert(key, resource);
            }
        }
        private void PopulateCache()
        {
            var c = new ClearCache.Command();
            c.Execute();

            var allResources = new GetAllResources.Query().Execute();

            foreach (var resource in allResources)
            {
                var key = CacheKeyHelper.BuildKey(resource.ResourceKey);
                ConfigurationContext.Current.CacheManager.Insert(key, resource);
            }
        }
示例#15
0
        public FileResult ExportResources()
        {
            var stream     = new MemoryStream();
            var writer     = new StreamWriter(stream, Encoding.UTF8);
            var serializer = new JsonDataSerializer();

            var resources = new GetAllResources.Query().Execute();

            writer.Write(serializer.Serialize(resources));
            writer.Flush();
            stream.Position = 0;

            return(File(stream, "application/json", $"localization-resources-{DateTime.Now.ToString("yyyyMMdd")}.json"));
        }
示例#16
0
        private (List <LocalizationResource>, IEnumerable <CultureInfo>) GetResources()
        {
            var availableLanguagesQuery = new AvailableLanguages.Query {
                IncludeInvariant = false
            };
            var languages = _queryExecutor.Execute(availableLanguagesQuery);

            var getResourcesQuery = new GetAllResources.Query(true);
            var resources         = _queryExecutor
                                    .Execute(getResourcesQuery)
                                    .OrderBy(_ => _.ResourceKey)
                                    .ToList();

            return(resources, languages);
        }
示例#17
0
        public FileResult ExportResources(string format = "json")
        {
            var exporter  = ConfigurationContext.Current.Export.Providers.FindById(format);
            var resources = new GetAllResources.Query(true).Execute();
            var result    = exporter.Export(resources.ToList(), Request.Params);

            var stream = new MemoryStream();
            var writer = new StreamWriter(stream, Encoding.UTF8);

            writer.Write(result.SerializedData);
            writer.Flush();
            stream.Position = 0;

            return(File(stream, result.FileMimeType, result.FileName));
        }
示例#18
0
        public IEnumerable <ResourceItem> Execute(GetAllTranslations.Query query)
        {
            var q            = new GetAllResources.Query();
            var allResources = q.Execute().Where(r =>
                                                 r.ResourceKey.StartsWith(query.Key) &&
                                                 r.Translations != null && r.Translations.Any(t => t.Language == query.Language.Name)).ToList();

            if (!allResources.Any())
            {
                return(Enumerable.Empty <ResourceItem>());
            }

            return(allResources.Select(r => new ResourceItem(r.ResourceKey,
                                                             r.Translations.First(t => t.Language == query.Language.Name).Value,
                                                             query.Language)).ToList());
        }
示例#19
0
        private List <ResourceListItem> GetAllResources()
        {
            var result    = new List <ResourceListItem>();
            var resources = new GetAllResources.Query().Execute().OrderBy(r => r.ResourceKey);

            foreach (var resource in resources)
            {
                result.Add(new ResourceListItem(
                               resource.ResourceKey,
                               resource.Translations.Select(t => new ResourceItem(resource.ResourceKey,
                                                                                  t.Value,
                                                                                  new CultureInfo(t.Language))).ToArray(),
                               !resource.FromCode));
            }

            return(result);
        }
        private LocalizationResourceApiModel PrepareViewModel()
        {
            var availableLanguagesQuery = new AvailableLanguages.Query();
            var languages = availableLanguagesQuery.Execute();

            var getResourcesQuery = new GetAllResources.Query();
            var resources = getResourcesQuery.Execute().OrderBy(r => r.ResourceKey).ToList();

            var user = RequestContext.Principal;
            var isAdmin = false;

            if (user != null)
            {
                isAdmin = user.Identity.IsAuthenticated && UiConfigurationContext.Current.AuthorizedAdminRoles.Any(r => user.IsInRole(r));
            }

            return new LocalizationResourceApiModel(resources, languages) { AdminMode = isAdmin };
        }
示例#21
0
        private List <ResourceListItem> GetAllResources()
        {
            var result    = new List <ResourceListItem>();
            var resources = new GetAllResources.Query().Execute().OrderBy(r => r.ResourceKey);

            foreach (var resource in resources)
            {
                result.Add(new ResourceListItem(resource.ResourceKey,
                                                resource.Translations.Where(t => t.Language != ConfigurationContext.CultureForTranslationsFromCode)
                                                .Select(t => new ResourceItem(resource.ResourceKey,
                                                                              t.Value,
                                                                              new CultureInfo(t.Language))).ToList(),
                                                !resource.FromCode,
                                                resource.IsHidden.HasValue && resource.IsHidden.Value));
            }

            return(result);
        }
        private void StoreKnownResourcesAndPopulateCache()
        {
            var allResources = new GetAllResources.Query(true).Execute();

            if (ConfigurationContext.Current.PopulateCacheOnStartup)
            {
                new ClearCache.Command().Execute();
                foreach (var resource in allResources)
                {
                    var key = CacheKeyHelper.BuildKey(resource.ResourceKey);
                    ConfigurationContext.Current.CacheManager.Insert(key, resource);
                }
            }
            else
            {
                // just store known resource keys in cache
                allResources.ForEach(r => ConfigurationContext.Current.BaseCacheManager.StoreKnownKey(r.ResourceKey));
            }
        }
        private (List <LocalizationResource>, IEnumerable <CultureInfo>, bool) GetResources()
        {
            var availableLanguagesQuery = new AvailableLanguages.Query {
                IncludeInvariant = true
            };
            var languages = availableLanguagesQuery.Execute();

            var getResourcesQuery = new GetAllResources.Query(true);
            var resources         = getResourcesQuery.Execute().OrderBy(_ => _.ResourceKey).ToList();

            var user    = Request.HttpContext.User;
            var isAdmin = false;

            if (user != null)
            {
                isAdmin = user.Identity.IsAuthenticated && _config.AuthorizedAdminRoles.Any(_ => user.IsInRole(_));
            }

            return(resources, languages, isAdmin);
        }
        private LocalizationResourceApiModel PrepareViewModel()
        {
            var availableLanguagesQuery = new AvailableLanguages.Query();
            var languages = availableLanguagesQuery.Execute();

            var getResourcesQuery = new GetAllResources.Query();
            var resources         = getResourcesQuery.Execute().OrderBy(r => r.ResourceKey).ToList();

            var user    = RequestContext.Principal;
            var isAdmin = false;

            if (user != null)
            {
                isAdmin = user.Identity.IsAuthenticated && UiConfigurationContext.Current.AuthorizedAdminRoles.Any(r => user.IsInRole(r));
            }

            return(new LocalizationResourceApiModel(resources, languages)
            {
                AdminMode = isAdmin
            });
        }
示例#25
0
        public void DiscoverAndRegister()
        {
            if (!ConfigurationContext.Current.DiscoverAndRegisterResources)
            {
                return;
            }

            var discoveredTypes = TypeDiscoveryHelper.GetTypes(t => t.GetCustomAttribute <LocalizedResourceAttribute>() != null,
                                                               t => t.GetCustomAttribute <LocalizedModelAttribute>() != null);

            var discoveredResources = discoveredTypes[0];
            var discoveredModels    = discoveredTypes[1];
            var foreignResources    = ConfigurationContext.Current.ForeignResources;

            if (foreignResources != null && foreignResources.Any())
            {
                discoveredResources.AddRange(foreignResources.Select(x => x.ResourceType));
            }

            // initialize db structures first (issue #53)
            if (ConfigurationContext.Current.Tenants.Any())
            {
                foreach (var t in ConfigurationContext.Current.Tenants)
                {
                    InitializeDatabaseStructures(t.ConnectionString);
                }
            }
            else
            {
                InitializeDatabaseStructures(ConfigurationContext.Current.DbContextConnectionString);
            }

            ResetSyncStatus();
            var allResources = new GetAllResources.Query(true).Execute();

            Parallel.Invoke(() => RegisterDiscoveredResources(discoveredResources, allResources),
                            () => RegisterDiscoveredResources(discoveredModels, allResources));

            StoreKnownResourcesAndPopulateCache();
        }
        public IEnumerable <LocalizationResource> Execute(GetAllResources.Query query)
        {
            if (query.ForceReadFromDb)
            {
                return(_inner.Execute(query));
            }

            // get keys for known resources
            var keys = ConfigurationContext.Current.BaseCacheManager.KnownResourceKeys.Keys;

            // if keys = 0, execute inner query to actually get resources from the db
            // this is usually called during initialization when cache is not yet filled up
            if (keys.Count == 0)
            {
                return(_inner.Execute(query));
            }

            var result = new List <LocalizationResource>();

            foreach (var key in keys)
            {
                var cacheKey = CacheKeyHelper.BuildKey(key);
                if (ConfigurationContext.Current.CacheManager.Get(cacheKey) is LocalizationResource localizationResource)
                {
                    result.Add(localizationResource);
                }
                else
                {
                    // failed to get from cache, should call database
                    var resourceFromDb = new GetResource.Query(key).Execute();
                    if (resourceFromDb != null)
                    {
                        ConfigurationContext.Current.CacheManager.Insert(cacheKey, resourceFromDb);
                        result.Add(resourceFromDb);
                    }
                }
            }

            return(result);
        }
        public FileResult ExportResources(string format = "json")
        {
            var exporter  = ConfigurationContext.Current.Export.Providers.FindById(format);
            var resources = new GetAllResources.Query(true).Execute();
            var languages = new AvailableLanguages.Query().Execute();

            foreach (var resource in resources)
            {
                var exportableTranslations = new List <LocalizationResourceTranslation>();
                var invariantTranslation   = resource.Translations.FindByLanguage(CultureInfo.InvariantCulture);
                if (invariantTranslation != null)
                {
                    exportableTranslations.Add(invariantTranslation);
                }

                foreach (var language in languages)
                {
                    var t = resource.Translations.FindByLanguage(language);
                    if (t != null)
                    {
                        exportableTranslations.Add(t);
                    }
                }

                resource.Translations = exportableTranslations;
            }

            var result = exporter.Export(resources.ToList(), Request.Params);

            var stream = new MemoryStream();
            var writer = new StreamWriter(stream, Encoding.UTF8);

            writer.Write(result.SerializedData);
            writer.Flush();
            stream.Position = 0;

            return(File(stream, result.FileMimeType, result.FileName));
        }
示例#28
0
        private void RegisterDiscoveredResources(IEnumerable <Type> types)
        {
            var helper     = new TypeDiscoveryHelper();
            var properties = types.SelectMany(type => helper.ScanResources(type)).DistinctBy(r => r.Key);

            var allResources   = new GetAllResources.Query().Execute();
            var defaultCulture = DetermineDefaultCulture();

            // split work queue by 400 resources each
            var groupedProperties = properties.SplitByCount(400);

            Parallel.ForEach(groupedProperties,
                             group =>
            {
                var sb = new StringBuilder();
                sb.AppendLine("declare @resourceId int");

                foreach (var property in group)
                {
                    var existingResource = allResources.FirstOrDefault(r => r.ResourceKey == property.Key);

                    if (existingResource == null)
                    {
                        sb.Append($@"
set @resourceId = isnull((select id from localizationresources where [resourcekey] = '{property.Key}'), -1)
if (@resourceId = -1)
begin
    insert into localizationresources ([resourcekey], modificationdate, author, fromcode, ismodified, ishidden) 
    values ('{property.Key}', getutcdate(), 'type-scanner', 1, 0, {Convert.ToInt32(property.IsHidden)})
    set @resourceId = SCOPE_IDENTITY()
    insert into localizationresourcetranslations (resourceid, [language], [value]) values (@resourceId, '{defaultCulture}', N'{property.Translation.Replace("'", "''")}')
    insert into localizationresourcetranslations (resourceid, [language], [value]) values (@resourceId, '{ConfigurationContext.CultureForTranslationsFromCode}', N'{property.Translation.Replace("'", "''")}')
end
");
                    }

                    if (existingResource != null)
                    {
                        sb.AppendLine($"update localizationresources set fromcode = 1, ishidden = {Convert.ToInt32(property.IsHidden)} where [id] = {existingResource.Id}");

                        if (existingResource.IsModified.HasValue && !existingResource.IsModified.Value)
                        {
                            AddTranslationScript(existingResource, defaultCulture, sb, property);
                            AddTranslationScript(existingResource, ConfigurationContext.CultureForTranslationsFromCode, sb, property);
                        }
                    }
                }

                using (var conn = new SqlConnection(ConfigurationManager.ConnectionStrings[ConfigurationContext.Current.ConnectionName].ConnectionString))
                {
                    var cmd = new SqlCommand(sb.ToString(), conn)
                    {
                        CommandTimeout = 60
                    };

                    conn.Open();
                    cmd.ExecuteNonQuery();
                    conn.Close();
                }
            });
        }
 public IEnumerable <LocalizationResource> Execute(GetAllResources.Query query)
 {
     return(_resources);
 }
        /// <summary>
        /// Place where query handling happens
        /// </summary>
        /// <param name="query">This is the query instance</param>
        /// <returns>
        /// You have to return something from the query execution. Of course you can return <c>null</c> as well if you
        /// will.
        /// </returns>
        public IEnumerable <LocalizationResource> Execute(GetAllResources.Query query)
        {
            var repository = new ResourceRepository(_configurationContext);

            return(repository.GetAll());
        }
        public IEnumerable <string> ImportChanges(ICollection <DetectedImportChange> changes)
        {
            var result  = new List <string>();
            var inserts = 0;
            var updates = 0;
            var deletes = 0;

            var allCurrentResources = new GetAllResources.Query(true).Execute().ToDictionary(r => r.ResourceKey);

            var newInserts = new List <LocalizationResource>();

            // process deletes
            foreach (var delete in changes.Where(c => c.ChangeType == ChangeType.Delete))
            {
                new DeleteResource.Command(delete.ExistingResource.ResourceKey).Execute();
                deletes++;
            }

            // process inserts
            foreach (var insert in changes.Where(c => c.ChangeType == ChangeType.Insert))
            {
                // fix incoming incomplete resource from web
                insert.ImportingResource.Author     = "import";
                insert.ImportingResource.IsModified = false;
                insert.ImportingResource.IsHidden   = false;

                // fix incoming resource translation invariant language (if any)
                insert.ImportingResource.Translations.ForEach(t => t.Language = t.Language ?? "");

                newInserts.Add(insert.ImportingResource);
                inserts++;
            }

            // process updates
            foreach (var update in changes.Where(c => c.ChangeType == ChangeType.Update))
            {
                // look for existing resource
                allCurrentResources.TryGetValue(update.ImportingResource.ResourceKey, out var existingResource);

                if (existingResource == null)
                {
                    // resource with this key does not exist - so we can just add it
                    update.ImportingResource.Author     = "import";
                    update.ImportingResource.IsModified = false;
                    update.ImportingResource.IsModified = false;

                    newInserts.Add(update.ImportingResource);
                    inserts++;
                    continue;
                }

                foreach (var translation in update.ImportingResource.Translations.Where(_ => _.Value != null))
                {
                    new CreateOrUpdateTranslation.Command(existingResource.ResourceKey, new CultureInfo(translation.Language), translation.Value).Execute();
                }

                updates++;
            }

            new CreateNewResources.Command(newInserts).Execute();
            var clearCommand = new ClearCache.Command();

            clearCommand.Execute();

            if (inserts > 0)
            {
                result.Add($"Inserted {inserts} resources.");
            }
            if (updates > 0)
            {
                result.Add($"Updated {updates} resources.");
            }
            if (deletes > 0)
            {
                result.Add($"Deleted {deletes} resources.");
            }

            return(result);
        }