Merge branch 'netcore/task/9727-published-request' into netcore/task/9733-routabledocumentfilter

This commit is contained in:
Shannon
2021-01-11 16:44:01 +11:00
42 changed files with 231 additions and 200 deletions

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Options;
@@ -112,10 +112,10 @@ namespace Umbraco.Web.Routing
// if the property varies, get the variant value, URL is "<domain>/<variant-alias>"
// but! only if the culture is published, else ignore
if (varies && !node.HasCulture(domainUri.Culture.Name)) continue;
if (varies && !node.HasCulture(domainUri.Culture)) continue;
var umbracoUrlName = varies
? node.Value<string>(_publishedValueFallback,Constants.Conventions.Content.UrlAlias, culture: domainUri.Culture.Name)
? node.Value<string>(_publishedValueFallback,Constants.Conventions.Content.UrlAlias, culture: domainUri.Culture)
: node.Value<string>(_publishedValueFallback, Constants.Conventions.Content.UrlAlias);
var aliases = umbracoUrlName?.Split(new [] {','}, StringSplitOptions.RemoveEmptyEntries);
@@ -127,7 +127,7 @@ namespace Umbraco.Web.Routing
{
var path = "/" + alias;
var uri = new Uri(CombinePaths(domainUri.Uri.GetLeftPart(UriPartial.Path), path));
yield return UrlInfo.Url(_uriUtility.UriFromUmbraco(uri, _requestConfig).ToString(), domainUri.Culture.Name);
yield return UrlInfo.Url(_uriUtility.UriFromUmbraco(uri, _requestConfig).ToString(), domainUri.Culture);
}
}
}

View File

@@ -77,7 +77,7 @@ namespace Umbraco.Web.Routing
if (!string.IsNullOrEmpty(cultureFromQuerystring))
{
// we're assuming it will match a culture, if an invalid one is passed in, an exception will throw (there is no TryGetCultureInfo method), i think this is ok though
frequest.SetCulture(CultureInfo.GetCultureInfo(cultureFromQuerystring));
frequest.SetCulture(cultureFromQuerystring);
}
frequest.SetPublishedContent(node);

View File

