diff --git a/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItem.cs b/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItem.cs index 584b3cd..ba3bd6c 100644 --- a/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItem.cs +++ b/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItem.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; using VirtoCommerce.Platform.Core.Common; @@ -27,6 +26,7 @@ public class SitemapItem : AuditableEntity, ICloneable public virtual object Clone() { var result = MemberwiseClone() as SitemapItem; + result.ItemsRecords = ItemsRecords?.Select(x => x.Clone()).OfType().ToList(); return result; diff --git a/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItemImageRecord.cs b/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItemImageRecord.cs new file mode 100644 index 0000000..a28e602 --- /dev/null +++ b/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItemImageRecord.cs @@ -0,0 +1,18 @@ +using System; + +namespace VirtoCommerce.SitemapsModule.Core.Models +{ + public class SitemapItemImageRecord : ICloneable + { + public string Loc { get; set; } + + #region ICloneable members + + public virtual object Clone() + { + return MemberwiseClone() as SitemapItemImageRecord; + } + + #endregion + } +} diff --git a/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItemRecord.cs b/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItemRecord.cs index 502ac0c..d37545f 100644 --- a/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItemRecord.cs +++ b/src/VirtoCommerce.SitemapsModule.Core/Models/SitemapItemRecord.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; using System.Linq; namespace VirtoCommerce.SitemapsModule.Core.Models @@ -17,6 +16,8 @@ public class SitemapItemRecord : ICloneable public ICollection Alternates { get; set; } = new List(); + public ICollection Images { get; set; } = new List(); + #region ICloneable members public virtual object Clone() @@ -24,6 +25,7 @@ public virtual object Clone() var result = MemberwiseClone() as SitemapItemRecord; result.Alternates = Alternates?.Select(x => x.Clone()).OfType().ToList(); + result.Images = Images?.Select(x => x.Clone()).OfType().ToList(); return result; } diff --git a/src/VirtoCommerce.SitemapsModule.Core/ModuleConstants.cs b/src/VirtoCommerce.SitemapsModule.Core/ModuleConstants.cs index 16ac8ba..cfb02c7 100644 --- a/src/VirtoCommerce.SitemapsModule.Core/ModuleConstants.cs +++ b/src/VirtoCommerce.SitemapsModule.Core/ModuleConstants.cs @@ -60,6 +60,14 @@ public static class General DefaultValue = ".md,.html" }; + public static readonly SettingDescriptor IncludeImages = new SettingDescriptor + { + Name = "Sitemap.IncludeImages", + GroupName = "Sitemap|General", + ValueType = SettingValueType.Boolean, + DefaultValue = false + }; + public static IEnumerable AllSettings { get @@ -68,6 +76,7 @@ public static IEnumerable AllSettings yield return FilenameSeparator; yield return SearchBunchSize; yield return AcceptedFilenameExtensions; + yield return IncludeImages; } } } diff --git a/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapItemImageXmlRecord.cs b/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapItemImageXmlRecord.cs new file mode 100644 index 0000000..66637e8 --- /dev/null +++ b/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapItemImageXmlRecord.cs @@ -0,0 +1,26 @@ +using System; +using System.Xml.Serialization; +using VirtoCommerce.SitemapsModule.Core.Models; + +namespace VirtoCommerce.SitemapsModule.Data.Models.Xml +{ + [Serializable] + [XmlType(Namespace = "http://www.google.com/schemas/sitemap-image/1.1")] + public class SitemapItemImageXmlRecord + { + [XmlElement("loc")] + public string Loc { get; set; } + + public virtual SitemapItemImageXmlRecord ToXmlModel(SitemapItemImageRecord coreModel) + { + if (coreModel == null) + { + throw new ArgumentNullException(nameof(coreModel)); + } + + Loc = coreModel.Loc; + + return this; + } + } +} diff --git a/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapItemXmlRecord.cs b/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapItemXmlRecord.cs index 857a800..a689821 100644 --- a/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapItemXmlRecord.cs +++ b/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapItemXmlRecord.cs @@ -24,6 +24,12 @@ public class SitemapItemXmlRecord [XmlElement("link", Namespace = "http://www.w3.org/1999/xhtml")] public List Alternates { get; set; } + /// + /// Containes images if load images checkbox is activated in settings + /// + [XmlElement("image", Namespace = "http://www.google.com/schemas/sitemap-image/1.1")] + public List Images { get; set; } + public virtual SitemapItemXmlRecord ToXmlModel(SitemapItemRecord coreModel) { if (coreModel == null) @@ -36,6 +42,7 @@ public virtual SitemapItemXmlRecord ToXmlModel(SitemapItemRecord coreModel) UpdateFrequency = coreModel.UpdateFrequency; Url = coreModel.Url; Alternates = coreModel.Alternates.Count > 0 ? coreModel.Alternates.Select(a => (new SitemapItemAlternateLinkXmlRecord()).ToXmlModel(a)).ToList() : null; + Images = coreModel.Images.Count > 0 ? coreModel.Images.Select(a => (new SitemapItemImageXmlRecord()).ToXmlModel(a)).ToList() : null; return this; } diff --git a/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapXmlRecord.cs b/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapXmlRecord.cs index 8cdca9a..56ac3df 100644 --- a/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapXmlRecord.cs +++ b/src/VirtoCommerce.SitemapsModule.Data/Models/Xml/SitemapXmlRecord.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Xml.Serialization; @@ -13,7 +13,13 @@ public SitemapXmlRecord() Items = new List(); } + /// + /// Property that is used to dynamically set xml namespaces for objects like Image + /// + [XmlNamespaceDeclarations] + public XmlSerializerNamespaces xmlns; + [XmlElement("url")] public List Items { get; set; } } -} \ No newline at end of file +} diff --git a/src/VirtoCommerce.SitemapsModule.Data/Services/SitemapItemRecordProviders/CatalogSitemapItemRecordProvider.cs b/src/VirtoCommerce.SitemapsModule.Data/Services/SitemapItemRecordProviders/CatalogSitemapItemRecordProvider.cs index b1ef5a7..2c3535b 100644 --- a/src/VirtoCommerce.SitemapsModule.Data/Services/SitemapItemRecordProviders/CatalogSitemapItemRecordProvider.cs +++ b/src/VirtoCommerce.SitemapsModule.Data/Services/SitemapItemRecordProviders/CatalogSitemapItemRecordProvider.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using VirtoCommerce.CatalogModule.Core.Model; +using VirtoCommerce.CatalogModule.Core.Model.ListEntry; using VirtoCommerce.CatalogModule.Core.Model.Search; using VirtoCommerce.CatalogModule.Core.Search; using VirtoCommerce.CatalogModule.Core.Services; @@ -20,17 +22,24 @@ public class CatalogSitemapItemRecordProvider : SitemapItemRecordProviderBase, I private readonly ISettingsManager _settingsManager; private readonly IItemService _itemService; private readonly IListEntrySearchService _listEntrySearchService; + private readonly IProductSearchService _productSearchService; + private readonly ICategorySearchService _categorySearchService; public CatalogSitemapItemRecordProvider( ISitemapUrlBuilder urlBuilder, ISettingsManager settingsManager, IItemService itemService, - IListEntrySearchService listEntrySearchService) + IListEntrySearchService listEntrySearchService, + IProductSearchService productSearchService, + ICategorySearchService categorySearchService) : base(urlBuilder) { _settingsManager = settingsManager; _itemService = itemService; _listEntrySearchService = listEntrySearchService; + + _productSearchService = productSearchService; + _categorySearchService = categorySearchService; } #region ISitemapItemRecordProvider members @@ -44,13 +53,17 @@ public virtual async Task LoadSitemapItemRecordsAsync(Store store, Sitemap sitem { throw new ArgumentNullException(nameof(sitemap)); } + await LoadCategoriesSitemapItemRecordsAsync(store, sitemap, baseUrl, progressCallback); await LoadProductsSitemapItemRecordsAsync(store, sitemap, baseUrl, progressCallback); } + #endregion protected virtual async Task LoadCategoriesSitemapItemRecordsAsync(Store store, Sitemap sitemap, string baseUrl, Action progressCallback = null) { + var shouldIncludeImages = await _settingsManager.GetValueAsync(ModuleConstants.Settings.General.IncludeImages); + var progressInfo = new ExportImportProgressInfo(); var categoryOptions = await GetCategoryOptions(store); var batchSize = await _settingsManager.GetValueAsync(ModuleConstants.Settings.General.SearchBunchSize); @@ -77,9 +90,35 @@ protected virtual async Task LoadCategoriesSitemapItemRecordsAsync(Store store, var result = await _listEntrySearchService.SearchAsync(listEntrySearchCriteria); totalCount = result.TotalCount; listEntrySearchCriteria.Skip += batchSize; + + // Only used if should include images + List products = new List(); + if (shouldIncludeImages) + { + // If images need to be included - run a search for picked products to get variations with images + var productIds = result.Results.Where(x => x is ProductListEntry).Select(x => x.Id).ToArray(); + products = await SearchProductsWithVariations(batchSize, productIds); + } + foreach (var listEntry in result.Results) { - categorySiteMapItem.ItemsRecords.AddRange(GetSitemapItemRecords(store, categoryOptions, sitemap.UrlTemplate, baseUrl, listEntry)); + var itemRecords = GetSitemapItemRecords(store, categoryOptions, sitemap.UrlTemplate, baseUrl, listEntry).ToList(); + + if (shouldIncludeImages && listEntry is ProductListEntry) + { + var item = products.FirstOrDefault(x => x.Id == listEntry.Id); + + // for each record per product add image urls to sitemap + foreach (var record in itemRecords) + { + record.Images.AddRange(item.Images.Select(x => new SitemapItemImageRecord + { + Loc = x.Url + })); + } + } + + categorySiteMapItem.ItemsRecords.AddRange(itemRecords); } progressInfo.Description = $"Catalog: Have been generated {Math.Min(listEntrySearchCriteria.Skip, totalCount)} of {totalCount} records for category {categorySiteMapItem.Title} item"; progressCallback?.Invoke(progressInfo); @@ -90,38 +129,114 @@ protected virtual async Task LoadCategoriesSitemapItemRecordsAsync(Store store, } } + /// + /// This helps keeping the imageless flow untouched for products + /// + /// + /// + /// + /// + /// protected virtual async Task LoadProductsSitemapItemRecordsAsync(Store store, Sitemap sitemap, string baseUrl, Action progressCallback = null) { - var progressInfo = new ExportImportProgressInfo(); - var productOptions = await GetProductOptions(store); + var shouldIncludeImages = await _settingsManager.GetValueAsync(ModuleConstants.Settings.General.IncludeImages); + + if (shouldIncludeImages) + { + await LoadProductsWithoutImages(store, sitemap, baseUrl, progressCallback); + } + else + { + await LoadProductsWithImages(store, sitemap, baseUrl, progressCallback); + } + } + + private async Task> SearchProductsWithVariations(int batchSize, string[] productIds = null, ProductSearchCriteria searchCriteria = null, Action progressCallback = null) + { + var products = (await _itemService.GetAsync(productIds, (ItemResponseGroup.Seo | ItemResponseGroup.Outlines | ItemResponseGroup.WithImages).ToString())) + . Where(p => !p.IsActive.HasValue || p.IsActive.Value).ToList(); + + return products; + } + + /// + /// This is used to load products with images + /// Images are attached to corresponding product per item record + /// + /// + /// + /// + /// + /// + private async Task LoadProductsWithImages(Store store, Sitemap sitemap, string baseUrl, Action progressCallback = null) + { var batchSize = await _settingsManager.GetValueAsync(ModuleConstants.Settings.General.SearchBunchSize); - var skip = 0; var productSitemapItems = sitemap.Items.Where(x => x.ObjectType.EqualsInvariant(SitemapItemTypes.Product)).ToList(); - if (productSitemapItems.Count > 0) - { - progressInfo.Description = $"Catalog: Starting records generation for {productSitemapItems.Count} products items"; - progressCallback?.Invoke(progressInfo); - do + var productOptions = await GetProductOptions(store); + + var productIds = productSitemapItems.Select(x => x.ObjectId).ToArray(); + + var products = await SearchProductsWithVariations(batchSize, productIds); + + foreach (var product in products) + { + var productSitemapItem = productSitemapItems.FirstOrDefault(x => x.ObjectId.EqualsInvariant(product.Id)); + if (productSitemapItem != null) { - var productIds = productSitemapItems.Select(x => x.ObjectId).Skip(skip).Take(batchSize).ToArray(); - var products = (await _itemService.GetAsync(productIds, (ItemResponseGroup.Seo | ItemResponseGroup.Outlines).ToString())).Where(p => !p.IsActive.HasValue || p.IsActive.Value); - skip += batchSize; - foreach (var product in products) + var itemRecords = GetSitemapItemRecords(store, productOptions, sitemap.UrlTemplate, baseUrl, product); + + foreach (var item in itemRecords) { - var productSitemapItem = productSitemapItems.FirstOrDefault(x => x.ObjectId.EqualsInvariant(product.Id)); - if (productSitemapItem != null) + var existingImages = product.Images.Where(x => !string.IsNullOrWhiteSpace(x.Url)).ToList(); + if (existingImages.Count > 0) { - var itemRecords = GetSitemapItemRecords(store, productOptions, sitemap.UrlTemplate, baseUrl, product); - productSitemapItem.ItemsRecords.AddRange(itemRecords); + item.Images.AddRange(existingImages.Select(x => new SitemapItemImageRecord + { + Loc = x.Url + })); } } - progressInfo.Description = $"Catalog: Have been generated {Math.Min(skip, productSitemapItems.Count)} of {productSitemapItems.Count} records for products items"; - progressCallback?.Invoke(progressInfo); + + productSitemapItem.ItemsRecords.AddRange(itemRecords); + } + } + } + + private async Task LoadProductsWithoutImages(Store store, Sitemap sitemap, string baseUrl, Action progressCallback = null) + { + var batchSize = await _settingsManager.GetValueAsync(ModuleConstants.Settings.General.SearchBunchSize); + + var productSitemapItems = sitemap.Items.Where(x => x.ObjectType.EqualsInvariant(SitemapItemTypes.Product)).ToList(); + var skip = 0; + var productOptions = await GetProductOptions(store); + + var progressInfo = new ExportImportProgressInfo(); + + do + { + var productIds = productSitemapItems.Select(x => x.ObjectId).Skip(skip).Take(batchSize).ToArray(); + + var products = (await _itemService.GetAsync(productIds, (ItemResponseGroup.Seo | ItemResponseGroup.Outlines ).ToString())) + .Where(p => !p.IsActive.HasValue || p.IsActive.Value); + + skip += batchSize; + + foreach (var product in products) + { + var productSitemapItem = productSitemapItems.FirstOrDefault(x => x.ObjectId.EqualsInvariant(product.Id)); + if (productSitemapItem != null) + { + var itemRecords = GetSitemapItemRecords(store, productOptions, sitemap.UrlTemplate, baseUrl, product); + + productSitemapItem.ItemsRecords.AddRange(itemRecords); + } } - while (skip < productSitemapItems.Count); + progressInfo.Description = $"Catalog: Have been generated {Math.Min(skip, productSitemapItems.Count)} of {productSitemapItems.Count} records for products items"; + progressCallback?.Invoke(progressInfo); } + while (skip < productSitemapItems.Count); } private async Task GetProductOptions(Store store) diff --git a/src/VirtoCommerce.SitemapsModule.Data/Services/SitemapXmlGenerator.cs b/src/VirtoCommerce.SitemapsModule.Data/Services/SitemapXmlGenerator.cs index f2c7c9a..c71dd40 100644 --- a/src/VirtoCommerce.SitemapsModule.Data/Services/SitemapXmlGenerator.cs +++ b/src/VirtoCommerce.SitemapsModule.Data/Services/SitemapXmlGenerator.cs @@ -73,8 +73,9 @@ public virtual async Task GenerateSitemapXmlAsync(string storeId, string var recordsLimitPerFile = await _settingsManager.GetValueAsync(ModuleConstants.Settings.General.RecordsLimitPerFile); var xmlNamespaces = new XmlSerializerNamespaces(); - xmlNamespaces.Add("", "https://www.sitemaps.org/schemas/sitemap/0.9"); + //xmlNamespaces.Add("", "https://www.sitemaps.org/schemas/sitemap/0.9"); xmlNamespaces.Add("xhtml", "https://www.w3.org/1999/xhtml"); + xmlNamespaces.Add("image", "http://www.google.com/schemas/sitemap-image/1.1"); var sitemapLocation = SitemapLocation.Parse(sitemapUrl, filenameSeparator); var store = await _storeService.GetByIdAsync(storeId, StoreResponseGroup.StoreInfo.ToString()); @@ -86,16 +87,20 @@ public virtual async Task GenerateSitemapXmlAsync(string storeId, string }); var allStoreSitemaps = await LoadAllStoreSitemaps(store, baseUrl); + var sitemapIndexXmlRecord = new SitemapIndexXmlRecord(); + foreach (var sitemap in allStoreSitemaps) { var xmlSiteMapRecords = sitemap.PagedLocations.Select(location => new SitemapIndexItemXmlRecord { //ModifiedDate = sitemap.Items.Select(x => x.ModifiedDate).OrderByDescending(x => x).FirstOrDefault()?.ToString("yyyy-MM-dd"), - Url = _sitemapUrlBuilder.BuildStoreUrl(store, store.DefaultLanguage, location, baseUrl) + Url = _sitemapUrlBuilder.BuildStoreUrl(store, store.DefaultLanguage, location, baseUrl), }).ToList(); + sitemapIndexXmlRecord.Sitemaps.AddRange(xmlSiteMapRecords); } + var xmlSerializer = new XmlSerializer(sitemapIndexXmlRecord.GetType()); xmlSerializer.Serialize(stream, sitemapIndexXmlRecord, xmlNamespaces); } @@ -106,12 +111,16 @@ public virtual async Task GenerateSitemapXmlAsync(string storeId, string if (sitemap != null) { await LoadSitemapRecords(store, sitemap, baseUrl, progressCallback); - var distinctRecords = sitemap.Items.SelectMany(x => x.ItemsRecords).GroupBy(x => x.Url).Select(x => x.FirstOrDefault()); + + var distinctRecords = sitemap.Items.SelectMany(x => x.ItemsRecords);//.GroupBy(x => x.Url).Select(x => x.FirstOrDefault()); var sitemapItemRecords = distinctRecords.Skip((sitemapLocation.PageNumber - 1) * recordsLimitPerFile).Take(recordsLimitPerFile).ToArray(); + var sitemapRecord = new SitemapXmlRecord { + xmlns = xmlNamespaces, Items = sitemapItemRecords.Select(i => new SitemapItemXmlRecord().ToXmlModel(i)).ToList() }; + if (sitemapRecord.Items.Count > 0) { var xmlSerializer = new XmlSerializer(sitemapRecord.GetType()); @@ -123,10 +132,9 @@ public virtual async Task GenerateSitemapXmlAsync(string storeId, string return stream; } - private async Task> LoadAllStoreSitemaps(Store store, string baseUrl) { - var result = new List(); + var sitemaps = new List(); var sitemapSearchCriteria = new SitemapSearchCriteria { StoreId = store.Id, @@ -134,12 +142,15 @@ private async Task> LoadAllStoreSitemaps(Store store, strin Take = int.MaxValue }; var sitemapSearchResult = await _sitemapSearchService.SearchAsync(sitemapSearchCriteria); + foreach (var sitemap in sitemapSearchResult.Results) { await LoadSitemapRecords(store, sitemap, baseUrl); - result.Add(sitemap); + + sitemaps.Add(sitemap); } - return result; + + return sitemaps; } private async Task LoadSitemapRecords(Store store, Sitemap sitemap, string baseUrl, Action progressCallback = null) @@ -154,6 +165,8 @@ private async Task LoadSitemapRecords(Store store, Sitemap sitemap, string baseU Take = int.MaxValue }; sitemap.Items = (await _sitemapItemSearchService.SearchAsync(sitemapItemSearchCriteria)).Results; + + var imageUrls = new List(); foreach (var recordProvider in _sitemapItemRecordProviders) { //Log exceptions to prevent fail whole sitemap.xml generation diff --git a/src/VirtoCommerce.SitemapsModule.Web/Localizations/de.VirtoCommerce.Sitemaps.json b/src/VirtoCommerce.SitemapsModule.Web/Localizations/de.VirtoCommerce.Sitemaps.json index 116eff8..4be4794 100644 --- a/src/VirtoCommerce.SitemapsModule.Web/Localizations/de.VirtoCommerce.Sitemaps.json +++ b/src/VirtoCommerce.SitemapsModule.Web/Localizations/de.VirtoCommerce.Sitemaps.json @@ -119,38 +119,42 @@ "sitemaps:delete": "Zugriff auf eine Sitemap löschen" }, - "settings": { - "Sitemap.RecordsLimitPerFile": { - "title": "Datensatzbegrenzung", - "description": "Aufzeichnungslimit für jede Sitemap-Datei Beachten Sie, dass Suchmaschinen-Crawler Sitepaketdateien akzeptieren, die weniger als 50000 URL-Datensätze enthalten und die Dateigröße weniger als 10 MB beträgt" - }, - "Sitemap.FilenameSeparator": { - "title": "Dateinamens-Trennzeichen", - "description": "Das Trennzeichen für den Dateinamen der Sitemap und dessen Teil im Falle der Anzahl der Sitemap-Elemente ist größer als die Anzahl der Datensätze pro Datei" - }, - "Sitemap.SearchBunchSize": { - "title": "Suche Gruppengröße", - "description": "Die Bündelgröße für Suchelemente (z. B. Katalogsuche)" - }, - "Sitemap.AcceptedFilenameExtensions": { - "title": "Akzeptierte Dateierweiterungen für statische Inhalte", - "description": "Dieses Feld enthält die durch Kommas getrennte Liste der Dateinamenerweiterungen für statische Inhalte, die in der Sitemap enthalten sind. Zum Beispiel: .md,.html" - }, - "Sitemap.ProductPageUpdateFrequency": { - "title": "Aktualisierungshäufigkeit der Produktseite", - "description": "Gibt an, wie häufig sich die Produktseite ändern wird. Dieser Wert stellt allgemeine Informationen für Suchmaschinen bereit und korreliert möglicherweise nicht genau mit der Häufigkeit, mit der die Seiten gecrawlt werden." - }, - "Sitemap.ProductPagePriority": { - "title": "Priorität der Produktseite", - "description": "Die Priorität der URL relativ zu anderen URLs auf der Website. Gültige Werte liegen zwischen 0,0 und 1,0. Dieser Wert wirkt sich nicht darauf aus, wie Seiten mit Seiten auf anderen Websites verglichen werden. Dadurch können die Suchmaschinen nur erfahren, welche Seiten für die Crawler am wichtigsten sind." - }, - "Sitemap.CategoryPageUpdateFrequency": { - "title": "Aktualisierungshäufigkeit der Kategorieseite", - "description": "Gibt an, wie häufig sich die Kategorieseite ändern wird. Dieser Wert stellt allgemeine Informationen für Suchmaschinen bereit und korreliert möglicherweise nicht genau mit der Häufigkeit, mit der die Seiten gecrawlt werden." - }, - "Sitemap.CategoryPagePriority": { - "title": "Kategorieseitenpriorität", - "description": "Die Priorität der URL relativ zu anderen URLs auf der Website. Gültige Werte liegen zwischen 0,0 und 1,0. Dieser Wert wirkt sich nicht darauf aus, wie Seiten mit Seiten auf anderen Websites verglichen werden. Dadurch können die Suchmaschinen nur erfahren, welche Seiten für die Crawler am wichtigsten sind." - } + "settings": { + "Sitemap.RecordsLimitPerFile": { + "title": "Datensatzbegrenzung", + "description": "Aufzeichnungslimit für jede Sitemap-Datei Beachten Sie, dass Suchmaschinen-Crawler Sitepaketdateien akzeptieren, die weniger als 50000 URL-Datensätze enthalten und die Dateigröße weniger als 10 MB beträgt" + }, + "Sitemap.FilenameSeparator": { + "title": "Dateinamens-Trennzeichen", + "description": "Das Trennzeichen für den Dateinamen der Sitemap und dessen Teil im Falle der Anzahl der Sitemap-Elemente ist größer als die Anzahl der Datensätze pro Datei" + }, + "Sitemap.SearchBunchSize": { + "title": "Suche Gruppengröße", + "description": "Die Bündelgröße für Suchelemente (z. B. Katalogsuche)" + }, + "Sitemap.AcceptedFilenameExtensions": { + "title": "Akzeptierte Dateierweiterungen für statische Inhalte", + "description": "Dieses Feld enthält die durch Kommas getrennte Liste der Dateinamenerweiterungen für statische Inhalte, die in der Sitemap enthalten sind. Zum Beispiel: .md,.html" + }, + "Sitemap.IncludeImages": { + "title": "Sollte Bilder in die Sitemap aufnehmen", + "description": "Diese Prüfung gibt an, ob Bilder in die Sitemap-Generierung einbezogen werden sollen" + }, + "Sitemap.ProductPageUpdateFrequency": { + "title": "Aktualisierungshäufigkeit der Produktseite", + "description": "Gibt an, wie häufig sich die Produktseite ändern wird. Dieser Wert stellt allgemeine Informationen für Suchmaschinen bereit und korreliert möglicherweise nicht genau mit der Häufigkeit, mit der die Seiten gecrawlt werden." + }, + "Sitemap.ProductPagePriority": { + "title": "Priorität der Produktseite", + "description": "Die Priorität der URL relativ zu anderen URLs auf der Website. Gültige Werte liegen zwischen 0,0 und 1,0. Dieser Wert wirkt sich nicht darauf aus, wie Seiten mit Seiten auf anderen Websites verglichen werden. Dadurch können die Suchmaschinen nur erfahren, welche Seiten für die Crawler am wichtigsten sind." + }, + "Sitemap.CategoryPageUpdateFrequency": { + "title": "Aktualisierungshäufigkeit der Kategorieseite", + "description": "Gibt an, wie häufig sich die Kategorieseite ändern wird. Dieser Wert stellt allgemeine Informationen für Suchmaschinen bereit und korreliert möglicherweise nicht genau mit der Häufigkeit, mit der die Seiten gecrawlt werden." + }, + "Sitemap.CategoryPagePriority": { + "title": "Kategorieseitenpriorität", + "description": "Die Priorität der URL relativ zu anderen URLs auf der Website. Gültige Werte liegen zwischen 0,0 und 1,0. Dieser Wert wirkt sich nicht darauf aus, wie Seiten mit Seiten auf anderen Websites verglichen werden. Dadurch können die Suchmaschinen nur erfahren, welche Seiten für die Crawler am wichtigsten sind." } + } } diff --git a/src/VirtoCommerce.SitemapsModule.Web/Localizations/en.VirtoCommerce.Sitemaps.json b/src/VirtoCommerce.SitemapsModule.Web/Localizations/en.VirtoCommerce.Sitemaps.json index 4feab44..f037888 100644 --- a/src/VirtoCommerce.SitemapsModule.Web/Localizations/en.VirtoCommerce.Sitemaps.json +++ b/src/VirtoCommerce.SitemapsModule.Web/Localizations/en.VirtoCommerce.Sitemaps.json @@ -152,6 +152,10 @@ "title": "Accepted static content file extensions", "description": "This field contains the comma separated list of static content filename extensions which will be included to the sitemap. I.e.: .md,.html" }, + "Sitemap.IncludeImages": { + "title": "Should include images in sitemap", + "description": "This check indicates whether images should be included in sitemap generation" + }, "Sitemap.ProductPageUpdateFrequency": { "title": "Product page update frequency", "description": "How frequently the product page is likely to change. This value provides general information to search engines and may not correlate exactly to how often they crawl the page." diff --git a/src/VirtoCommerce.SitemapsModule.Web/Localizations/ru.VirtoCommerce.Sitemaps.json b/src/VirtoCommerce.SitemapsModule.Web/Localizations/ru.VirtoCommerce.Sitemaps.json index 8953390..59500e5 100644 --- a/src/VirtoCommerce.SitemapsModule.Web/Localizations/ru.VirtoCommerce.Sitemaps.json +++ b/src/VirtoCommerce.SitemapsModule.Web/Localizations/ru.VirtoCommerce.Sitemaps.json @@ -135,38 +135,42 @@ "sitemaps:delete": "Удаление карты сайта" }, - "settings": { - "Sitemap.RecordsLimitPerFile": { - "title": "Предельное количество записей", - "description": "Количество записей, которое может содержаться в одном файле с картой сайта. Роботы некоторых поисковых систем принимают карты сайтов, которые содержат не более 50000 ссылок и имеют размер не более 10 МБ." - }, - "Sitemap.FilenameSeparator": { - "title": "Разделитель названий файлов", - "description": "Строка, которая будет разделять название карты сайта и порядковый номер её части, если суммарное количество записей в карте сайта превысит предельное количество записей." - }, - "Sitemap.SearchBunchSize": { - "title": "Предельное количество результатов поиска", - "description": "Предельное количество элементов, получаемых в результате поиска (например, при поиске по каталогам)." - }, - "Sitemap.AcceptedFilenameExtensions": { - "title": "Допустимые расширения файлов со статическим содержимым", - "description": "Расширения файлов со статическим содержимым, которые будут учитываться при построении карты сайта. Значения могут быть перечислены через запятую, например: .md,.html" - }, - "Sitemap.ProductPageUpdateFrequency": { - "title": "Период обновления информации о продукте", - "description": "Указывает, насколько часто обычно меняется содержимое страниц с информацией о продукте. Указанное значение является лишь \"подсказкой\" для поисковых систем, и реальный период между индексациями страницы поисковыми роботами может отличаться от указанного здесь значения." - }, - "Sitemap.ProductPagePriority": { - "title": "Приоритет страниц продуктов", - "description": "Значение от 0.0 до 1.0, указывающее приоритет страниц продуктов относительно других страниц сайта. Это значение не используется при сравнении релевантности страниц этого сайта со страницами других сайтов - оно лишь подсказывает поисковым системам, какие страницы на этом сайте наиболее важны для поисковых роботов." - }, - "Sitemap.CategoryPageUpdateFrequency": { - "title": "Период обновления категорий продуктов", - "description": "Указывает, насколько часто обычно меняются категории продуктов. Указанное значение является лишь \"подсказкой\" для поисковых систем, и реальный период между индексациями страницы поисковыми роботами может отличаться от указанного здесь значения." - }, - "Sitemap.CategoryPagePriority": { - "title": "Приоритет страниц категорий продуктов", - "description": "Значение от 0.0 до 1.0, указывающее приоритет страниц категорий продуктов относительно других страниц сайта. Это значение не используется при сравнении релевантности страниц этого сайта со страницами других сайтов - оно лишь подсказывает поисковым системам, какие страницы на этом сайте наиболее важны для поисковых роботов." - } + "settings": { + "Sitemap.RecordsLimitPerFile": { + "title": "Предельное количество записей", + "description": "Количество записей, которое может содержаться в одном файле с картой сайта. Роботы некоторых поисковых систем принимают карты сайтов, которые содержат не более 50000 ссылок и имеют размер не более 10 МБ." + }, + "Sitemap.FilenameSeparator": { + "title": "Разделитель названий файлов", + "description": "Строка, которая будет разделять название карты сайта и порядковый номер её части, если суммарное количество записей в карте сайта превысит предельное количество записей." + }, + "Sitemap.SearchBunchSize": { + "title": "Предельное количество результатов поиска", + "description": "Предельное количество элементов, получаемых в результате поиска (например, при поиске по каталогам)." + }, + "Sitemap.AcceptedFilenameExtensions": { + "title": "Допустимые расширения файлов со статическим содержимым", + "description": "Расширения файлов со статическим содержимым, которые будут учитываться при построении карты сайта. Значения могут быть перечислены через запятую, например: .md,.html" + }, + "Sitemap.IncludeImages": { + "title": "Необходимо добавить изображения в sitemap", + "description": "Указывает, нужно ли сохранять адреса изображений в sitemap" + }, + "Sitemap.ProductPageUpdateFrequency": { + "title": "Период обновления информации о продукте", + "description": "Указывает, насколько часто обычно меняется содержимое страниц с информацией о продукте. Указанное значение является лишь \"подсказкой\" для поисковых систем, и реальный период между индексациями страницы поисковыми роботами может отличаться от указанного здесь значения." + }, + "Sitemap.ProductPagePriority": { + "title": "Приоритет страниц продуктов", + "description": "Значение от 0.0 до 1.0, указывающее приоритет страниц продуктов относительно других страниц сайта. Это значение не используется при сравнении релевантности страниц этого сайта со страницами других сайтов - оно лишь подсказывает поисковым системам, какие страницы на этом сайте наиболее важны для поисковых роботов." + }, + "Sitemap.CategoryPageUpdateFrequency": { + "title": "Период обновления категорий продуктов", + "description": "Указывает, насколько часто обычно меняются категории продуктов. Указанное значение является лишь \"подсказкой\" для поисковых систем, и реальный период между индексациями страницы поисковыми роботами может отличаться от указанного здесь значения." + }, + "Sitemap.CategoryPagePriority": { + "title": "Приоритет страниц категорий продуктов", + "description": "Значение от 0.0 до 1.0, указывающее приоритет страниц категорий продуктов относительно других страниц сайта. Это значение не используется при сравнении релевантности страниц этого сайта со страницами других сайтов - оно лишь подсказывает поисковым системам, какие страницы на этом сайте наиболее важны для поисковых роботов." } + } }