Merge branch 'release' into dev

This commit is contained in:
damianedwards 2015-05-28 12:16:51 -07:00
commit b583c46372
6 changed files with 83 additions and 39 deletions

View File

@ -0,0 +1,22 @@
// 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;
using System.Collections.Generic;
namespace Microsoft.Framework.Localization
{
/// <summary>
/// Represents a cache of string names in resources.
/// </summary>
public interface IResourceNamesCache
{
/// <summary>
/// Adds a set of resource names to the cache by using the specified function, if the name does not already exist.
/// </summary>
/// <param name="name">The resource name to add string names for.</param>
/// <param name="valueFactory">The function used to generate the string names for the resource.</param>
/// <returns>The string names for the resource.</returns>
IList<string> GetOrAdd(string name, Func<string, IList<string>> valueFactory);
}
}

View File

@ -18,12 +18,10 @@ 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 readonly IResourceNamesCache _resourceNamesCache;
private readonly ResourceManager _resourceManager; private readonly ResourceManager _resourceManager;
private readonly AssemblyWrapper _resourceAssemblyWrapper; private readonly AssemblyWrapper _resourceAssemblyWrapper;
private readonly string _resourceBaseName; private readonly string _resourceBaseName;
@ -34,11 +32,13 @@ namespace Microsoft.Framework.Localization
/// <param name="resourceManager">The <see cref="System.Resources.ResourceManager"/> to read strings from.</param> /// <param name="resourceManager">The <see cref="System.Resources.ResourceManager"/> to read strings from.</param>
/// <param name="resourceAssembly">The <see cref="Assembly"/> that contains the strings as embedded resources.</param> /// <param name="resourceAssembly">The <see cref="Assembly"/> that contains the strings as embedded resources.</param>
/// <param name="baseName">The base name of the embedded resource in the <see cref="Assembly"/> that contains the strings.</param> /// <param name="baseName">The base name of the embedded resource in the <see cref="Assembly"/> that contains the strings.</param>
/// <param name="resourceNamesCache">Cache of the list of strings for a given resource assembly name.</param>
public ResourceManagerStringLocalizer( public ResourceManagerStringLocalizer(
[NotNull] ResourceManager resourceManager, [NotNull] ResourceManager resourceManager,
[NotNull] Assembly resourceAssembly, [NotNull] Assembly resourceAssembly,
[NotNull] string baseName) [NotNull] string baseName,
: this(resourceManager, new AssemblyWrapper(resourceAssembly), baseName) [NotNull] IResourceNamesCache resourceNamesCache)
: this(resourceManager, new AssemblyWrapper(resourceAssembly), baseName, resourceNamesCache)
{ {
} }
@ -49,11 +49,13 @@ namespace Microsoft.Framework.Localization
public ResourceManagerStringLocalizer( public ResourceManagerStringLocalizer(
[NotNull] ResourceManager resourceManager, [NotNull] ResourceManager resourceManager,
[NotNull] AssemblyWrapper resourceAssemblyWrapper, [NotNull] AssemblyWrapper resourceAssemblyWrapper,
[NotNull] string baseName) [NotNull] string baseName,
[NotNull] IResourceNamesCache resourceNamesCache)
{ {
_resourceAssemblyWrapper = resourceAssemblyWrapper; _resourceAssemblyWrapper = resourceAssemblyWrapper;
_resourceManager = resourceManager; _resourceManager = resourceManager;
_resourceBaseName = baseName; _resourceBaseName = baseName;
_resourceNamesCache = resourceNamesCache;
} }
/// <inheritdoc /> /// <inheritdoc />
@ -85,10 +87,16 @@ namespace Microsoft.Framework.Localization
public IStringLocalizer WithCulture(CultureInfo culture) public IStringLocalizer WithCulture(CultureInfo culture)
{ {
return culture == null return culture == null
? new ResourceManagerStringLocalizer(_resourceManager, _resourceAssemblyWrapper, _resourceBaseName) ? new ResourceManagerStringLocalizer(
: new ResourceManagerWithCultureStringLocalizer(_resourceManager, _resourceManager,
_resourceAssemblyWrapper, _resourceAssemblyWrapper.Assembly,
_resourceBaseName, _resourceBaseName,
_resourceNamesCache)
: new ResourceManagerWithCultureStringLocalizer(
_resourceManager,
_resourceAssemblyWrapper.Assembly,
_resourceBaseName,
_resourceNamesCache,
culture); culture);
} }
@ -143,9 +151,6 @@ namespace Microsoft.Framework.Localization
} }
} }
// Internal to allow testing
internal static void ClearResourceNamesCache() => _resourceNamesCache.Clear();
private IEnumerable<string> GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture) private IEnumerable<string> GetResourceNamesFromCultureHierarchy(CultureInfo startingCulture)
{ {
var currentCulture = startingCulture; var currentCulture = startingCulture;

View File

@ -5,7 +5,6 @@ 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
@ -15,6 +14,8 @@ namespace Microsoft.Framework.Localization
/// </summary> /// </summary>
public class ResourceManagerStringLocalizerFactory : IStringLocalizerFactory public class ResourceManagerStringLocalizerFactory : IStringLocalizerFactory
{ {
private readonly IResourceNamesCache _resourceNamesCache = new ResourceNamesCache();
private readonly IApplicationEnvironment _applicationEnvironment; private readonly IApplicationEnvironment _applicationEnvironment;
/// <summary> /// <summary>
@ -35,9 +36,13 @@ 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 = new AssemblyWrapper(typeInfo.Assembly); var assembly = 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,
_resourceNamesCache);
} }
/// <summary> /// <summary>
@ -52,8 +57,9 @@ namespace Microsoft.Framework.Localization
return new ResourceManagerStringLocalizer( return new ResourceManagerStringLocalizer(
new ResourceManager(baseName, assembly), new ResourceManager(baseName, assembly),
new AssemblyWrapper(assembly), assembly,
baseName); baseName,
_resourceNamesCache);
} }
} }
} }