@@ -54,7 +54,7 @@ namespace Umbraco.Web.Routing
? frequest.Domain.ContentId + DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded())
: frequest.Uri.GetAbsolutePathDecoded();
IRedirectUrl redirectUrl = _redirectUrlService.GetMostRecentRedirectUrl(route, frequest.Culture.Name);
IRedirectUrl redirectUrl = _redirectUrlService.GetMostRecentRedirectUrl(route, frequest.Culture);
if (redirectUrl == null)
{

View File

@@ -74,7 +74,7 @@ namespace Umbraco.Web.Routing
_logger.LogDebug("Test route {Route}", route);
IPublishedContent node = umbCtx.Content.GetByRoute(umbCtx.InPreviewMode, route, culture: docreq.Culture?.Name);
IPublishedContent node = umbCtx.Content.GetByRoute(umbCtx.InPreviewMode, route, culture: docreq.Culture);
if (node != null)
{
docreq.SetPublishedContent(node);

View File

@@ -59,7 +59,7 @@ namespace Umbraco.Web.Routing
node = FindContentByAlias(
umbCtx.Content,
frequest.Domain != null ? frequest.Domain.ContentId : 0,
frequest.Culture.Name,
frequest.Culture,
frequest.Uri.GetAbsolutePathDecoded());
if (node != null)

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;
@@ -83,7 +83,9 @@ namespace Umbraco.Web.Routing
var umbracoContext = _umbracoContextAccessor.UmbracoContext;
var node = umbracoContext.Content.GetById(id);
if (node == null)
{
yield break;
}
// look for domains, walking up the tree
var n = node;
@@ -96,17 +98,19 @@ namespace Umbraco.Web.Routing
// no domains = exit
if (domainUris ==null)
{
yield break;
}
foreach (var d in domainUris)
{
var culture = d?.Culture?.Name;
var culture = d?.Culture;
//although we are passing in culture here, if any node in this path is invariant, it ignores the culture anyways so this is ok
// although we are passing in culture here, if any node in this path is invariant, it ignores the culture anyways so this is ok
var route = umbracoContext.Content.GetRouteById(id, culture);
if (route == null) continue;
//need to strip off the leading ID for the route if it exists (occurs if the route is for a node with a domain assigned)
// need to strip off the leading ID for the route if it exists (occurs if the route is for a node with a domain assigned)
var pos = route.IndexOf('/');
var path = pos == 0 ? route : route.Substring(pos);

View File

@@ -1,4 +1,4 @@
using System.Globalization;
using System.Globalization;
namespace Umbraco.Web.Routing
{
@@ -15,7 +15,7 @@ namespace Umbraco.Web.Routing
/// <param name="contentId">The identifier of the content which supports the domain.</param>
/// <param name="culture">The culture of the domain.</param>
/// <param name="isWildcard">A value indicating whether the domain is a wildcard domain.</param>
public Domain(int id, string name, int contentId, CultureInfo culture, bool isWildcard)
public Domain(int id, string name, int contentId, string culture, bool isWildcard)
{
Id = id;
Name = name;
@@ -55,7 +55,7 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Gets the culture of the domain.
/// </summary>
public CultureInfo Culture { get; }
public string Culture { get; }
/// <summary>
/// Gets a value indicating whether the domain is a wildcard domain.

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
@@ -51,8 +51,8 @@ namespace Umbraco.Web.Routing
var rootContentId = domain?.ContentId ?? -1;
var wcDomain = FindWildcardDomainInPath(umbracoContext.Domains.GetAll(true), contentPath, rootContentId);
if (wcDomain != null) return wcDomain.Culture.Name;
if (domain != null) return domain.Culture.Name;
if (wcDomain != null) return wcDomain.Culture;
if (domain != null) return domain.Culture;
return umbracoContext.Domains.DefaultCulture;
}
@@ -233,13 +233,13 @@ namespace Umbraco.Web.Routing
if (culture != null) // try the supplied culture
{
var cultureDomains = domainsAndUris.Where(x => x.Culture.Name.InvariantEquals(culture)).ToList();
var cultureDomains = domainsAndUris.Where(x => x.Culture.InvariantEquals(culture)).ToList();
if (cultureDomains.Count > 0) return cultureDomains;
}
if (defaultCulture != null) // try the defaultCulture culture
{
var cultureDomains = domainsAndUris.Where(x => x.Culture.Name.InvariantEquals(defaultCulture)).ToList();
var cultureDomains = domainsAndUris.Where(x => x.Culture.InvariantEquals(defaultCulture)).ToList();
if (cultureDomains.Count > 0) return cultureDomains;
}
@@ -254,13 +254,13 @@ namespace Umbraco.Web.Routing
if (culture != null) // try the supplied culture
{
domainAndUri = domainsAndUris.FirstOrDefault(x => x.Culture.Name.InvariantEquals(culture));
domainAndUri = domainsAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(culture));
if (domainAndUri != null) return domainAndUri;
}
if (defaultCulture != null) // try the defaultCulture culture
{
domainAndUri = domainsAndUris.FirstOrDefault(x => x.Culture.Name.InvariantEquals(defaultCulture));
domainAndUri = domainsAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(defaultCulture));
if (domainAndUri != null) return domainAndUri;
}

View File

@@ -45,7 +45,11 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Gets the content request's culture.
/// </summary>
CultureInfo Culture { get; }
/// <remarks>
/// This will get mapped to a CultureInfo eventually but CultureInfo are expensive to create so we want to leave that up to the
/// localization middleware to do. See https://github.com/dotnet/aspnetcore/blob/b795ac3546eb3e2f47a01a64feb3020794ca33bb/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs#L165.
/// </remarks>
string Culture { get; }
/// <summary>
/// Gets the url to redirect to, when the content request triggers a redirect.

View File

@@ -26,7 +26,7 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Gets the <see cref="CultureInfo"/> assigned (if any)
/// </summary>
CultureInfo Culture { get; }
string Culture { get; }
/// <summary>
/// Gets a value indicating whether the current published content has been obtained
@@ -64,7 +64,7 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Sets the culture for the request
/// </summary>
IPublishedRequestBuilder SetCulture(CultureInfo culture);
IPublishedRequestBuilder SetCulture(string culture);
/// <summary>
/// Sets the found <see cref="IPublishedContent"/> for the request

View File

@@ -13,7 +13,7 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Initializes a new instance of the <see cref="PublishedRequest"/> class.
/// </summary>
public PublishedRequest(Uri uri, IPublishedContent publishedContent, bool isInternalRedirect, ITemplate template, DomainAndUri domain, CultureInfo culture, string redirectUrl, int? responseStatusCode, IReadOnlyList<string> cacheExtensions, IReadOnlyDictionary<string, string> headers, bool cacheabilityNoCache, bool ignorePublishedContentCollisions)
public PublishedRequest(Uri uri, IPublishedContent publishedContent, bool isInternalRedirect, ITemplate template, DomainAndUri domain, string culture, string redirectUrl, int? responseStatusCode, IReadOnlyList<string> cacheExtensions, IReadOnlyDictionary<string, string> headers, bool setNoCacheHeader, bool ignorePublishedContentCollisions)
{
Uri = uri ?? throw new ArgumentNullException(nameof(uri));
PublishedContent = publishedContent;
@@ -25,7 +25,7 @@ namespace Umbraco.Web.Routing
ResponseStatusCode = responseStatusCode;
CacheExtensions = cacheExtensions;
Headers = headers;
SetNoCacheHeader = cacheabilityNoCache;
SetNoCacheHeader = setNoCacheHeader;
IgnorePublishedContentCollisions = ignorePublishedContentCollisions;
}
@@ -48,7 +48,7 @@ namespace Umbraco.Web.Routing
public DomainAndUri Domain { get; }
/// <inheritdoc/>
public CultureInfo Culture { get; }
public string Culture { get; }
/// <inheritdoc/>
public string RedirectUrl { get; }

View File

@@ -36,7 +36,7 @@ namespace Umbraco.Web.Routing
public DomainAndUri Domain { get; private set; }
/// <inheritdoc/>
public CultureInfo Culture { get; private set; }
public string Culture { get; private set; }
/// <inheritdoc/>
public ITemplate Template { get; private set; }
@@ -89,7 +89,7 @@ namespace Umbraco.Web.Routing
}
/// <inheritdoc/>
public IPublishedRequestBuilder SetCulture(CultureInfo culture)
public IPublishedRequestBuilder SetCulture(string culture)
{
Culture = culture;
return this;

View File

@@ -121,15 +121,15 @@ namespace Umbraco.Web.Routing
return request.Build();
}
private void SetVariationContext(CultureInfo culture)
private void SetVariationContext(string culture)
{
VariationContext variationContext = _variationContextAccessor.VariationContext;
if (variationContext != null && variationContext.Culture == culture?.Name)
if (variationContext != null && variationContext.Culture == culture)
{
return;
}
_variationContextAccessor.VariationContext = new VariationContext(culture?.Name);
_variationContextAccessor.VariationContext = new VariationContext(culture);
}
/// <inheritdoc />
@@ -272,7 +272,7 @@ namespace Umbraco.Web.Routing
}
// variant, ensure that the culture corresponding to the domain's language is published
return domainDocument.Cultures.ContainsKey(domain.Culture.Name);
return domainDocument.Cultures.ContainsKey(domain.Culture);
}
domains = domains.Where(IsPublishedContentDomain).ToList();
@@ -302,10 +302,10 @@ namespace Umbraco.Web.Routing
// not matching any existing domain
_logger.LogDebug("{TracePrefix}Matches no domain", tracePrefix);
request.SetCulture(defaultCulture == null ? CultureInfo.CurrentUICulture : new CultureInfo(defaultCulture));
request.SetCulture(defaultCulture ?? CultureInfo.CurrentUICulture.Name);
}
_logger.LogDebug("{TracePrefix}Culture={CultureName}", tracePrefix, request.Culture.Name);
_logger.LogDebug("{TracePrefix}Culture={CultureName}", tracePrefix, request.Culture);
return request.Domain != null;
}
@@ -331,7 +331,7 @@ namespace Umbraco.Web.Routing
if (domain != null)
{
request.SetCulture(domain.Culture);
_logger.LogDebug("{TracePrefix}Got domain on node {DomainContentId}, set culture to {CultureName}", tracePrefix, domain.ContentId, request.Culture.Name);
_logger.LogDebug("{TracePrefix}Got domain on node {DomainContentId}, set culture to {CultureName}", tracePrefix, domain.ContentId, request.Culture);
}
else
{
@@ -665,7 +665,14 @@ namespace Umbraco.Web.Routing
var templateId = request.PublishedContent.TemplateId;
ITemplate template = GetTemplate(templateId);
request.SetTemplate(template);
_logger.LogDebug("FindTemplate: Running with template id={TemplateId} alias={TemplateAlias}", template.Id, template.Alias);
if (template != null)
{
_logger.LogDebug("FindTemplate: Running with template id={TemplateId} alias={TemplateAlias}", template.Id, template.Alias);
}
else
{
_logger.LogWarning("FindTemplate: Could not find template with id {TemplateId}", templateId);
}
}
else
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -284,9 +284,11 @@ namespace Umbraco.Web.Routing
// we do our best, but can't do the impossible
// get the "default" domain ie the first one for the culture, else the first one (exists, length > 0)
if (qualifiedSites == null)
return domainAndUris.FirstOrDefault(x => x.Culture.Name.InvariantEquals(culture)) ??
domainAndUris.FirstOrDefault(x => x.Culture.Name.InvariantEquals(defaultCulture)) ??
domainAndUris.First();
{
return domainAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(culture))
?? domainAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(defaultCulture))
?? domainAndUris.First();
}
// find a site that contains the current authority
var currentSite = qualifiedSites.FirstOrDefault(site => site.Value.Contains(currentAuthority));
@@ -308,7 +310,7 @@ namespace Umbraco.Web.Routing
.FirstOrDefault(domainAndUri => domainAndUri != null);
// random, really
ret = ret ?? domainAndUris.FirstOrDefault(x => x.Culture.Name.InvariantEquals(culture)) ?? domainAndUris.First();
ret = ret ?? domainAndUris.FirstOrDefault(x => x.Culture.InvariantEquals(culture)) ?? domainAndUris.First();
return ret;
}

