Removed Moq from tests & enabled .NET Core
- Introduced AssemblyWrapper to enable testing - Cleaned up properties on ResourceManagerStringLocalizer - #15 Change "Strategy" to "Provider" - #19
This commit is contained in:
parent
9384848cc7
commit
4ba159afe7
|
|
@ -36,9 +36,9 @@ namespace LocalizationSample
|
||||||
//}
|
//}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Optionally create an app-specific strategy with just a delegate, e.g. look up user preference from DB.
|
// Optionally create an app-specific provider with just a delegate, e.g. look up user preference from DB.
|
||||||
// Inserting it as position 0 ensures it has priority over any of the default strategies.
|
// Inserting it as position 0 ensures it has priority over any of the default providers.
|
||||||
//options.RequestCultureStrategies.Insert(0, new CustomRequestCultureStrategy(async context =>
|
//options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
|
||||||
//{
|
//{
|
||||||
|
|
||||||
//}));
|
//}));
|
||||||
|
|
@ -74,13 +74,13 @@ $@"<!doctype html>
|
||||||
function useCookie() {{
|
function useCookie() {{
|
||||||
var culture = document.getElementById('culture');
|
var culture = document.getElementById('culture');
|
||||||
var uiCulture = document.getElementById('uiCulture');
|
var uiCulture = document.getElementById('uiCulture');
|
||||||
var cookieValue = '{CookieRequestCultureStrategy.DefaultCookieName}=c='+culture.options[culture.selectedIndex].value+'|uic='+uiCulture.options[uiCulture.selectedIndex].value;
|
var cookieValue = '{CookieRequestCultureProvider.DefaultCookieName}=c='+culture.options[culture.selectedIndex].value+'|uic='+uiCulture.options[uiCulture.selectedIndex].value;
|
||||||
document.cookie = cookieValue;
|
document.cookie = cookieValue;
|
||||||
window.location = window.location.href.split('?')[0];
|
window.location = window.location.href.split('?')[0];
|
||||||
}}
|
}}
|
||||||
|
|
||||||
function clearCookie() {{
|
function clearCookie() {{
|
||||||
document.cookie='{CookieRequestCultureStrategy.DefaultCookieName}=""""';
|
document.cookie='{CookieRequestCultureProvider.DefaultCookieName}=""""';
|
||||||
}}
|
}}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -101,7 +101,7 @@ $@"<!doctype html>
|
||||||
await context.Response.WriteAsync("</form>");
|
await context.Response.WriteAsync("</form>");
|
||||||
await context.Response.WriteAsync("<br />");
|
await context.Response.WriteAsync("<br />");
|
||||||
await context.Response.WriteAsync("<table><tbody>");
|
await context.Response.WriteAsync("<table><tbody>");
|
||||||
await context.Response.WriteAsync($"<tr><th>Winning strategy:</th><td>{requestCultureFeature.Strategy.GetType().Name}</td></tr>");
|
await context.Response.WriteAsync($"<tr><th>Winning provider:</th><td>{requestCultureFeature.Provider.GetType().Name}</td></tr>");
|
||||||
await context.Response.WriteAsync($"<tr><th>{SR["Current request culture:"]}</th><td>{requestCulture.Culture.DisplayName} ({requestCulture.Culture})</td></tr>");
|
await context.Response.WriteAsync($"<tr><th>{SR["Current request culture:"]}</th><td>{requestCulture.Culture.DisplayName} ({requestCulture.Culture})</td></tr>");
|
||||||
await context.Response.WriteAsync($"<tr><th>{SR["Current request UI culture:"]}</th><td>{requestCulture.UICulture.DisplayName} ({requestCulture.UICulture})</td></tr>");
|
await context.Response.WriteAsync($"<tr><th>{SR["Current request UI culture:"]}</th><td>{requestCulture.UICulture.DisplayName} ({requestCulture.UICulture})</td></tr>");
|
||||||
await context.Response.WriteAsync($"<tr><th>{SR["Current thread culture:"]}</th><td>{CultureInfo.CurrentCulture.DisplayName} ({CultureInfo.CurrentCulture})</td></tr>");
|
await context.Response.WriteAsync($"<tr><th>{SR["Current thread culture:"]}</th><td>{CultureInfo.CurrentCulture.DisplayName} ({CultureInfo.CurrentCulture})</td></tr>");
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Localization
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the culture information for a request via the value of the Accept-Language header.
|
/// Determines the culture information for a request via the value of the Accept-Language header.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AcceptLanguageHeaderRequestCultureStrategy : RequestCultureStrategy
|
public class AcceptLanguageHeaderRequestCultureProvider : RequestCultureProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum number of values in the Accept-Language header to attempt to create a <see cref="System.Globalization.CultureInfo"/>
|
/// The maximum number of values in the Accept-Language header to attempt to create a <see cref="System.Globalization.CultureInfo"/>
|
||||||
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Localization
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the culture information for a request via the value of a cookie.
|
/// Determines the culture information for a request via the value of a cookie.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CookieRequestCultureStrategy : RequestCultureStrategy
|
public class CookieRequestCultureProvider : RequestCultureProvider
|
||||||
{
|
{
|
||||||
private static readonly char[] _cookieSeparator = new[] { '|' };
|
private static readonly char[] _cookieSeparator = new[] { '|' };
|
||||||
private static readonly string _culturePrefix = "c=";
|
private static readonly string _culturePrefix = "c=";
|
||||||
|
|
@ -11,23 +11,23 @@ namespace Microsoft.AspNet.Localization
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the culture information for a request via the configured delegate.
|
/// Determines the culture information for a request via the configured delegate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CustomRequestCultureStrategy : RequestCultureStrategy
|
public class CustomRequestCultureProvider : RequestCultureProvider
|
||||||
{
|
{
|
||||||
private readonly Func<HttpContext, Task<RequestCulture>> _strategy;
|
private readonly Func<HttpContext, Task<RequestCulture>> _provider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="CustomRequestCultureStrategy"/> using the specified delegate.
|
/// Creates a new <see cref="CustomRequestCultureProvider"/> using the specified delegate.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="strategy">The strategy delegate.</param>
|
/// <param name="provider">The provider delegate.</param>
|
||||||
public CustomRequestCultureStrategy([NotNull] Func<HttpContext, Task<RequestCulture>> strategy)
|
public CustomRequestCultureProvider([NotNull] Func<HttpContext, Task<RequestCulture>> provider)
|
||||||
{
|
{
|
||||||
_strategy = strategy;
|
_provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override Task<RequestCulture> DetermineRequestCulture([NotNull] HttpContext httpContext)
|
public override Task<RequestCulture> DetermineRequestCulture([NotNull] HttpContext httpContext)
|
||||||
{
|
{
|
||||||
return _strategy(httpContext);
|
return _provider(httpContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,10 +14,10 @@ namespace Microsoft.AspNet.Localization
|
||||||
RequestCulture RequestCulture { get; }
|
RequestCulture RequestCulture { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="IRequestCultureStrategy"/> that determined the request's culture information.
|
/// The <see cref="IRequestCultureProvider"/> that determined the request's culture information.
|
||||||
/// If the value is <c>null</c> then no strategy was used and the request's culture was set to the value of
|
/// If the value is <c>null</c> then no provider was used and the request's culture was set to the value of
|
||||||
/// <see cref="RequestLocalizationOptions.DefaultRequestCulture"/>.
|
/// <see cref="RequestLocalizationOptions.DefaultRequestCulture"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IRequestCultureStrategy Strategy { get; }
|
IRequestCultureProvider Provider { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,17 +7,17 @@ using Microsoft.AspNet.Http;
|
||||||
namespace Microsoft.AspNet.Localization
|
namespace Microsoft.AspNet.Localization
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a strategy for determining the culture information of an <see cref="HttpRequest"/>.
|
/// Represents a provider for determining the culture information of an <see cref="HttpRequest"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IRequestCultureStrategy
|
public interface IRequestCultureProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implements the strategy to determine the culture of the given request.
|
/// Implements the provider to determine the culture of the given request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="httpContext">The <see cref="HttpContext"/> for the request.</param>
|
/// <param name="httpContext">The <see cref="HttpContext"/> for the request.</param>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// The determined <see cref="RequestCulture"/>.
|
/// The determined <see cref="RequestCulture"/>.
|
||||||
/// Returns <c>null</c> if the strategy couldn't determine a <see cref="RequestCulture"/>.
|
/// Returns <c>null</c> if the provider couldn't determine a <see cref="RequestCulture"/>.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext);
|
Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext);
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Localization
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines the culture information for a request via values in the query string.
|
/// Determines the culture information for a request via values in the query string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class QueryStringRequestCultureStrategy : RequestCultureStrategy
|
public class QueryStringRequestCultureProvider : RequestCultureProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The key that contains the culture name.
|
/// The key that contains the culture name.
|
||||||
|
|
@ -14,16 +14,16 @@ namespace Microsoft.AspNet.Localization
|
||||||
/// Creates a new <see cref="RequestCultureFeature"/> with the specified <see cref="Localization.RequestCulture"/>.
|
/// Creates a new <see cref="RequestCultureFeature"/> with the specified <see cref="Localization.RequestCulture"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="requestCulture">The <see cref="Localization.RequestCulture"/>.</param>
|
/// <param name="requestCulture">The <see cref="Localization.RequestCulture"/>.</param>
|
||||||
public RequestCultureFeature([NotNull] RequestCulture requestCulture, IRequestCultureStrategy strategy)
|
public RequestCultureFeature([NotNull] RequestCulture requestCulture, IRequestCultureProvider provider)
|
||||||
{
|
{
|
||||||
RequestCulture = requestCulture;
|
RequestCulture = requestCulture;
|
||||||
Strategy = strategy;
|
Provider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public RequestCulture RequestCulture { get; }
|
public RequestCulture RequestCulture { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IRequestCultureStrategy Strategy { get; }
|
public IRequestCultureProvider Provider { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,13 @@
|
||||||
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.Http;
|
using Microsoft.AspNet.Http;
|
||||||
using Microsoft.Framework.Internal;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Localization
|
namespace Microsoft.AspNet.Localization
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An abstract base class strategy for determining the culture information of an <see cref="HttpRequest"/>.
|
/// An abstract base class provider for determining the culture information of an <see cref="HttpRequest"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class RequestCultureStrategy : IRequestCultureStrategy
|
public abstract class RequestCultureProvider : IRequestCultureProvider
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current options for the <see cref="RequestLocalizationMiddleware"/>.
|
/// The current options for the <see cref="RequestLocalizationMiddleware"/>.
|
||||||
|
|
@ -40,23 +40,23 @@ namespace Microsoft.AspNet.Localization
|
||||||
var requestCulture = _options.DefaultRequestCulture ??
|
var requestCulture = _options.DefaultRequestCulture ??
|
||||||
new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
|
new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
|
||||||
|
|
||||||
IRequestCultureStrategy winningStrategy = null;
|
IRequestCultureProvider winningProvider = null;
|
||||||
|
|
||||||
if (_options.RequestCultureStrategies != null)
|
if (_options.RequestCultureProviders != null)
|
||||||
{
|
{
|
||||||
foreach (var strategy in _options.RequestCultureStrategies)
|
foreach (var provider in _options.RequestCultureProviders)
|
||||||
{
|
{
|
||||||
var result = await strategy.DetermineRequestCulture(context);
|
var result = await provider.DetermineRequestCulture(context);
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
requestCulture = result;
|
requestCulture = result;
|
||||||
winningStrategy = strategy;
|
winningProvider = provider;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context.SetFeature<IRequestCultureFeature>(new RequestCultureFeature(requestCulture, winningStrategy));
|
context.SetFeature<IRequestCultureFeature>(new RequestCultureFeature(requestCulture, winningProvider));
|
||||||
|
|
||||||
SetCurrentThreadCulture(requestCulture);
|
SetCurrentThreadCulture(requestCulture);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,17 @@ namespace Microsoft.AspNet.Localization
|
||||||
{
|
{
|
||||||
DefaultRequestCulture = new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
|
DefaultRequestCulture = new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
|
||||||
|
|
||||||
RequestCultureStrategies = new List<IRequestCultureStrategy>
|
RequestCultureProviders = new List<IRequestCultureProvider>
|
||||||
{
|
{
|
||||||
new QueryStringRequestCultureStrategy { Options = this },
|
new QueryStringRequestCultureProvider { Options = this },
|
||||||
new CookieRequestCultureStrategy { Options = this },
|
new CookieRequestCultureProvider { Options = this },
|
||||||
new AcceptLanguageHeaderRequestCultureStrategy { Options = this }
|
new AcceptLanguageHeaderRequestCultureProvider { Options = this }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default <see cref="RequestCulture"/> to use. This value will be used if none of the configured
|
/// The default <see cref="RequestCulture"/> to use. This value will be used if none of the configured
|
||||||
/// <see cref="IRequestCultureStrategy"/> options result in a non-<c>null</c> result.
|
/// <see cref="IRequestCultureProvider"/> options result in a non-<c>null</c> result.
|
||||||
/// Defaults to <see cref="RequestCulture.Culture"/> set to <see cref="CultureInfo.DefaultThreadCurrentCulture"/>
|
/// Defaults to <see cref="RequestCulture.Culture"/> set to <see cref="CultureInfo.DefaultThreadCurrentCulture"/>
|
||||||
/// and <see cref="RequestCulture.UICulture"/> set to <see cref="CultureInfo.DefaultThreadCurrentUICulture"/>.
|
/// and <see cref="RequestCulture.UICulture"/> set to <see cref="CultureInfo.DefaultThreadCurrentUICulture"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -54,16 +54,16 @@ namespace Microsoft.AspNet.Localization
|
||||||
public IList<CultureInfo> SupportedUICultures { get; set; }
|
public IList<CultureInfo> SupportedUICultures { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// An ordered list of strategies used to determine a request's culture information. The first strategy that
|
/// An ordered list of providers used to determine a request's culture information. The first provider that
|
||||||
/// returns a non-<c>null</c> result for a given request will be used.
|
/// returns a non-<c>null</c> result for a given request will be used.
|
||||||
/// Defaults to the following:
|
/// Defaults to the following:
|
||||||
/// <list type="number">
|
/// <list type="number">
|
||||||
/// <item><description><see cref="QueryStringRequestCultureStrategy"/></description></item>
|
/// <item><description><see cref="QueryStringRequestCultureProvider"/></description></item>
|
||||||
/// <item><description><see cref="CookieRequestCultureStrategy"/></description></item>
|
/// <item><description><see cref="CookieRequestCultureProvider"/></description></item>
|
||||||
/// <item><description><see cref="AcceptLanguageHeaderRequestCultureStrategy"/></description></item>
|
/// <item><description><see cref="AcceptLanguageHeaderRequestCultureProvider"/></description></item>
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Improves usability")]
|
[SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly", Justification = "Improves usability")]
|
||||||
public IList<IRequestCultureStrategy> RequestCultureStrategies { get; set; }
|
public IList<IRequestCultureProvider> RequestCultureProviders { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.Framework.Internal;
|
||||||
|
|
||||||
|
namespace Microsoft.Framework.Localization.Internal
|
||||||
|
{
|
||||||
|
public class AssemblyWrapper
|
||||||
|
{
|
||||||
|
public AssemblyWrapper([NotNull] Assembly assembly)
|
||||||
|
{
|
||||||
|
Assembly = assembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Assembly Assembly { get; }
|
||||||
|
|
||||||
|
public virtual string FullName => Assembly.FullName;
|
||||||
|
|
||||||
|
public virtual Stream GetManifestResourceStream(string name) => Assembly.GetManifestResourceStream(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,6 +9,7 @@ using System.Globalization;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Resources;
|
using System.Resources;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
using Microsoft.Framework.Localization.Internal;
|
||||||
|
|
||||||
namespace Microsoft.Framework.Localization
|
namespace Microsoft.Framework.Localization
|
||||||
{
|
{
|
||||||
|
|
@ -18,12 +19,16 @@ namespace Microsoft.Framework.Localization
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ResourceManagerStringLocalizer : IStringLocalizer
|
public class ResourceManagerStringLocalizer : IStringLocalizer
|
||||||
{
|
{
|
||||||
|
private static readonly ConcurrentDictionary<string, IList<string>> _resourceNamesCache =
|
||||||
|
new ConcurrentDictionary<string, IList<string>>();
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, object> _missingManifestCache =
|
private readonly ConcurrentDictionary<string, object> _missingManifestCache =
|
||||||
new ConcurrentDictionary<string, object>();
|
new ConcurrentDictionary<string, object>();
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<string, IList<string>> _resourceNamesCache =
|
private readonly ResourceManager _resourceManager;
|
||||||
new ConcurrentDictionary<string, IList<string>>();
|
private readonly AssemblyWrapper _resourceAssemblyWrapper;
|
||||||
|
private readonly string _resourceBaseName;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="ResourceManagerStringLocalizer"/>.
|
/// Creates a new <see cref="ResourceManagerStringLocalizer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -34,26 +39,23 @@ namespace Microsoft.Framework.Localization
|
||||||
[NotNull] ResourceManager resourceManager,
|
[NotNull] ResourceManager resourceManager,
|
||||||
[NotNull] Assembly resourceAssembly,
|
[NotNull] Assembly resourceAssembly,
|
||||||
[NotNull] string baseName)
|
[NotNull] string baseName)
|
||||||
|
: this(resourceManager, new AssemblyWrapper(resourceAssembly), baseName)
|
||||||
{
|
{
|
||||||
ResourceManager = resourceManager;
|
|
||||||
ResourceAssembly = resourceAssembly;
|
|
||||||
ResourceBaseName = baseName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The <see cref="System.Resources.ResourceManager"/> to read strings from.
|
/// Intended for testing purposes only.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected ResourceManager ResourceManager { get; }
|
public ResourceManagerStringLocalizer(
|
||||||
|
[NotNull] ResourceManager resourceManager,
|
||||||
/// <summary>
|
[NotNull] AssemblyWrapper resourceAssemblyWrapper,
|
||||||
/// The <see cref="Assembly"/> that contains the strings as embedded resources.
|
[NotNull] string baseName)
|
||||||
/// </summary>
|
{
|
||||||
protected Assembly ResourceAssembly { get; }
|
_resourceAssemblyWrapper = resourceAssemblyWrapper;
|
||||||
|
_resourceManager = resourceManager;
|
||||||
/// <summary>
|
_resourceBaseName = baseName;
|
||||||
/// The base name of the embedded resource in the <see cref="Assembly"/> that contains the strings.
|
}
|
||||||
/// </summary>
|
|
||||||
protected string ResourceBaseName { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public virtual LocalizedString this[[NotNull] string name]
|
public virtual LocalizedString this[[NotNull] string name]
|
||||||
|
|
@ -84,16 +86,15 @@ namespace Microsoft.Framework.Localization
|
||||||
public IStringLocalizer WithCulture(CultureInfo culture)
|
public IStringLocalizer WithCulture(CultureInfo culture)
|
||||||
{
|
{
|
||||||
return culture == null
|
return culture == null
|
||||||
? new ResourceManagerStringLocalizer(ResourceManager, ResourceAssembly, ResourceBaseName)
|
? new ResourceManagerStringLocalizer(_resourceManager, _resourceAssemblyWrapper, _resourceBaseName)
|
||||||
: new ResourceManagerWithCultureStringLocalizer(
|
: new ResourceManagerWithCultureStringLocalizer(_resourceManager,
|
||||||
ResourceManager,
|
_resourceAssemblyWrapper,
|
||||||
ResourceAssembly,
|
_resourceBaseName,
|
||||||
ResourceBaseName,
|
|
||||||
culture);
|
culture);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a resource string from the <see cref="ResourceManager"/> and returns <c>null</c> instead of
|
/// Gets a resource string from the <see cref="_resourceManager"/> and returns <c>null</c> instead of
|
||||||
/// throwing exceptions if a match isn't found.
|
/// throwing exceptions if a match isn't found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The name of the string resource.</param>
|
/// <param name="name">The name of the string resource.</param>
|
||||||
|
|
@ -110,7 +111,7 @@ namespace Microsoft.Framework.Localization
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return culture == null ? ResourceManager.GetString(name) : ResourceManager.GetString(name, culture);
|
return culture == null ? _resourceManager.GetString(name) : _resourceManager.GetString(name, culture);
|
||||||
}
|
}
|
||||||
catch (MissingManifestResourceException)
|
catch (MissingManifestResourceException)
|
||||||
{
|
{
|
||||||
|
|
@ -150,10 +151,7 @@ namespace Microsoft.Framework.Localization
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal to allow testing
|
// Internal to allow testing
|
||||||
internal static void ClearResourceNamesCache()
|
internal static void ClearResourceNamesCache() => _resourceNamesCache.Clear();
|
||||||
{
|
|
||||||
_resourceNamesCache.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<string> GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture)
|
private IEnumerable<string> GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture)
|
||||||
{
|
{
|
||||||
|
|
@ -186,19 +184,19 @@ namespace Microsoft.Framework.Localization
|
||||||
|
|
||||||
private IList<string> GetResourceNamesForCulture(CultureInfo culture)
|
private IList<string> GetResourceNamesForCulture(CultureInfo culture)
|
||||||
{
|
{
|
||||||
var resourceStreamName = ResourceBaseName;
|
var resourceStreamName = _resourceBaseName;
|
||||||
if (!string.IsNullOrEmpty(culture.Name))
|
if (!string.IsNullOrEmpty(culture.Name))
|
||||||
{
|
{
|
||||||
resourceStreamName += "." + culture.Name;
|
resourceStreamName += "." + culture.Name;
|
||||||
}
|
}
|
||||||
resourceStreamName += ".resources";
|
resourceStreamName += ".resources";
|
||||||
|
|
||||||
var cacheKey = $"assembly={ResourceAssembly.FullName};resourceStreamName={resourceStreamName}";
|
var cacheKey = $"assembly={_resourceAssemblyWrapper.FullName};resourceStreamName={resourceStreamName}";
|
||||||
|
|
||||||
var cultureResourceNames = _resourceNamesCache.GetOrAdd(cacheKey, key =>
|
var cultureResourceNames = _resourceNamesCache.GetOrAdd(cacheKey, key =>
|
||||||
{
|
{
|
||||||
var names = new List<string>();
|
var names = new List<string>();
|
||||||
using (var cultureResourceStream = ResourceAssembly.GetManifestResourceStream(key))
|
using (var cultureResourceStream = _resourceAssemblyWrapper.GetManifestResourceStream(key))
|
||||||
using (var resources = new ResourceReader(cultureResourceStream))
|
using (var resources = new ResourceReader(cultureResourceStream))
|
||||||
{
|
{
|
||||||
foreach (DictionaryEntry entry in resources)
|
foreach (DictionaryEntry entry in resources)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Resources;
|
using System.Resources;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
using Microsoft.Framework.Localization.Internal;
|
||||||
using Microsoft.Framework.Runtime;
|
using Microsoft.Framework.Runtime;
|
||||||
|
|
||||||
namespace Microsoft.Framework.Localization
|
namespace Microsoft.Framework.Localization
|
||||||
|
|
@ -34,7 +35,7 @@ namespace Microsoft.Framework.Localization
|
||||||
public IStringLocalizer Create([NotNull] Type resourceSource)
|
public IStringLocalizer Create([NotNull] Type resourceSource)
|
||||||
{
|
{
|
||||||
var typeInfo = resourceSource.GetTypeInfo();
|
var typeInfo = resourceSource.GetTypeInfo();
|
||||||
var assembly = typeInfo.Assembly;
|
var assembly = new AssemblyWrapper(typeInfo.Assembly);
|
||||||
var baseName = typeInfo.FullName;
|
var baseName = typeInfo.FullName;
|
||||||
return new ResourceManagerStringLocalizer(new ResourceManager(resourceSource), assembly, baseName);
|
return new ResourceManagerStringLocalizer(new ResourceManager(resourceSource), assembly, baseName);
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +50,10 @@ namespace Microsoft.Framework.Localization
|
||||||
{
|
{
|
||||||
var assembly = Assembly.Load(new AssemblyName(location ?? _applicationEnvironment.ApplicationName));
|
var assembly = Assembly.Load(new AssemblyName(location ?? _applicationEnvironment.ApplicationName));
|
||||||
|
|
||||||
return new ResourceManagerStringLocalizer(new ResourceManager(baseName, assembly), assembly, baseName);
|
return new ResourceManagerStringLocalizer(
|
||||||
|
new ResourceManager(baseName, assembly),
|
||||||
|
new AssemblyWrapper(assembly),
|
||||||
|
baseName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Resources;
|
using System.Resources;
|
||||||
using Microsoft.Framework.Internal;
|
using Microsoft.Framework.Internal;
|
||||||
|
using Microsoft.Framework.Localization.Internal;
|
||||||
|
|
||||||
namespace Microsoft.Framework.Localization
|
namespace Microsoft.Framework.Localization
|
||||||
{
|
{
|
||||||
|
|
@ -35,6 +35,19 @@ namespace Microsoft.Framework.Localization
|
||||||
_culture = culture;
|
_culture = culture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Intended for testing purposes only.
|
||||||
|
/// </summary>
|
||||||
|
public ResourceManagerWithCultureStringLocalizer(
|
||||||
|
[NotNull] ResourceManager resourceManager,
|
||||||
|
[NotNull] AssemblyWrapper assemblyWrapper,
|
||||||
|
[NotNull] string baseName,
|
||||||
|
[NotNull] CultureInfo culture)
|
||||||
|
: base(resourceManager, assemblyWrapper, baseName)
|
||||||
|
{
|
||||||
|
_culture = culture;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override LocalizedString this[[NotNull] string name]
|
public override LocalizedString this[[NotNull] string name]
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Resources;
|
using System.Resources;
|
||||||
using Moq;
|
using Microsoft.Framework.Localization.Internal;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.Framework.Localization.Test
|
namespace Microsoft.Framework.Localization.Test
|
||||||
|
|
@ -18,19 +18,11 @@ namespace Microsoft.Framework.Localization.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ResourceManagerStringLocalizer.ClearResourceNamesCache();
|
ResourceManagerStringLocalizer.ClearResourceNamesCache();
|
||||||
var resourceManager = new Mock<ResourceManager>();
|
|
||||||
var resourceAssembly = new Mock<TestAssembly1>();
|
|
||||||
resourceAssembly.Setup(rm => rm.GetManifestResourceStream(It.IsAny<string>()))
|
|
||||||
.Returns(() => MakeResourceStream());
|
|
||||||
var baseName = "test";
|
var baseName = "test";
|
||||||
var localizer1 = new ResourceManagerStringLocalizer(
|
var resourceAssembly = new TestAssemblyWrapper();
|
||||||
resourceManager.Object,
|
var resourceManager = new TestResourceManager(baseName, resourceAssembly.Assembly);
|
||||||
resourceAssembly.Object,
|
var localizer1 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName);
|
||||||
baseName);
|
var localizer2 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName);
|
||||||
var localizer2 = new ResourceManagerStringLocalizer(
|
|
||||||
resourceManager.Object,
|
|
||||||
resourceAssembly.Object,
|
|
||||||
baseName);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
|
|
@ -41,9 +33,7 @@ namespace Microsoft.Framework.Localization.Test
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var expectedCallCount = GetCultureInfoDepth(CultureInfo.CurrentUICulture);
|
var expectedCallCount = GetCultureInfoDepth(CultureInfo.CurrentUICulture);
|
||||||
resourceAssembly.Verify(
|
Assert.Equal(expectedCallCount, resourceAssembly.GetManifestResourceStreamCallCount);
|
||||||
rm => rm.GetManifestResourceStream(It.IsAny<string>()),
|
|
||||||
Times.Exactly(expectedCallCount));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -51,24 +41,13 @@ namespace Microsoft.Framework.Localization.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
ResourceManagerStringLocalizer.ClearResourceNamesCache();
|
ResourceManagerStringLocalizer.ClearResourceNamesCache();
|
||||||
var resourceManager = new Mock<ResourceManager>();
|
|
||||||
var resourceAssembly1 = new Mock<TestAssembly1>();
|
|
||||||
resourceAssembly1.CallBase = true;
|
|
||||||
var resourceAssembly2 = new Mock<TestAssembly2>();
|
|
||||||
resourceAssembly2.CallBase = true;
|
|
||||||
resourceAssembly1.Setup(rm => rm.GetManifestResourceStream(It.IsAny<string>()))
|
|
||||||
.Returns(() => MakeResourceStream());
|
|
||||||
resourceAssembly2.Setup(rm => rm.GetManifestResourceStream(It.IsAny<string>()))
|
|
||||||
.Returns(() => MakeResourceStream());
|
|
||||||
var baseName = "test";
|
var baseName = "test";
|
||||||
var localizer1 = new ResourceManagerStringLocalizer(
|
var resourceAssembly1 = new TestAssemblyWrapper("Assembly1");
|
||||||
resourceManager.Object,
|
var resourceAssembly2 = new TestAssemblyWrapper("Assembly2");
|
||||||
resourceAssembly1.Object,
|
var resourceManager1 = new TestResourceManager(baseName, resourceAssembly1.Assembly);
|
||||||
baseName);
|
var resourceManager2 = new TestResourceManager(baseName, resourceAssembly2.Assembly);
|
||||||
var localizer2 = new ResourceManagerStringLocalizer(
|
var localizer1 = new ResourceManagerStringLocalizer(resourceManager1, resourceAssembly1, baseName);
|
||||||
resourceManager.Object,
|
var localizer2 = new ResourceManagerStringLocalizer(resourceManager2, resourceAssembly2, baseName);
|
||||||
resourceAssembly2.Object,
|
|
||||||
baseName);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
localizer1.ToList();
|
localizer1.ToList();
|
||||||
|
|
@ -76,12 +55,8 @@ namespace Microsoft.Framework.Localization.Test
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var expectedCallCount = GetCultureInfoDepth(CultureInfo.CurrentUICulture);
|
var expectedCallCount = GetCultureInfoDepth(CultureInfo.CurrentUICulture);
|
||||||
resourceAssembly1.Verify(
|
Assert.Equal(expectedCallCount, resourceAssembly1.GetManifestResourceStreamCallCount);
|
||||||
rm => rm.GetManifestResourceStream(It.IsAny<string>()),
|
Assert.Equal(expectedCallCount, resourceAssembly2.GetManifestResourceStreamCallCount);
|
||||||
Times.Exactly(expectedCallCount));
|
|
||||||
resourceAssembly2.Verify(
|
|
||||||
rm => rm.GetManifestResourceStream(It.IsAny<string>()),
|
|
||||||
Times.Exactly(expectedCallCount));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Stream MakeResourceStream()
|
private static Stream MakeResourceStream()
|
||||||
|
|
@ -114,25 +89,35 @@ namespace Microsoft.Framework.Localization.Test
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestAssembly1 : Assembly
|
public class TestResourceManager : ResourceManager
|
||||||
{
|
{
|
||||||
public override string FullName
|
public TestResourceManager(string baseName, Assembly assembly)
|
||||||
|
: base(baseName, assembly)
|
||||||
{
|
{
|
||||||
get
|
|
||||||
{
|
|
||||||
return nameof(TestAssembly1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string GetString(string name, CultureInfo culture) => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TestAssembly2 : Assembly
|
public class TestAssemblyWrapper : AssemblyWrapper
|
||||||
{
|
{
|
||||||
public override string FullName
|
private readonly string _name;
|
||||||
|
|
||||||
|
public TestAssemblyWrapper(string name = nameof(TestAssemblyWrapper))
|
||||||
|
: base(typeof(TestAssemblyWrapper).GetTypeInfo().Assembly)
|
||||||
{
|
{
|
||||||
get
|
_name = name;
|
||||||
{
|
}
|
||||||
return nameof(TestAssembly2);
|
|
||||||
}
|
public int GetManifestResourceStreamCallCount { get; private set; }
|
||||||
|
|
||||||
|
public override string FullName => _name;
|
||||||
|
|
||||||
|
public override Stream GetManifestResourceStream(string name)
|
||||||
|
{
|
||||||
|
GetManifestResourceStreamCallCount++;
|
||||||
|
return MakeResourceStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Moq": "4.2.1502.911",
|
"xunit": "2.1.0-*",
|
||||||
"xunit": "2.1.0-*",
|
"xunit.runner.dnx": "2.1.0-*",
|
||||||
"xunit.runner.dnx": "2.1.0-*",
|
"Microsoft.Framework.Localization": "1.0.0-*",
|
||||||
"Microsoft.Framework.Localization": "1.0.0-*"
|
"System.Reflection": "4.0.10-*"
|
||||||
},
|
},
|
||||||
|
|
||||||
"commands": {
|
"commands": {
|
||||||
"test": "xunit.runner.dnx"
|
"test": "xunit.runner.dnx"
|
||||||
},
|
},
|
||||||
|
|
||||||
"frameworks": {
|
"frameworks": {
|
||||||
"dnx451": { }
|
"dnx451": { },
|
||||||
}
|
"dnxcore50": { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue