Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing DataAnnotations localization #3396

Merged
merged 1 commit into from
Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,13 @@ public class PortableObjectStringLocalizer : IPluralStringLocalizer
{
private readonly ILocalizationManager _localizationManager;
private readonly ILogger _logger;
private string _context;

private CultureDictionary _dictionary;
private CultureDictionary _parentCultureDictionary;

public string Context { get; private set; }

public PortableObjectStringLocalizer(CultureInfo culture, string context, ILocalizationManager localizationManager, ILogger logger)
public PortableObjectStringLocalizer(string context, ILocalizationManager localizationManager, ILogger logger)
{
Context = context;
_context = context;
_localizationManager = localizationManager;
_logger = logger;
_dictionary = localizationManager.GetDictionary(culture);

if (culture.Parent != null)
{
_parentCultureDictionary = localizationManager.GetDictionary(culture.Parent);
}
}

public LocalizedString this[string name]
Expand All @@ -39,7 +29,8 @@ public LocalizedString this[string name]
throw new ArgumentNullException(nameof(name));
}

var translation = GetTranslation(name, Context, null);
var translation = GetTranslation(name, _context, CultureInfo.CurrentUICulture, null);

return new LocalizedString(name, translation ?? name, translation == null);
}
}
Expand All @@ -57,12 +48,30 @@ public LocalizedString this[string name]

public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
{
return _dictionary.Translations.Select(t => new LocalizedString(t.Key, t.Value.FirstOrDefault()));
var culture = CultureInfo.CurrentUICulture;

while (culture != null)
{
var dictionary = _localizationManager.GetDictionary(culture);

foreach(var entry in dictionary.Translations.Select(t => new LocalizedString(t.Key, t.Value.FirstOrDefault())))
{
yield return entry;
}

if (culture == culture.Parent)
{
break;
}

culture = culture.Parent;
}
}

public IStringLocalizer WithCulture(CultureInfo culture)
{
return new PortableObjectStringLocalizer(culture, Context, _localizationManager, _logger);
// This method is never used in ASP.NET and is made obsolete in future releases.
return this;
}

public (LocalizedString, object[]) GetTranslation(string name, params object[] arguments)
Expand All @@ -75,7 +84,8 @@ public IStringLocalizer WithCulture(CultureInfo culture)
// Check if a plural form is called, which is when the only argument is of type PluralizationArgument
if (arguments.Length == 1 && arguments[0] is PluralizationArgument pluralArgument)
{
var translation = GetTranslation(name, Context, pluralArgument.Count);
var translation = GetTranslation(name, _context, CultureInfo.CurrentUICulture, pluralArgument.Count);

object[] argumentsWithCount;

if (pluralArgument.Arguments.Length > 0)
Expand All @@ -89,7 +99,8 @@ public IStringLocalizer WithCulture(CultureInfo culture)
argumentsWithCount = new object[] { pluralArgument.Count };
}

translation = translation ?? GetTranslation(pluralArgument.Forms, pluralArgument.Count);
translation = translation ?? GetTranslation(pluralArgument.Forms, CultureInfo.CurrentUICulture, pluralArgument.Count);

return (new LocalizedString(name, translation, translation == null), argumentsWithCount);
}
else
Expand All @@ -99,9 +110,12 @@ public IStringLocalizer WithCulture(CultureInfo culture)
}
}