View File

@@ -1,9 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Security.Principal;
using System.Text;
using System.Threading;
namespace Umbraco.Core.Security
@@ -13,7 +9,6 @@ namespace Umbraco.Core.Security
/// <summary>
/// Ensures that the thread culture is set based on the back office user's culture
/// </summary>
/// <param name="identity"></param>
public static void EnsureCulture(this IIdentity identity)
{
var culture = GetCulture(identity);
@@ -27,16 +22,10 @@ namespace Umbraco.Core.Security
{
if (identity is UmbracoBackOfficeIdentity umbIdentity && umbIdentity.IsAuthenticated)
{
return UserCultures.GetOrAdd(umbIdentity.Culture, s => new CultureInfo(s));
return CultureInfo.GetCultureInfo(umbIdentity.Culture);
}
return null;
}
/// <summary>
/// Used so that we aren't creating a new CultureInfo object for every single request
/// </summary>
private static readonly ConcurrentDictionary<string, CultureInfo> UserCultures = new ConcurrentDictionary<string, CultureInfo>();
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Threading.Tasks;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Strings;
@@ -12,35 +13,31 @@ namespace Umbraco.Core.Templates
/// <summary>
/// Renders the template for the specified pageId and an optional altTemplateId
/// </summary>
/// <param name="contentId"></param>
/// <param name="contentId">The content id</param>
/// <param name="altTemplateId">If not specified, will use the template assigned to the node</param>
/// <returns></returns>
IHtmlEncodedString RenderTemplate(int contentId, int? altTemplateId = null);
Task<IHtmlEncodedString> RenderTemplateAsync(int contentId, int? altTemplateId = null);
/// <summary>
/// Renders the macro with the specified alias.
/// </summary>
/// <param name="contentId"></param>
/// <param name="contentId">The content id</param>
/// <param name="alias">The alias.</param>
/// <returns></returns>
IHtmlEncodedString RenderMacro(int contentId, string alias);
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="contentId"></param>
/// <param name="contentId">The content id</param>
/// <param name="alias">The alias.</param>
/// <param name="parameters">The parameters.</param>
/// <returns></returns>
IHtmlEncodedString RenderMacro(int contentId, string alias, object parameters);
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="contentId"></param>
/// <param name="contentId">The content id</param>
/// <param name="alias">The alias.</param>
/// <param name="parameters">The parameters.</param>
/// <returns></returns>
IHtmlEncodedString RenderMacro(int contentId, string alias, IDictionary<string, object> parameters);
/// <summary>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq;
using System.IO;
using Umbraco.Web.Templates;
@@ -8,6 +8,7 @@ using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Strings;
using Umbraco.Web;
using Umbraco.Web.Macros;
using System.Threading.Tasks;
namespace Umbraco.Core.Templates
{
@@ -24,6 +25,9 @@ namespace Umbraco.Core.Templates
private readonly IMacroRenderer _macroRenderer;
private readonly ITemplateRenderer _templateRenderer;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoComponentRenderer"/> class.
/// </summary>
public UmbracoComponentRenderer(IUmbracoContextAccessor umbracoContextAccessor, IMacroRenderer macroRenderer, ITemplateRenderer templateRenderer)
{
_umbracoContextAccessor = umbracoContextAccessor;
@@ -31,76 +35,55 @@ namespace Umbraco.Core.Templates
_templateRenderer = templateRenderer ?? throw new ArgumentNullException(nameof(templateRenderer));
}
/// <summary>
/// Renders the template for the specified pageId and an optional altTemplateId
/// </summary>
/// <param name="contentId"></param>
/// <param name="altTemplateId">If not specified, will use the template assigned to the node</param>
/// <returns></returns>
public IHtmlEncodedString RenderTemplate(int contentId, int? altTemplateId = null)
/// <inheritdoc/>
public async Task<IHtmlEncodedString> RenderTemplateAsync(int contentId, int? altTemplateId = null)
{
using (var sw = new StringWriter())
{
try
{
_templateRenderer.RenderAsync(contentId, altTemplateId, sw);
await _templateRenderer.RenderAsync(contentId, altTemplateId, sw);
}
catch (Exception ex)
{
sw.Write("<!-- Error rendering template with id {0}: '{1}' -->", contentId, ex);
}
return new HtmlEncodedString(sw.ToString());
}
}
/// <summary>
/// Renders the macro with the specified alias.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <returns></returns>
public IHtmlEncodedString RenderMacro(int contentId, string alias)
{
return RenderMacro(contentId, alias, new { });
}
/// <inheritdoc/>
public IHtmlEncodedString RenderMacro(int contentId, string alias) => RenderMacro(contentId, alias, new { });
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <param name="parameters">The parameters.</param>
/// <returns></returns>
public IHtmlEncodedString RenderMacro(int contentId, string alias, object parameters)
{
return RenderMacro(contentId, alias, parameters?.ToDictionary<object>());
}
/// <inheritdoc/>
public IHtmlEncodedString RenderMacro(int contentId, string alias, object parameters) => RenderMacro(contentId, alias, parameters?.ToDictionary<object>());
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <param name="parameters">The parameters.</param>
/// <returns></returns>
/// <inheritdoc/>
public IHtmlEncodedString RenderMacro(int contentId, string alias, IDictionary<string, object> parameters)
{
if (contentId == default)
{
throw new ArgumentException("Invalid content id " + contentId);
}
var content = _umbracoContextAccessor.UmbracoContext.Content?.GetById(contentId);
if (content == null)
{
throw new InvalidOperationException("Cannot render a macro, no content found by id " + contentId);
}
return RenderMacro(content, alias, parameters);
}
/// <inheritdoc/>
public IHtmlEncodedString RenderMacroForContent(IPublishedContent content, string alias, IDictionary<string, object> parameters)
{
if(content == null)
{
throw new InvalidOperationException("Cannot render a macro, IPublishedContent is null");
}
return RenderMacro(content, alias, parameters);
}
@@ -108,16 +91,15 @@ namespace Umbraco.Core.Templates
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="alias">The macro alias.</param>
/// <param name="parameters">The parameters.</param>
/// <param name="content">The content used for macro rendering</param>
/// <returns></returns>
private IHtmlEncodedString RenderMacro(IPublishedContent content, string alias, IDictionary<string, object> parameters)
{
if (content == null) throw new ArgumentNullException(nameof(content));
if (content == null)
{
throw new ArgumentNullException(nameof(content));
}
// TODO: We are doing at ToLower here because for some insane reason the UpdateMacroModel method looks for a lower case match. the whole macro concept needs to be rewritten.
//NOTE: the value could have HTML encoded values, so we need to deal with that
// NOTE: the value could have HTML encoded values, so we need to deal with that
var macroProps = parameters?.ToDictionary(
x => x.Key.ToLowerInvariant(),
i => (i.Value is string) ? WebUtility.HtmlDecode(i.Value.ToString()) : i.Value);

View File

@@ -54,7 +54,7 @@ namespace Umbraco.Web.Routing
_logger.LogDebug("Looking for a page to handle 404.");
// try to find a culture as best as we can
CultureInfo errorCulture = CultureInfo.CurrentUICulture;
string errorCulture = CultureInfo.CurrentUICulture.Name;
if (frequest.Domain != null)
{
errorCulture = frequest.Domain.Culture;
@@ -67,7 +67,7 @@ namespace Umbraco.Web.Routing
while (pos > 1)
{
route = route.Substring(0, pos);
node = umbCtx.Content.GetByRoute(route, culture: frequest?.Culture?.Name);
node = umbCtx.Content.GetByRoute(route, culture: frequest?.Culture);
if (node != null)
{
break;

View File

@@ -21,12 +21,12 @@ namespace Umbraco.Web.Routing
ContentErrorPage[] error404Collection,
IEntityService entityService,
IPublishedContentQuery publishedContentQuery,
CultureInfo errorCulture)
string errorCulture)
{
if (error404Collection.Length > 1)
{
// test if a 404 page exists with current culture thread
ContentErrorPage cultureErr = error404Collection.FirstOrDefault(x => x.Culture == errorCulture.Name)
ContentErrorPage cultureErr = error404Collection.FirstOrDefault(x => x.Culture.InvariantEquals(errorCulture))
?? error404Collection.FirstOrDefault(x => x.Culture == "default"); // there should be a default one!
if (cultureErr != null)

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -86,7 +86,6 @@ namespace Umbraco.Core.Services.Implement
/// <summary>
/// Returns all key/values in storage for the given culture
/// </summary>
/// <returns></returns>
public IDictionary<string, string> GetAllStoredValues(CultureInfo culture)
{
if (culture == null) throw new ArgumentNullException("culture");
@@ -108,16 +107,18 @@ namespace Umbraco.Core.Services.Implement
return result;
}
//convert all areas + keys to a single key with a '/'
// convert all areas + keys to a single key with a '/'
result = GetStoredTranslations(xmlSource, culture);
//merge with the English file in case there's keys in there that don't exist in the local file
var englishCulture = new CultureInfo("en-US");
// merge with the English file in case there's keys in there that don't exist in the local file
var englishCulture = CultureInfo.GetCultureInfo("en-US");
if (culture.Equals(englishCulture) == false)
{
var englishResults = GetStoredTranslations(xmlSource, englishCulture);
foreach (var englishResult in englishResults.Where(englishResult => result.ContainsKey(englishResult.Key) == false))
{
result.Add(englishResult.Key, englishResult.Value);
}
}
}
else
@@ -128,13 +129,13 @@ namespace Umbraco.Core.Services.Implement
return result;
}
//convert all areas + keys to a single key with a '/'
// convert all areas + keys to a single key with a '/'
foreach (var area in _dictionarySource[culture])
{
foreach (var key in area.Value)
{
var dictionaryKey = string.Format("{0}/{1}", area.Key, key.Key);
//i don't think it's possible to have duplicates because we're dealing with a dictionary in the first place, but we'll double check here just in case.
// i don't think it's possible to have duplicates because we're dealing with a dictionary in the first place, but we'll double check here just in case.
if (result.ContainsKey(dictionaryKey) == false)
{
result.Add(dictionaryKey, key.Value);

View File

@@ -461,7 +461,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var domains = _serviceContext.DomainService.GetAll(true);
foreach (var domain in domains
.Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false)
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, CultureInfo.GetCultureInfo(x.LanguageIsoCode), x.IsWildcard)))
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, x.LanguageIsoCode, x.IsWildcard)))
{
_domainStore.SetLocked(domain.Id, domain);
}
@@ -865,7 +865,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (domain == null) continue;
if (domain.RootContentId.HasValue == false) continue; // anomaly
if (domain.LanguageIsoCode.IsNullOrWhiteSpace()) continue; // anomaly
var culture = CultureInfo.GetCultureInfo(domain.LanguageIsoCode);
var culture = domain.LanguageIsoCode;
_domainStore.SetLocked(domain.Id, new Domain(domain.Id, domain.DomainName, domain.RootContentId.Value, culture, domain.IsWildcard));
break;
}

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.CoreThings
public void TestSetup()
{
_savedCulture = Thread.CurrentThread.CurrentCulture;
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB"); // make sure the dates parse correctly
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB"); // make sure the dates parse correctly
}
[TearDown]