View File

@ -6,7 +6,6 @@ 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
{ {
@ -24,26 +23,15 @@ namespace Microsoft.Framework.Localization
/// <param name="resourceManager">The <see cref="System.Resources.ResourceManager"/> to read strings from.</param> /// <param name="resourceManager">The <see cref="System.Resources.ResourceManager"/> to read strings from.</param>
/// <param name="resourceAssembly">The <see cref="Assembly"/> that contains the strings as embedded resources.</param> /// <param name="resourceAssembly">The <see cref="Assembly"/> that contains the strings as embedded resources.</param>
/// <param name="baseName">The base name of the embedded resource in the <see cref="Assembly"/> that contains the strings.</param> /// <param name="baseName">The base name of the embedded resource in the <see cref="Assembly"/> that contains the strings.</param>
/// <param name="resourceNamesCache">Cache of the list of strings for a given resource assembly name.</param>
/// <param name="culture">The specific <see cref="CultureInfo"/> to use.</param> /// <param name="culture">The specific <see cref="CultureInfo"/> to use.</param>
public ResourceManagerWithCultureStringLocalizer( public ResourceManagerWithCultureStringLocalizer(
[NotNull] ResourceManager resourceManager, [NotNull] ResourceManager resourceManager,
[NotNull] Assembly assembly, [NotNull] Assembly resourceAssembly,
[NotNull] string baseName, [NotNull] string baseName,
[NotNull] IResourceNamesCache resourceNamesCache,
[NotNull] CultureInfo culture) [NotNull] CultureInfo culture)
: base(resourceManager, assembly, baseName) : base(resourceManager, resourceAssembly, baseName, resourceNamesCache)
{
_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; _culture = culture;
} }

View File

@ -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;
using System.Collections.Concurrent;
using System.Collections.Generic;
namespace Microsoft.Framework.Localization
{
/// <summary>
/// An implementation of <see cref="IResourceNamesCache"/> backed by a <see cref="ConcurrentDictionary{TKey, TValue}"/>.
/// </summary>
public class ResourceNamesCache : IResourceNamesCache
{
private readonly ConcurrentDictionary<string, IList<string>> _cache = new ConcurrentDictionary<string, IList<string>>();
/// <inheritdoc />
public IList<string> GetOrAdd(string name, Func<string, IList<string>> valueFactory)
{
return _cache.GetOrAdd(name, valueFactory);
}
}
}

View File

@ -17,12 +17,12 @@ namespace Microsoft.Framework.Localization.Test
public void EnumeratorCachesCultureWalkForSameAssembly() public void EnumeratorCachesCultureWalkForSameAssembly()
{ {
// Arrange // Arrange
ResourceManagerStringLocalizer.ClearResourceNamesCache(); var resourceNamesCache = new ResourceNamesCache();
var baseName = "test"; var baseName = "test";
var resourceAssembly = new TestAssemblyWrapper(); var resourceAssembly = new TestAssemblyWrapper();
var resourceManager = new TestResourceManager(baseName, resourceAssembly.Assembly); var resourceManager = new TestResourceManager(baseName, resourceAssembly.Assembly);
var localizer1 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName); var localizer1 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName, resourceNamesCache);
var localizer2 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName); var localizer2 = new ResourceManagerStringLocalizer(resourceManager, resourceAssembly, baseName, resourceNamesCache);
// Act // Act
for (int i = 0; i < 5; i++) for (int i = 0; i < 5; i++)
@ -40,14 +40,14 @@ namespace Microsoft.Framework.Localization.Test
public void EnumeratorCacheIsScopedByAssembly() public void EnumeratorCacheIsScopedByAssembly()
{ {
// Arrange // Arrange
ResourceManagerStringLocalizer.ClearResourceNamesCache(); var resourceNamesCache = new ResourceNamesCache();
var baseName = "test"; var baseName = "test";
var resourceAssembly1 = new TestAssemblyWrapper("Assembly1"); var resourceAssembly1 = new TestAssemblyWrapper("Assembly1");
var resourceAssembly2 = new TestAssemblyWrapper("Assembly2"); var resourceAssembly2 = new TestAssemblyWrapper("Assembly2");
var resourceManager1 = new TestResourceManager(baseName, resourceAssembly1.Assembly); var resourceManager1 = new TestResourceManager(baseName, resourceAssembly1.Assembly);
var resourceManager2 = new TestResourceManager(baseName, resourceAssembly2.Assembly); var resourceManager2 = new TestResourceManager(baseName, resourceAssembly2.Assembly);
var localizer1 = new ResourceManagerStringLocalizer(resourceManager1, resourceAssembly1, baseName); var localizer1 = new ResourceManagerStringLocalizer(resourceManager1, resourceAssembly1, baseName, resourceNamesCache);
var localizer2 = new ResourceManagerStringLocalizer(resourceManager2, resourceAssembly2, baseName); var localizer2 = new ResourceManagerStringLocalizer(resourceManager2, resourceAssembly2, baseName, resourceNamesCache);
// Act // Act
localizer1.ToList(); localizer1.ToList();