using System.Net; using Microsoft.AspNetCore.Http; using Nop.Core.Domain.Localization; using Nop.Core.Infrastructure; namespace Nop.Services.Localization; /// /// Represents extensions for localized URLs /// public static class LocalizedUrlExtensions { private static readonly char[] _separator = ['/', '?']; /// /// Get a value indicating whether URL is localized (contains SEO code) /// /// URL /// Application path base /// A value indicating whether passed URL is raw URL /// /// A task that represents the asynchronous operation /// The task result contains true if passed URL contains SEO code; otherwise false. Language whose SEO code is in the URL if URL is localized /// public static async Task<(bool IsLocalized, Language Language)> IsLocalizedUrlAsync(this string url, PathString pathBase, bool isRawPath) { if (string.IsNullOrEmpty(url)) return (false, null); //remove application path from raw URL if (isRawPath) url = url.RemoveApplicationPathFromRawUrl(pathBase); //get first segment of passed URL var firstSegment = url.Split(_separator, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault() ?? string.Empty; if (string.IsNullOrEmpty(firstSegment)) return (false, null); //suppose that the first segment is the language code and try to get language var languageService = EngineContext.Current.Resolve(); var language = (await languageService.GetAllLanguagesAsync()) .FirstOrDefault(urlLanguage => urlLanguage.UniqueSeoCode.Equals(firstSegment, StringComparison.InvariantCultureIgnoreCase)); //if language exists and published passed URL is localized return (language?.Published ?? false, language); } /// /// Remove application path from raw URL /// /// Raw URL /// Application path base /// Result public static string RemoveApplicationPathFromRawUrl(this string rawUrl, PathString pathBase) { new PathString(rawUrl).StartsWithSegments(pathBase, out var result); return WebUtility.UrlDecode(result); } /// /// Remove language SEO code from URL /// /// Raw URL /// Application path base /// A value indicating whether passed URL is raw URL /// URL without language SEO code public static string RemoveLanguageSeoCodeFromUrl(this string url, PathString pathBase, bool isRawPath) { if (string.IsNullOrEmpty(url)) return url; //remove application path from raw URL if (isRawPath) url = url.RemoveApplicationPathFromRawUrl(pathBase); //get result URL url = url.TrimStart('/'); var result = url.Contains('/') ? url[(url.IndexOf('/'))..] : string.Empty; //and add back application path to raw URL if (isRawPath) result = pathBase + result; return result; } /// /// Add language SEO code to URL /// /// Raw URL /// Application path base /// A value indicating whether passed URL is raw URL /// Language /// Result public static string AddLanguageSeoCodeToUrl(this string url, PathString pathBase, bool isRawPath, Language language) { ArgumentNullException.ThrowIfNull(language); //null validation is not required //if (string.IsNullOrEmpty(url)) // return url; //remove application path from raw URL if (isRawPath && !string.IsNullOrEmpty(url)) url = url.RemoveApplicationPathFromRawUrl(pathBase); //add language code url = $"/{language.UniqueSeoCode}{url}"; //and add back application path to raw URL if (isRawPath) url = pathBase + url; return url; } }