View File

@@ -19,8 +19,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
[TearDown]
public void TearDown() => SiteDomainHelper.Clear(); // assuming this works!
private static readonly CultureInfo s_cultureFr = CultureInfo.GetCultureInfo("fr-fr");
private static readonly CultureInfo s_cultureGb = CultureInfo.GetCultureInfo("en-gb");
private static readonly string s_cultureFr = "fr-fr";
private static readonly string s_cultureGb = "en-gb";
[Test]
public void AddSites()
@@ -185,7 +185,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
new Domain(1, "domain1.com", -1, s_cultureGb, false),
};
DomainAndUri[] domainAndUris = DomainAndUris(current, domains);
string output = helper.MapDomain(domainAndUris, current, s_cultureFr.Name, s_cultureFr.Name).Uri.ToString();
string output = helper.MapDomain(domainAndUris, current, s_cultureFr, s_cultureFr).Uri.ToString();
Assert.AreEqual("https://domain1.com/", output);
// will pick it all right
@@ -196,7 +196,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
new Domain(1, "https://domain2.com", -1, s_cultureGb, false)
};
domainAndUris = DomainAndUris(current, domains);
output = helper.MapDomain(domainAndUris, current, s_cultureFr.Name, s_cultureFr.Name).Uri.ToString();
output = helper.MapDomain(domainAndUris, current, s_cultureFr, s_cultureFr).Uri.ToString();
Assert.AreEqual("https://domain1.com/", output);
current = new Uri("https://domain1.com/foo/bar");
@@ -206,7 +206,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
new Domain(1, "https://domain4.com", -1, s_cultureGb, false)
};
domainAndUris = DomainAndUris(current, domains);
output = helper.MapDomain(domainAndUris, current, s_cultureFr.Name, s_cultureFr.Name).Uri.ToString();
output = helper.MapDomain(domainAndUris, current, s_cultureFr, s_cultureFr).Uri.ToString();
Assert.AreEqual("https://domain1.com/", output);
current = new Uri("https://domain4.com/foo/bar");
@@ -216,7 +216,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
new Domain(1, "https://domain4.com", -1, s_cultureGb, false)
};
domainAndUris = DomainAndUris(current, domains);
output = helper.MapDomain(domainAndUris, current, s_cultureFr.Name, s_cultureFr.Name).Uri.ToString();
output = helper.MapDomain(domainAndUris, current, s_cultureFr, s_cultureFr).Uri.ToString();
Assert.AreEqual("https://domain4.com/", output);
}
@@ -240,8 +240,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
new DomainAndUri(new Domain(1, "domain1.com", -1, s_cultureFr, false), current),
new DomainAndUri(new Domain(1, "domain2.com", -1, s_cultureGb, false), current),
}, current,
s_cultureFr.Name,
s_cultureFr.Name).Uri.ToString();
s_cultureFr,
s_cultureFr).Uri.ToString();
Assert.AreEqual("http://domain1.com/", output);
// current is a site1 uri, domains do not contain current
@@ -253,8 +253,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
new DomainAndUri(new Domain(1, "domain1.net", -1, s_cultureFr, false), current),
new DomainAndUri(new Domain(1, "domain2.net", -1, s_cultureGb, false), current)
}, current,
s_cultureFr.Name,
s_cultureFr.Name).Uri.ToString();
s_cultureFr,
s_cultureFr).Uri.ToString();
Assert.AreEqual("http://domain1.net/", output);
// current is a site1 uri, domains do not contain current
@@ -267,8 +267,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
new DomainAndUri(new Domain(1, "domain2.net", -1, s_cultureFr, false), current),
new DomainAndUri(new Domain(1, "domain1.net", -1, s_cultureGb, false), current)
}, current,
s_cultureFr.Name,
s_cultureFr.Name).Uri.ToString();
s_cultureFr,
s_cultureFr).Uri.ToString();
Assert.AreEqual("http://domain1.net/", output);
}
@@ -301,8 +301,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
},
current,
true,
s_cultureFr.Name,
s_cultureFr.Name).ToArray();
s_cultureFr,
s_cultureFr).ToArray();
Assert.AreEqual(1, output.Count());
Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray());
@@ -320,8 +320,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
},
current,
true,
s_cultureFr.Name,
s_cultureFr.Name).ToArray();
s_cultureFr,
s_cultureFr).ToArray();
Assert.AreEqual(1, output.Count());
Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray());
@@ -343,8 +343,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
},
current,
true,
s_cultureFr.Name,
s_cultureFr.Name).ToArray();
s_cultureFr,
s_cultureFr).ToArray();
Assert.AreEqual(3, output.Count());
Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray());
@@ -364,8 +364,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Routing
new DomainAndUri(new Domain(1, "domain1.org", -1, s_cultureGb, false), current), // yes: same site (though bogus setup)
}, current,
true,
s_cultureFr.Name,
s_cultureFr.Name).ToArray();
s_cultureFr,
s_cultureFr).ToArray();
Assert.AreEqual(3, output.Count());
Assert.Contains("http://domain1.org/", output.Select(d => d.Uri.ToString()).ToArray());