private string GetTranslation(string[] pluralForms, int? count)
private string GetTranslation(string[] pluralForms, CultureInfo culture, int? count)
{
var pluralForm = count.HasValue ? _dictionary.PluralRule(count.Value) : 0;
var dictionary = _localizationManager.GetDictionary(culture);

var pluralForm = count.HasValue ? dictionary.PluralRule(count.Value) : 0;

if (pluralForm >= pluralForms.Length)
{
_logger.LogWarning($"Plural form '{pluralForm}' doesn't exist in values provided by the 'IStringLocalizer.Plural' method. Provided values: {String.Join(", ", pluralForms)}");
Expand All @@ -113,21 +127,28 @@ private string GetTranslation(string[] pluralForms, int? count)
return pluralForms[pluralForm];
}

private string GetTranslation(string name, string context, int? count)
private string GetTranslation(string name, string context, CultureInfo culture, int? count)
{
var key = CultureDictionaryRecord.GetKey(name, context);
try
{
var translation = _dictionary[key, count];
var dictionary = _localizationManager.GetDictionary(culture);

if (translation == null && _parentCultureDictionary != null)
var translation = dictionary[key, count];

if (translation == null && culture.Parent != null && culture.Parent != culture)
{
translation = _parentCultureDictionary[key, count]; // fallback to the parent culture
dictionary = _localizationManager.GetDictionary(culture.Parent);

if (dictionary != null)
{
translation = dictionary[key, count]; // fallback to the parent culture
}
}

if (translation == null && context != null)
{
translation = GetTranslation(name, null, count); // fallback to the translation without context
translation = GetTranslation(name, null, culture, count); // fallback to the translation without context
}

return translation;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Globalization;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;

Expand All @@ -20,7 +19,7 @@ public PortableObjectStringLocalizerFactory(

public IStringLocalizer Create(Type resourceSource)
{
return new PortableObjectStringLocalizer(CultureInfo.CurrentUICulture, resourceSource.FullName, _localizationManager, _logger);
return new PortableObjectStringLocalizer(resourceSource.FullName, _localizationManager, _logger);
}

public IStringLocalizer Create(string baseName, string location)
Expand All @@ -43,7 +42,7 @@ public IStringLocalizer Create(string baseName, string location)

var relativeName = baseName.Substring(index);

return new PortableObjectStringLocalizer(CultureInfo.CurrentUICulture, relativeName, _localizationManager, _logger);
return new PortableObjectStringLocalizer(relativeName, _localizationManager, _logger);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ public void LocalizerReturnsTranslationsFromProvidedDictionary()
SetupDictionary("cs", new[] {
new CultureDictionaryRecord("ball", null, new[] { "míč", "míče", "míčů" })
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), null, _localizationManager.Object, _logger.Object);

var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);

CultureInfo.CurrentUICulture = new CultureInfo("cs");

var translation = localizer["ball"];

Expand All @@ -44,7 +47,10 @@ public void LocalizerReturnsOriginalTextIfTranslationsDoesntExistInProvidedDicti
SetupDictionary("cs", new[] {
new CultureDictionaryRecord("ball", null, new[] { "míč", "míče", "míčů" })
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), null, _localizationManager.Object, _logger.Object);

var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);

CultureInfo.CurrentUICulture = new CultureInfo("cs");

var translation = localizer["car"];

Expand All @@ -55,7 +61,10 @@ public void LocalizerReturnsOriginalTextIfTranslationsDoesntExistInProvidedDicti
public void LocalizerReturnsOriginalTextIfDictionaryIsEmpty()
{
SetupDictionary("cs", new CultureDictionaryRecord[] { });
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), null, _localizationManager.Object, _logger.Object);

var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);

CultureInfo.CurrentUICulture = new CultureInfo("cs");

var translation = localizer["car"];

Expand All @@ -71,7 +80,10 @@ public void LocalizerFallbacksToParentCultureIfTranslationDoesntExistInSpecificC
SetupDictionary("cs-CZ", new[] {
new CultureDictionaryRecord("car", null, new[] { "auto", "auta", "aut" })
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs-cz"), null, _localizationManager.Object, _logger.Object);

var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);

CultureInfo.CurrentUICulture = new CultureInfo("cs-cz");

var translation = localizer["ball"];

Expand All @@ -87,7 +99,9 @@ public void LocalizerReturnsTranslationFromSpecificCultureIfItExists()
SetupDictionary("cs-CZ", new[] {
new CultureDictionaryRecord("ball", null, new[] { "balón", "balóny", "balónů" })
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs-CZ"), null, _localizationManager.Object, _logger.Object);
var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);

CultureInfo.CurrentUICulture = new CultureInfo("cs-CZ");

var translation = localizer["ball"];

Expand All @@ -101,7 +115,9 @@ public void LocalizerReturnsTranslationWithSpecificContext()
new CultureDictionaryRecord("ball", null, new[] { "míč", "míče", "míčů" }),
new CultureDictionaryRecord("ball", "small", new[] { "míček", "míčky", "míčků" })
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), "small", _localizationManager.Object, _logger.Object);
var localizer = new PortableObjectStringLocalizer("small", _localizationManager.Object, _logger.Object);

CultureInfo.CurrentUICulture = new CultureInfo("cs");

var translation = localizer["ball"];