View File

@@ -48,7 +48,7 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Web.Routing
sut.SetDomain(
new DomainAndUri(
new Domain(1, "test", 2, CultureInfo.GetCultureInfo("en-AU"), false), new Uri("https://example.com/en-au")));
new Domain(1, "test", 2, "en-AU", false), new Uri("https://example.com/en-au")));
Assert.IsNotNull(sut.Domain);
Assert.IsNotNull(sut.Culture);
@@ -62,8 +62,8 @@ namespace Umbraco.Tests.UnitTests.Umbraco.Core.Web.Routing
IPublishedContent content = Mock.Of<IPublishedContent>(x => x.Id == 1);
ITemplate template = Mock.Of<ITemplate>(x => x.Id == 1);
string[] cacheExt = new[] { "must-revalidate" };
var auCulture = CultureInfo.GetCultureInfo("en-AU");
var usCulture = CultureInfo.GetCultureInfo("en-US");
var auCulture = "en-AU";
var usCulture = "en-US";
var domain = new DomainAndUri(
new Domain(1, "test", 2, auCulture, false), new Uri("https://example.com/en-au"));
IReadOnlyDictionary<string, string> headers = new Dictionary<string, string> { ["Hello"] = "world" };

View File

@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Umbraco.Core;
@@ -19,20 +19,14 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
}
/// <inheritdoc />
public IEnumerable<Domain> GetAll(bool includeWildcards)
{
return _domainService.GetAll(includeWildcards)
public IEnumerable<Domain> GetAll(bool includeWildcards) => _domainService.GetAll(includeWildcards)
.Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false)
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, CultureInfo.GetCultureInfo(x.LanguageIsoCode), x.IsWildcard));
}
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, x.LanguageIsoCode, x.IsWildcard));
/// <inheritdoc />
public IEnumerable<Domain> GetAssigned(int documentId, bool includeWildcards = false)
{
return _domainService.GetAssignedDomains(documentId, includeWildcards)
public IEnumerable<Domain> GetAssigned(int documentId, bool includeWildcards = false) => _domainService.GetAssignedDomains(documentId, includeWildcards)
.Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false)
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, CultureInfo.GetCultureInfo(x.LanguageIsoCode), x.IsWildcard));
}
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, x.LanguageIsoCode, x.IsWildcard));
/// <inheritdoc />
public bool HasAssigned(int documentId, bool includeWildcards = false)

View File

@@ -35,7 +35,7 @@ namespace Umbraco.Tests.PublishedContent
var request = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var content = GetPublishedContentMock();
request.SetPublishedContent(content.Object);
request.SetCulture(new CultureInfo("en-AU"));
request.SetCulture("en-AU");
request.SetRedirect("/hello");
var result = publishedRouter.BuildRequest(request);

View File

@@ -64,7 +64,9 @@ namespace Umbraco.Tests.Routing
publishedRouter.FindDomain(request);
if (expectedNode > 0)
Assert.AreEqual(expectedCulture, request.Culture.Name);
{
Assert.AreEqual(expectedCulture, request.Culture);
}
var finder = new ContentFinderByUrlAlias(LoggerFactory.CreateLogger<ContentFinderByUrlAlias>(), Mock.Of<IPublishedValueFallback>(), VariationContextAccessor, GetUmbracoContextAccessor(umbracoContext));
var result = finder.TryFindContent(request);

View File

@@ -49,8 +49,9 @@ namespace Umbraco.Tests.Routing
Assert.IsTrue(result);
Assert.IsNotNull(frequest.PublishedContent);
Assert.IsNotNull(frequest.GetTemplateAlias());
Assert.AreEqual("blah".ToUpperInvariant(), frequest.GetTemplateAlias().ToUpperInvariant());
var templateAlias = frequest.GetTemplateAlias();
Assert.IsNotNull(templateAlias );
Assert.AreEqual("blah".ToUpperInvariant(), templateAlias.ToUpperInvariant());
}
}
}

View File

@@ -34,7 +34,7 @@ namespace Umbraco.Tests.Routing
var snapshotService = CreatePublishedSnapshotService(globalSettings);
var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings, snapshotService: snapshotService);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext));
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var frequest = await publishedRouter.CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
Assert.IsTrue(globalSettings.HideTopLevelNodeFromPath);
@@ -119,7 +119,7 @@ namespace Umbraco.Tests.Routing
var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext));
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite", -1, CultureInfo.CurrentCulture, false), new Uri("http://mysite/")));
frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite", -1, "en-US", false), new Uri("http://mysite/")));
var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var result = lookup.TryFindContent(frequest);
@@ -147,7 +147,7 @@ namespace Umbraco.Tests.Routing
var umbracoContext = GetUmbracoContext(urlString, globalSettings:globalSettings);
var publishedRouter = CreatePublishedRouter(GetUmbracoContextAccessor(umbracoContext));
var frequest = await publishedRouter .CreateRequestAsync(umbracoContext.CleanedUmbracoUrl);
frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite/æøå", -1, CultureInfo.CurrentCulture, false), new Uri("http://mysite/æøå")));
frequest.SetDomain(new DomainAndUri(new Domain(1, "mysite/æøå", -1, "en-US", false), new Uri("http://mysite/æøå")));
var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var result = lookup.TryFindContent(frequest);