Expand All @@ -115,7 +131,9 @@ public void LocalizerReturnsTranslationWithoutContextIfTranslationWithContextDoe
new CultureDictionaryRecord("ball", null, new[] { "míč", "míče", "míčů" }),
new CultureDictionaryRecord("ball", "big", new[] { "míček", "míčky", "míčků" })
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), "small", _localizationManager.Object, _logger.Object);
var localizer = new PortableObjectStringLocalizer("small", _localizationManager.Object, _logger.Object);

CultureInfo.CurrentUICulture = new CultureInfo("cs");

var translation = localizer["ball"];

Expand All @@ -128,7 +146,9 @@ public void LocalizerReturnsFormattedTranslation()
SetupDictionary("cs", new[] {
new CultureDictionaryRecord("The page (ID:{0}) was deleted.", null, new[] { "Stránka (ID:{0}) byla smazána." })
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), "small", _localizationManager.Object, _logger.Object);
var localizer = new PortableObjectStringLocalizer("small", _localizationManager.Object, _logger.Object);

CultureInfo.CurrentUICulture = new CultureInfo("cs");

var translation = localizer["The page (ID:{0}) was deleted.", 1];

Expand All @@ -141,7 +161,8 @@ public void HtmlLocalizerDoesNotFormatTwiceIfFormattedTranslationContainsCurlyBr
SetupDictionary("cs", new[] {
new CultureDictionaryRecord("The page (ID:{0}) was deleted.", null, new[] { "Stránka (ID:{0}) byla smazána." })
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), "small", _localizationManager.Object, _logger.Object);
var localizer = new PortableObjectStringLocalizer("small", _localizationManager.Object, _logger.Object);
CultureInfo.CurrentUICulture = new CultureInfo("cs");
var htmlLocalizer = new PortableObjectHtmlLocalizer(localizer);
var unformatted = htmlLocalizer["The page (ID:{0}) was deleted.", "{1}"];

Expand Down Expand Up @@ -170,8 +191,8 @@ public void LocalizerReturnsOriginalTextForPluralIfTranslationDoesntExist(string
SetupDictionary("cs", new[] {
new CultureDictionaryRecord("ball", null, new[] { "míč", "míče", "míčů" }),
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), null, _localizationManager.Object, _logger.Object);

var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);
CultureInfo.CurrentUICulture = new CultureInfo("cs");
var translation = localizer.Plural(count, "car", "cars");

Assert.Equal(expected, translation);
Expand All @@ -186,8 +207,8 @@ public void LocalizerReturnsTranslationInCorrectPluralForm(string expected, int
SetupDictionary("cs", new[] {
new CultureDictionaryRecord("ball", null, new[] { "míč", "{0} míče", "{0} míčů" }),
});
var localizer = new PortableObjectStringLocalizer(new CultureInfo("cs"), null, _localizationManager.Object, _logger.Object);

var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);
CultureInfo.CurrentUICulture = new CultureInfo("cs");
var translation = localizer.Plural(count, "ball", "{0} balls", count);

Assert.Equal(expected, translation);
Expand All @@ -200,8 +221,8 @@ public void LocalizerReturnsTranslationInCorrectPluralForm(string expected, int
public void LocalizerReturnsOriginalValuesIfTranslationDoesntExistAndMultiplePluraflFormsAreSpecified(string expected, int count)
{
SetupDictionary("en", new CultureDictionaryRecord[] { });
var localizer = new PortableObjectStringLocalizer(new CultureInfo("en"), null, _localizationManager.Object, _logger.Object);

var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);
CultureInfo.CurrentUICulture = new CultureInfo("en");
var translation = localizer.Plural(count, new[] { "míč", "{0} míče", "{0} míčů" }, count);

Assert.Equal(expected, translation);
Expand All @@ -215,8 +236,8 @@ public void LocalizerReturnsCorrectPluralFormIfMultiplePluraflFormsAreSpecified(
SetupDictionary("en", new CultureDictionaryRecord[] {
new CultureDictionaryRecord("míč", null, new[] { "ball", "{0} balls" })
}, _enPluralRule);
var localizer = new PortableObjectStringLocalizer(new CultureInfo("en"), null, _localizationManager.Object, _logger.Object);

var localizer = new PortableObjectStringLocalizer(null, _localizationManager.Object, _logger.Object);
CultureInfo.CurrentUICulture = new CultureInfo("en");
var translation = localizer.Plural(count, new[] { "míč", "{0} míče", "{0} míčů" }, count);

Assert.Equal(expected, translation);
Expand Down