View File

@@ -180,7 +180,7 @@ namespace Umbraco.Tests.Routing
// must lookup domain else lookup by URL fails
publishedRouter.FindDomain(frequest);
Assert.AreEqual(expectedCulture, frequest.Culture.Name);
Assert.AreEqual(expectedCulture, frequest.Culture);
var lookup = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var result = lookup.TryFindContent(frequest);

View File

@@ -275,7 +275,7 @@ namespace Umbraco.Tests.Routing
// lookup domain
publishedRouter.FindDomain(frequest);
Assert.AreEqual(expectedCulture, frequest.Culture.Name);
Assert.AreEqual(expectedCulture, frequest.Culture);
var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var result = finder.TryFindContent(frequest);
@@ -331,7 +331,7 @@ namespace Umbraco.Tests.Routing
publishedRouter.HandleWildcardDomains(frequest);
Assert.IsTrue(result);
Assert.AreEqual(expectedCulture, frequest.Culture.Name);
Assert.AreEqual(expectedCulture, frequest.Culture);
Assert.AreEqual(frequest.PublishedContent.Id, expectedNode);
}
// domains such as "/en" are natively supported, and when instanciating
@@ -377,7 +377,7 @@ namespace Umbraco.Tests.Routing
publishedRouter.FindDomain(frequest);
Assert.IsNotNull(frequest.Domain);
Assert.AreEqual(expectedCulture, frequest.Culture.Name);
Assert.AreEqual(expectedCulture, frequest.Culture);
var finder = new ContentFinderByUrl(LoggerFactory.CreateLogger<ContentFinderByUrl>(), GetUmbracoContextAccessor(umbracoContext));
var result = finder.TryFindContent(frequest);

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -186,8 +186,8 @@ namespace Umbraco.Tests.Routing
if (contentId != 9876) return Enumerable.Empty<Domain>();
return new[]
{
new Domain(2, "example.us", 9876, CultureInfo.GetCultureInfo("en-US"), false), //default
new Domain(3, "example.fr", 9876, CultureInfo.GetCultureInfo("fr-FR"), false)
new Domain(2, "example.us", 9876, "en-US", false), //default
new Domain(3, "example.fr", 9876, "fr-FR", false)
};
});
domainCache.Setup(x => x.DefaultCulture).Returns(CultureInfo.GetCultureInfo("en-US").Name);
@@ -240,8 +240,8 @@ namespace Umbraco.Tests.Routing
if (contentId != 9876) return Enumerable.Empty<Domain>();
return new[]
{
new Domain(2, "example.us", 9876, CultureInfo.GetCultureInfo("en-US"), false), //default
new Domain(3, "example.fr", 9876, CultureInfo.GetCultureInfo("fr-FR"), false)
new Domain(2, "example.us", 9876, "en-US", false), //default
new Domain(3, "example.fr", 9876, "fr-FR", false)
};
});
domainCache.Setup(x => x.DefaultCulture).Returns(CultureInfo.GetCultureInfo("en-US").Name);

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
@@ -50,6 +50,7 @@ namespace Umbraco.Web.BackOffice.Controllers
// get cultures - new-ing instances to get proper display name,
// in the current culture, and not the cached one
// (see notes in Language class about culture info names)
// TODO: Fix this requirement, see https://github.com/umbraco/Umbraco-CMS/issues/3623
return CultureInfo.GetCultures(CultureTypes.AllCultures)
.Where(x => !x.Name.IsNullOrWhiteSpace())
.Select(x => new CultureInfo(x.Name)) // important!

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Umbraco.Core;
@@ -49,7 +50,7 @@ namespace Umbraco.Web.BackOffice.Controllers
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
}
public IEnumerable<Section> GetSections()
public async Task<IEnumerable<Section>> GetSections()
{
var sections = _sectionService.GetAllowedSections(_backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0));
@@ -74,7 +75,7 @@ namespace Umbraco.Web.BackOffice.Controllers
if (hasDashboards) continue;
// get the first tree in the section and get its root node route path
var sectionRoot = appTreeController.GetApplicationTrees(section.Alias, null, null).Result;
var sectionRoot = await appTreeController.GetApplicationTrees(section.Alias, null, null);
section.RoutePath = GetRoutePathForFirstTree(sectionRoot);
}

View File

@@ -212,7 +212,9 @@ namespace Umbraco.Web.BackOffice.Mapping
// NOTE: unfortunately we're not async, we'll use .Result and hope this won't cause a deadlock anywhere for now
var urls = source.GetContentUrlsAsync(_publishedRouter, umbracoContext, _localizationService, _localizedTextService, _contentService, _variationContextAccessor, _loggerFactory.CreateLogger<IContent>(), _uriUtility, _publishedUrlProvider)
.Result
.ConfigureAwait(false)
.GetAwaiter()
.GetResult()
.ToArray();
return urls;

View File

@@ -52,7 +52,7 @@ namespace Umbraco.Web.Common.ActionsResults
await response.WriteAsync("<p>" + _message + "</p>");
}
await response.WriteAsync("<p>This page can be replaced with a custom 404. Check the documentation for \"custom 404\".</p>");
await response.WriteAsync("<p>This page can be replaced with a custom 404. Check the <a target='_blank' href='https://our.umbraco.com/documentation/tutorials/Custom-Error-Pages/'>documentation for \"custom 404\"</a>.</p>");
await response.WriteAsync("<p style=\"border-top: 1px solid #ccc; padding-top: 10px\"><small>This page is intentionally left ugly ;-)</small></p>");
await response.WriteAsync("</body></html>");
}

View File

@@ -1,7 +1,9 @@
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.Options;
using Umbraco.Core.Security;
namespace Umbraco.Web.Common.Localization
@@ -12,6 +14,13 @@ namespace Umbraco.Web.Common.Localization
/// </summary>
public class UmbracoBackOfficeIdentityCultureProvider : RequestCultureProvider
{
private readonly RequestLocalizationOptions _localizationOptions;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoBackOfficeIdentityCultureProvider"/> class.
/// </summary>
public UmbracoBackOfficeIdentityCultureProvider(RequestLocalizationOptions localizationOptions) => _localizationOptions = localizationOptions;
/// <inheritdoc/>
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
@@ -22,6 +31,17 @@ namespace Umbraco.Web.Common.Localization
return NullProviderCultureResult;
}
// We need to dynamically change the supported cultures since we won't ever know what languages are used since
// they are dynamic within Umbraco.
var cultureExists = _localizationOptions.SupportedCultures.Contains(culture);
if (!cultureExists)
{
// add this as a supporting culture
_localizationOptions.SupportedCultures.Add(culture);
_localizationOptions.SupportedUICultures.Add(culture);
}
return Task.FromResult(new ProviderCultureResult(culture.Name));
}
}

View File

@@ -1,8 +1,13 @@
using System.Globalization;
using System;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Umbraco.Web.Common.Routing;
using Umbraco.Web.Routing;
@@ -13,19 +18,42 @@ namespace Umbraco.Web.Common.Localization
/// </summary>
public class UmbracoPublishedContentCultureProvider : RequestCultureProvider
{
private readonly RequestLocalizationOptions _localizationOptions;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoPublishedContentCultureProvider"/> class.
/// </summary>
public UmbracoPublishedContentCultureProvider(RequestLocalizationOptions localizationOptions) => _localizationOptions = localizationOptions;
/// <inheritdoc/>
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
if (httpContext.GetRouteValue(Core.Constants.Web.UmbracoRouteDefinitionDataToken) is UmbracoRouteValues routeValues)
{
CultureInfo culture = routeValues.PublishedRequest?.Culture;
string culture = routeValues.PublishedRequest?.Culture;
if (culture != null)
{
return Task.FromResult(new ProviderCultureResult(culture.Name));
// We need to dynamically change the supported cultures since we won't ever know what languages are used since
// they are dynamic within Umbraco.
// This code to check existence is borrowed from aspnetcore to avoid creating a CultureInfo
// https://github.com/dotnet/aspnetcore/blob/b795ac3546eb3e2f47a01a64feb3020794ca33bb/src/Middleware/Localization/src/RequestLocalizationMiddleware.cs#L165
CultureInfo existingCulture = _localizationOptions.SupportedCultures.FirstOrDefault(supportedCulture =>
StringSegment.Equals(supportedCulture.Name, culture, StringComparison.OrdinalIgnoreCase));
if (existingCulture == null)
{
// add this as a supporting culture
var ci = CultureInfo.GetCultureInfo(culture);
_localizationOptions.SupportedCultures.Add(ci);
_localizationOptions.SupportedUICultures.Add(ci);
}
return Task.FromResult(new ProviderCultureResult(culture));
}
}
return NullProviderCultureResult;
}
}
}

View File

@@ -30,8 +30,8 @@ namespace Umbraco.Web.Common.Localization
options.RequestCultureProviders = new List<IRequestCultureProvider>();
}
options.RequestCultureProviders.Insert(0, new UmbracoBackOfficeIdentityCultureProvider());
options.RequestCultureProviders.Insert(1, new UmbracoPublishedContentCultureProvider());
options.RequestCultureProviders.Insert(0, new UmbracoBackOfficeIdentityCultureProvider(options));
options.RequestCultureProviders.Insert(1, new UmbracoPublishedContentCultureProvider(options));
}
}
}

View File

@@ -87,8 +87,8 @@ namespace Umbraco.Web.Common.Templates
var defaultLanguage = _languageService.GetAllLanguages().FirstOrDefault();
requestBuilder.SetCulture(defaultLanguage == null
? CultureInfo.CurrentUICulture
: defaultLanguage.CultureInfo);
? CultureInfo.CurrentUICulture.Name
: defaultLanguage.CultureInfo.Name);
}
else
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Xml.XPath;
using Umbraco.Core;
@@ -7,6 +7,7 @@ using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Templates;
using Umbraco.Core.Strings;
using Umbraco.Core.Xml;
using System.Threading.Tasks;
namespace Umbraco.Web.Website
{
@@ -95,13 +96,10 @@ namespace Umbraco.Web.Website
/// <summary>
/// Renders the template for the specified pageId and an optional altTemplateId
/// </summary>
/// <param name="contentId"></param>
/// <param name="contentId">The content id</param>
/// <param name="altTemplateId">If not specified, will use the template assigned to the node</param>
/// <returns></returns>
public IHtmlEncodedString RenderTemplate(int contentId, int? altTemplateId = null)
{
return _componentRenderer.RenderTemplate(contentId, altTemplateId);
}
public async Task<IHtmlEncodedString> RenderTemplateAsync(int contentId, int? altTemplateId = null)
=> await _componentRenderer.RenderTemplateAsync(contentId, altTemplateId);
#region RenderMacro

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
@@ -12,6 +12,7 @@ using Umbraco.Core.Xml;
using Umbraco.Web.Mvc;
using Microsoft.Extensions.Logging;
using Umbraco.Web.Security;
using System.Threading.Tasks;
namespace Umbraco.Web
{
@@ -104,13 +105,10 @@ namespace Umbraco.Web
/// <summary>
/// Renders the template for the specified pageId and an optional altTemplateId
/// </summary>
/// <param name="contentId"></param>
/// <param name="contentId">The content id</param>
/// <param name="altTemplateId">If not specified, will use the template assigned to the node</param>
/// <returns></returns>
public IHtmlEncodedString RenderTemplate(int contentId, int? altTemplateId = null)
{
return _componentRenderer.RenderTemplate(contentId, altTemplateId);
}
public async Task<IHtmlEncodedString> RenderTemplateAsync(int contentId, int? altTemplateId = null)
=> await _componentRenderer.RenderTemplateAsync(contentId, altTemplateId);
#region RenderMacro