Merge branch 'release' into dev

This commit is contained in:
Kirthi Krishnamraju 2015-07-16 16:09:29 -07:00
commit d06dcbc996
39 changed files with 2178 additions and 44 deletions

View File

@ -84,6 +84,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Cors.T
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.DataAnnotations.Test", "test\Microsoft.AspNet.Mvc.DataAnnotations.Test\Microsoft.AspNet.Mvc.DataAnnotations.Test.xproj", "{827DBBCB-F3A9-4BAD-8262-4BD43E28EB3B}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Localization", "src\Microsoft.AspNet.Mvc.Localization\Microsoft.AspNet.Mvc.Localization.xproj", "{50893B10-5735-4F35-9995-F81DA3F0189E}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Localization.Test", "test\Microsoft.AspNet.Mvc.Localization.Test\Microsoft.AspNet.Mvc.Localization.Test.xproj", "{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -371,7 +375,7 @@ Global
{F21E225B-190B-4DAA-8B0A-05986D231F56}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{F21E225B-190B-4DAA-8B0A-05986D231F56}.Release|x86.ActiveCfg = Release|Any CPU
{F21E225B-190B-4DAA-8B0A-05986D231F56}.Release|x86.Build.0 = Release|Any CPU
{3F8B8FC1-9FE4-4788-8991-367113E8D7AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F8B8FC1-9FE4-4788-8991-367113E8D7AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3F8B8FC1-9FE4-4788-8991-367113E8D7AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3F8B8FC1-9FE4-4788-8991-367113E8D7AD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{3F8B8FC1-9FE4-4788-8991-367113E8D7AD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
@ -491,6 +495,30 @@ Global
{827DBBCB-F3A9-4BAD-8262-4BD43E28EB3B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{827DBBCB-F3A9-4BAD-8262-4BD43E28EB3B}.Release|x86.ActiveCfg = Release|Any CPU
{827DBBCB-F3A9-4BAD-8262-4BD43E28EB3B}.Release|x86.Build.0 = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|x86.ActiveCfg = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|x86.Build.0 = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|Any CPU.Build.0 = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|x86.ActiveCfg = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|x86.Build.0 = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|x86.ActiveCfg = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|x86.Build.0 = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|Any CPU.Build.0 = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|x86.ActiveCfg = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -531,5 +559,7 @@ Global
{2DD786CA-7AF7-437A-B499-801A589B9A1C} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{6BB4C20B-24C0-45D6-9E4C-C2620959BDD5} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{827DBBCB-F3A9-4BAD-8262-4BD43E28EB3B} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{50893B10-5735-4F35-9995-F81DA3F0189E} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
EndGlobalSection
EndGlobal

30
Mvc.sln
View File

@ -184,6 +184,10 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.DataAn
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.ViewFeatures.Test", "test\Microsoft.AspNet.Mvc.ViewFeatures.Test\Microsoft.AspNet.Mvc.ViewFeatures.Test.xproj", "{60873DFA-97B9-419E-BAA3-940FC9B07085}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Localization", "src\Microsoft.AspNet.Mvc.Localization\Microsoft.AspNet.Mvc.Localization.xproj", "{50893B10-5735-4F35-9995-F81DA3F0189E}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Localization.Test", "test\Microsoft.AspNet.Mvc.Localization.Test\Microsoft.AspNet.Mvc.Localization.Test.xproj", "{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -1126,6 +1130,30 @@ Global
{60873DFA-97B9-419E-BAA3-940FC9B07085}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{60873DFA-97B9-419E-BAA3-940FC9B07085}.Release|x86.ActiveCfg = Release|Any CPU
{60873DFA-97B9-419E-BAA3-940FC9B07085}.Release|x86.Build.0 = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|x86.ActiveCfg = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Debug|x86.Build.0 = Debug|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|Any CPU.Build.0 = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|x86.ActiveCfg = Release|Any CPU
{50893B10-5735-4F35-9995-F81DA3F0189E}.Release|x86.Build.0 = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|x86.ActiveCfg = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Debug|x86.Build.0 = Debug|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|Any CPU.Build.0 = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|x86.ActiveCfg = Release|Any CPU
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1216,5 +1244,7 @@ Global
{6BB4C20B-24C0-45D6-9E4C-C2620959BDD5} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{827DBBCB-F3A9-4BAD-8262-4BD43E28EB3B} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{60873DFA-97B9-419E-BAA3-940FC9B07085} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{50893B10-5735-4F35-9995-F81DA3F0189E} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E}
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
EndGlobalSection
EndGlobal

View File

@ -37,6 +37,7 @@ namespace Microsoft.AspNet.Mvc
"Microsoft.AspNet.Mvc.DataAnnotations",
"Microsoft.AspNet.Mvc.Formatters.Json",
"Microsoft.AspNet.Mvc.Formatters.Xml",
"Microsoft.AspNet.Mvc.Localization",
"Microsoft.AspNet.Mvc.Razor",
"Microsoft.AspNet.Mvc.Razor.Host",
"Microsoft.AspNet.Mvc.TagHelpers",

View File

@ -0,0 +1,191 @@
// 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.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Localization;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// An <see cref="IHtmlLocalizer"/> that uses the <see cref="IStringLocalizer"/> to provide localized HTML content.
/// This service just encodes the arguments but not the resource string.
/// </summary>
public class HtmlLocalizer : IHtmlLocalizer
{
private IStringLocalizer _localizer;
private readonly IHtmlEncoder _encoder;
/// <summary>
/// Creates a new <see cref="HtmlLocalizer"/>.
/// </summary>
/// <param name="localizer">The <see cref="IStringLocalizer"/> to read strings from.</param>
/// <param name="encoder">The <see cref="IHtmlEncoder"/>.</param>
public HtmlLocalizer([NotNull] IStringLocalizer localizer, [NotNull] IHtmlEncoder encoder)
{
_localizer = localizer;
_encoder = encoder;
}
/// <inheritdoc />
public virtual LocalizedString this[[NotNull] string key] => _localizer[key];
/// <inheritdoc />
public virtual LocalizedString this[[NotNull] string key, params object[] arguments] =>
_localizer[key, arguments];
/// <summary>
/// Creates a new <see cref="IHtmlLocalizer"/> for a specific <see cref="CultureInfo"/>.
/// </summary>
/// <param name="culture">The <see cref="CultureInfo"/> to use.</param>
/// <returns>A culture-specific <see cref="IHtmlLocalizer"/>.</returns>
public virtual IHtmlLocalizer WithCulture([NotNull] CultureInfo culture) =>
new HtmlLocalizer(_localizer.WithCulture(culture), _encoder);
/// <summary>
/// Creates a new <see cref="IStringLocalizer"/> for a specific <see cref="CultureInfo"/>.
/// </summary>
/// <param name="culture">The <see cref="CultureInfo"/> to use.</param>
/// <returns>A culture-specific <see cref="IStringLocalizer"/>.</returns>
IStringLocalizer IStringLocalizer.WithCulture([NotNull] CultureInfo culture) => WithCulture(culture);
/// <inheritdoc />
public virtual LocalizedString GetString([NotNull] string key) => _localizer.GetString(key);
/// <inheritdoc />
public virtual LocalizedString GetString([NotNull] string key, params object[] arguments) =>
_localizer.GetString(key, arguments);
/// <inheritdoc />
public virtual IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures) =>
_localizer.GetAllStrings(includeAncestorCultures);
/// <inheritdoc />
public virtual LocalizedHtmlString Html([NotNull] string key) => ToHtmlString(_localizer.GetString(key));
/// <inheritdoc />
public virtual LocalizedHtmlString Html([NotNull] string key, params object[] arguments)
{
var stringValue = _localizer[key].Value;
return ToHtmlString(new LocalizedString(key, EncodeArguments(stringValue, arguments)));
}
/// <summary>
/// Creates a new <see cref="LocalizedHtmlString"/> for a <see cref="LocalizedString"/>.
/// </summary>
/// <param name="result">The <see cref="LocalizedString"/>.</param>
protected virtual LocalizedHtmlString ToHtmlString(LocalizedString result) =>
new LocalizedHtmlString(result.Name, result.Value, result.ResourceNotFound);
/// <summary>
/// Encodes the arguments based on the object type.
/// </summary>
/// <param name="resourceString">The resourceString whose arguments need to be encoded.</param>
/// <param name="arguments">The array of objects to encode.</param>
/// <returns>The string with encoded arguments.</returns>
protected virtual string EncodeArguments([NotNull] string resourceString, [NotNull] object[] arguments)
{
var position = 0;
var length = resourceString.Length;
char currentCharacter;
StringBuilder tokenBuffer = null;
var outputBuffer = new StringBuilder();
var isToken = false;
while (position < length)
{
currentCharacter = resourceString[position];
position++;
if (currentCharacter == '}')
{
if (position < length && resourceString[position] == '}') // Treat as escape character for }}
{
if (isToken)
{
tokenBuffer.Append("}}");
}
else
{
outputBuffer.Append("}");
}
position++;
}
else
{
AppendToBuffer(isToken, '}', tokenBuffer, outputBuffer);
if (position == length)
{
break;
}
AppendToOutputBuffer(arguments, tokenBuffer, outputBuffer);
isToken = false;
tokenBuffer = null;
}
}
else if (currentCharacter == '{')
{
if (position < length && resourceString[position] == '{') // Treat as escape character for {{
{
if (isToken)
{
tokenBuffer.Append("{{");
}
else
{
outputBuffer.Append("{");
}
position++;
}
else
{
tokenBuffer = new StringBuilder();
tokenBuffer.Append("{");
isToken = true;
}
}
else
{
AppendToBuffer(isToken, currentCharacter, tokenBuffer, outputBuffer);
}
}
AppendToOutputBuffer(arguments, tokenBuffer, outputBuffer);
return outputBuffer.ToString();
}
private void AppendToBuffer(
bool isToken,
char value,
StringBuilder tokenBuffer,
StringBuilder outputBuffer)
{
if (isToken)
{
tokenBuffer.Append(value);
}
else
{
outputBuffer.Append(value);
}
}
private void AppendToOutputBuffer(object[] arguments, StringBuilder tokenBuffer, StringBuilder outputBuffer)
{
if (tokenBuffer != null && tokenBuffer.Length > 0)
{
outputBuffer.Append(_encoder.HtmlEncode(string.Format(tokenBuffer.ToString(), arguments)));
}
}
}
}

View File

@ -0,0 +1,53 @@
// 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 Microsoft.Framework.Internal;
using Microsoft.Framework.Localization;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// An <see cref="IHtmlLocalizerFactory"/> that creates instances of <see cref="HtmlLocalizer"/>.
/// </summary>
public class HtmlLocalizerFactory : IHtmlLocalizerFactory
{
private readonly IStringLocalizerFactory _factory;
private readonly IHtmlEncoder _encoder;
/// <summary>
/// Creates a new <see cref="HtmlLocalizer"/>.
/// </summary>
/// <param name="localizerFactory">The <see cref="IStringLocalizerFactory"/>.</param>
/// <param name="encoder">The <see cref="IHtmlEncoder"/>.</param>
public HtmlLocalizerFactory([NotNull] IStringLocalizerFactory localizerFactory, [NotNull] IHtmlEncoder encoder)
{
_factory = localizerFactory;
_encoder = encoder;
}
/// <summary>
/// Creates an <see cref="HtmlLocalizer"/> using the <see cref="System.Reflection.Assembly"/> and
/// <see cref="Type.FullName"/> of the specified <see cref="Type"/>.
/// </summary>
/// <param name="resourceSource">The <see cref="Type"/>.</param>
/// <returns>The <see cref="HtmlLocalizer"/>.</returns>
public virtual IHtmlLocalizer Create(Type resourceSource)
{
return new HtmlLocalizer(_factory.Create(resourceSource), _encoder);
}
/// <summary>
/// Creates an <see cref="HtmlLocalizer"/>.
/// </summary>
/// <param name="baseName">The base name of the resource to load strings from.</param>
/// <param name="location">The location to load resources from.</param>
/// <returns>The <see cref="HtmlLocalizer"/>.</returns>
public virtual IHtmlLocalizer Create(string baseName, string location)
{
var localizer = _factory.Create(baseName, location);
return new HtmlLocalizer(localizer, _encoder);
}
}
}

View File

@ -0,0 +1,60 @@
// 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.Collections.Generic;
using System.Globalization;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Localization;
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// This is an <see cref="HtmlLocalizer"/> that provides localized HTML content.
/// </summary>
/// <typeparam name = "TResource"> The <see cref="System.Type"/> to scope the resource names.</typeparam>
public class HtmlLocalizer<TResource> : IHtmlLocalizer<TResource>
{
private readonly IHtmlLocalizer _localizer;
/// <summary>
/// Creates a new <see cref="HtmlLocalizer"/>.
/// </summary>
/// <param name="factory">The <see cref="IHtmlLocalizerFactory"/>.</param>
public HtmlLocalizer(IHtmlLocalizerFactory factory)
{
_localizer = factory.Create(typeof(TResource));
}
/// <inheritdoc />
public virtual LocalizedString this[[NotNull] string key] => _localizer[key];
/// <inheritdoc />
public virtual LocalizedString this[[NotNull] string key, params object[] arguments] =>
_localizer[key, arguments];
/// <inheritdoc />
public virtual IHtmlLocalizer WithCulture([NotNull] CultureInfo culture) => _localizer.WithCulture(culture);
/// <inheritdoc />
IStringLocalizer IStringLocalizer.WithCulture([NotNull] CultureInfo culture) =>
_localizer.WithCulture(culture);
/// <inheritdoc />
public virtual LocalizedString GetString([NotNull] string key) => _localizer.GetString(key);
/// <inheritdoc />
public virtual LocalizedString GetString([NotNull] string key, params object[] arguments) =>
_localizer.GetString(key, arguments);
/// <inheritdoc />
public virtual LocalizedHtmlString Html([NotNull] string key) => _localizer.Html(key);
/// <inheritdoc />
public virtual LocalizedHtmlString Html([NotNull] string key, params object[] arguments) =>
_localizer.Html(key, arguments);
/// <inheritdoc />
public virtual IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures) =>
_localizer.GetAllStrings(includeAncestorCultures);
}
}

View File

@ -0,0 +1,38 @@
// 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.Globalization;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Localization;
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// This service does not HTML encode the resource string. It HTML encodes all arguments that are formatted in
/// the resource string.
/// </summary>
public interface IHtmlLocalizer : IStringLocalizer
{
/// <summary>
/// Creates a new <see cref="HtmlLocalizer"/> for a specific <see cref="CultureInfo"/>.
/// </summary>
/// <param name="culture">The <see cref="CultureInfo"/> to use.</param>
/// <returns>A culture-specific <see cref="IHtmlLocalizer"/>.</returns>
new IHtmlLocalizer WithCulture([NotNull] CultureInfo culture);
/// <summary>
/// Gets the <see cref="LocalizedHtmlString"/> resource for a specific key.
/// </summary>
/// <param name="key">The key to use.</param>
/// <returns>The <see cref="LocalizedHtmlString"/> resource.</returns>
LocalizedHtmlString Html([NotNull] string key);
/// <summary>
/// Gets the <see cref="LocalizedHtmlString"/> resource for a specific key.
/// </summary>
/// <param name="key">The key to use.</param>
/// <param name="arguments">The values to format the string with.</param>
/// <returns>The <see cref="LocalizedHtmlString"/> resource.</returns>
LocalizedHtmlString Html([NotNull] string key, params object[] arguments);
}
}

View File

@ -0,0 +1,30 @@
// 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 Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// A factory that creates <see cref="IHtmlLocalizer"/> instances.
/// </summary>
public interface IHtmlLocalizerFactory
{
/// <summary>
/// Creates an <see cref="IHtmlLocalizer"/> using the <see cref="System.Reflection.Assembly"/> and
/// <see cref="Type.FullName"/> of the specified <see cref="Type"/>.
/// </summary>
/// <param name="resourceSource">The <see cref="Type"/>.</param>
/// <returns>The <see cref="IHtmlLocalizer"/>.</returns>
IHtmlLocalizer Create([NotNull] Type resourceSource);
/// <summary>
/// Creates an <see cref="IHtmlLocalizer"/>.
/// </summary>
/// <param name="baseName">The base name of the resource to load strings from.</param>
/// <param name="location">The location to load resources from.</param>
/// <returns>The <see cref="IHtmlLocalizer"/>.</returns>
IHtmlLocalizer Create([NotNull] string baseName, [NotNull] string location);
}
}

View File

@ -0,0 +1,13 @@
// 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.
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// An <see cref="IHtmlLocalizer"/> that provides localized HTML content.
/// </summary>
/// <typeparam name = "TResource"> The <see cref="System.Type"/> to scope the resource names.</typeparam>
public interface IHtmlLocalizer<TResource> : IHtmlLocalizer
{
}
}

View File

@ -0,0 +1,12 @@
// 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.
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// A service that provides localized strings for views.
/// </summary>
public interface IViewLocalizer : IHtmlLocalizer
{
}
}

View File

@ -0,0 +1,51 @@
// 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 Microsoft.AspNet.Mvc.Rendering;
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// An <see cref="HtmlString"/> with localized content.
/// </summary>
public class LocalizedHtmlString : HtmlString
{
/// <summary>
/// Creates an instance of <see cref="LocalizedHtmlString"/>.
/// </summary>
/// <param name="key">The name of the string resource.</param>
/// <param name="value">The string resource.</param>
public LocalizedHtmlString(string key, string value)
: this(key, value, isResourceNotFound: false)
{
}
/// <summary>
/// Creates an instance of <see cref="LocalizedHtmlString"/>.
/// </summary>
/// <param name="key">The name of the string resource.</param>
/// <param name="value">The string resource.</param>
/// <param name="isResourceNotFound">A flag that indicates if the resource is not found.</param>
public LocalizedHtmlString(string key, string value, bool isResourceNotFound)
: base(value)
{
Key = key;
IsResourceNotFound = isResourceNotFound;
}
/// <summary>
/// The name of the string resource.
/// </summary>
public string Key { get; }
/// <summary>
/// The string resource.
/// </summary>
public string Value => ToString();
/// <summary>
/// Gets a flag that indicates if the resource is not found.
/// </summary>
public bool IsResourceNotFound { get; }
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>50893b10-5735-4f35-9995-f81da3f0189e</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -0,0 +1,52 @@
// 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.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Localization;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.Internal;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.Framework.DependencyInjection
{
public static class MvcLocalizationServiceCollectionExtensions
{
/// <summary>
/// Adds Mvc localization to the application.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddMvcLocalization([NotNull] this IServiceCollection services)
{
return AddMvcLocalization(services, LanguageViewLocationExpanderFormat.Suffix);
}
/// <summary>
/// Adds Mvc localization to the application.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="option">The view format for localized views.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddMvcLocalization(
[NotNull] this IServiceCollection services,
LanguageViewLocationExpanderFormat format)
{
services.Configure<RazorViewEngineOptions>(
options =>
{
options.ViewLocationExpanders.Add(new LanguageViewLocationExpander(format));
},
DefaultOrder.DefaultFrameworkSortOrder);
services.TryAdd(ServiceDescriptor.Singleton<IHtmlLocalizerFactory, HtmlLocalizerFactory>());
services.TryAdd(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(HtmlLocalizer<>)));
services.TryAdd(ServiceDescriptor.Transient<IViewLocalizer, ViewLocalizer>());
if (!services.Any(sd => sd.ServiceType == typeof(IHtmlEncoder)))
{
services.TryAdd(ServiceDescriptor.Instance<IHtmlEncoder>(HtmlEncoder.Default));
}
return services.AddLocalization();
}
}
}

View File

@ -0,0 +1,62 @@
// <auto-generated />
namespace Microsoft.AspNet.Mvc.Localization
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.AspNet.Mvc.Localization.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Must call CreateStringLocalizer method before using this property.
/// </summary>
internal static string NullStringLocalizer
{
get { return GetString("NullStringLocalizer"); }
}
/// <summary>
/// Must call CreateStringLocalizer method before using this property.
/// </summary>
internal static string FormatNullStringLocalizer()
{
return GetString("NullStringLocalizer");
}
/// <summary>
/// IStringLocalizerFactory is null. Must call other constructor overload to use this property.
/// </summary>
internal static string NullStringLocalizerFactory
{
get { return GetString("NullStringLocalizerFactory"); }
}
/// <summary>
/// IStringLocalizerFactory is null. Must call other constructor overload to use this property.
/// </summary>
internal static string FormatNullStringLocalizerFactory()
{
return GetString("NullStringLocalizerFactory");
}
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

View File

@ -0,0 +1,76 @@
// 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.Collections.Generic;
using System.Globalization;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.Internal;
using Microsoft.Framework.Localization;
using Microsoft.Framework.Runtime;
namespace Microsoft.AspNet.Mvc.Localization
{
/// <summary>
/// A <see cref="HtmlLocalizer"/> that provides localized strings for views.
/// </summary>
public class ViewLocalizer : IViewLocalizer, ICanHasViewContext
{
private readonly IHtmlLocalizerFactory _localizerFactory;
private readonly string _applicationName;
private IHtmlLocalizer _localizer;
/// <summary>
/// Creates a new <see cref="ViewLocalizer"/>.
/// </summary>
/// <param name="localizerFactory">The <see cref="IHtmlLocalizerFactory"/>.</param>
/// <param name="applicationEnvironment">The <see cref="IApplicationEnvironment"/>.</param>
public ViewLocalizer(
[NotNull] IHtmlLocalizerFactory localizerFactory,
[NotNull] IApplicationEnvironment applicationEnvironment)
{
_applicationName = applicationEnvironment.ApplicationName;
_localizerFactory = localizerFactory;
}
/// <inheritdoc />
public LocalizedString this[[NotNull] string name] => _localizer[name];
/// <inheritdoc />
public LocalizedString this[[NotNull] string name, params object[] arguments] => _localizer[name, arguments];
/// <inheritdoc />
public LocalizedString GetString([NotNull] string name) => _localizer.GetString(name);
/// <inheritdoc />
public LocalizedString GetString([NotNull] string name, params object[] values) =>
_localizer.GetString(name, values);
/// <inheritdoc />
public LocalizedHtmlString Html([NotNull] string key) => _localizer.Html(key);
/// <inheritdoc />
public LocalizedHtmlString Html([NotNull] string key, params object[] arguments) =>
_localizer.Html(key, arguments);
/// <inheritdoc />
public IStringLocalizer WithCulture([NotNull] CultureInfo culture) => _localizer.WithCulture(culture);
/// <inheritdoc />
IHtmlLocalizer IHtmlLocalizer.WithCulture([NotNull] CultureInfo culture) => _localizer.WithCulture(culture);
public void Contextualize(ViewContext viewContext)
{
var baseName = viewContext.View.Path.Replace('/', '.').Replace('\\', '.');
if (baseName.StartsWith("."))
{
baseName = baseName.Substring(1);
}
baseName = _applicationName + "." + baseName;
_localizer = _localizerFactory.Create(baseName, _applicationName);
}
/// <inheritdoc />
public IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures) =>
_localizer.GetAllStrings(includeAncestorCultures);
}
}

View File

@ -0,0 +1,31 @@
{
"description": "Features that enable globalization & localization of MVC applications.",
"version": "6.0.0-*",
"compilationOptions": {
"warningsAsErrors": false
},
"dependencies": {
"Microsoft.AspNet.Localization": "1.0.0-*",
"Microsoft.AspNet.Mvc.Razor": "6.0.0-*",
"Microsoft.Framework.DependencyInjection": "1.0.0-*",
"Microsoft.Framework.Localization": "1.0.0-*",
"Microsoft.Framework.NotNullAttribute.Sources": { "version": "1.0.0-*", "type": "build" },
"Microsoft.Framework.PropertyHelper.Sources": { "version": "1.0.0-*", "type": "build" }
},
"frameworks": {
"dnx451": {},
"dnxcore50": {}
},
"exclude": [
"wwwroot",
"node_modules",
"bower_components"
],
"packExclude": [
"node_modules",
"bower_components",
"**.kproj",
"**.user",
"**.vspscc"
]
}

View File

@ -100,33 +100,5 @@ namespace Microsoft.Framework.DependencyInjection
return WithControllersAsServices(services, controllerTypes.Select(type => type.AsType()));
}
/// <summary>
/// Adds Mvc localization to the application.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddMvcLocalization([NotNull] this IServiceCollection services)
{
return AddMvcLocalization(services, LanguageViewLocationExpanderFormat.Suffix);
}
/// <summary>
/// Adds Mvc localization to the application.
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
/// <param name="format">The view format for localized views.</param>
/// <returns>The <see cref="IServiceCollection"/>.</returns>
public static IServiceCollection AddMvcLocalization(
[NotNull] this IServiceCollection services,
LanguageViewLocationExpanderFormat format)
{
services.ConfigureRazorViewEngine(options =>
{
options.ViewLocationExpanders.Add(new LanguageViewLocationExpander(format));
});
return services;
}
}
}

View File

@ -13,6 +13,7 @@
"Microsoft.AspNet.Mvc.Cors": "6.0.0-*",
"Microsoft.AspNet.Mvc.DataAnnotations": "6.0.0-*",
"Microsoft.AspNet.Mvc.Formatters.Json": "6.0.0-*",
"Microsoft.AspNet.Mvc.Localization": "6.0.0-*",
"Microsoft.AspNet.Mvc.Razor": "6.0.0-*",
"Microsoft.AspNet.Mvc.ViewFeatures": "6.0.0-*",
"Microsoft.Framework.Caching.Memory": "1.0.0-*",

View File

@ -3,8 +3,11 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Resources;
using System.Threading.Tasks;
using System.Xml.Linq;
using LocalizationWebSite;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Testing;
@ -75,5 +78,102 @@ mypartial
// Assert
Assert.Equal(expected, body.Trim(), ignoreLineEndingDifferences: true);
}
public static IEnumerable<object[]> LocalizationResourceData
{
get
{
// Dnx does not support reading resources yet. Coreclr return null value while trying to read resources.
// https://github.com/aspnet/Mvc/issues/2747
#if DNX451
var expected1 =
@"Hello there!!
Learn More
Hi John ! You are in 2015 year and today is Thursday";
yield return new[] {"en-GB", expected1 };
var expected2 =
@"Bonjour!
apprendre Encore Plus
Salut John ! Vous êtes en 2015 an aujourd'hui est Thursday";
yield return new[] { "fr", expected2 };
#else
var expectedCoreClr =
@"Hello there!!
Learn More
Hi";
yield return new[] {"en-GB", expectedCoreClr };
yield return new[] {"fr", expectedCoreClr };
#endif
}
}
[Theory]
[MemberData(nameof(LocalizationResourceData))]
public async Task Localization_Resources_ReturnExpectedValues(string value, string expected)
{
// Arrange
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
var client = server.CreateClient();
var cultureCookie = "c=" + value + "|uic=" + value;
client.DefaultRequestHeaders.Add(
"Cookie",
new CookieHeaderValue("ASPNET_CULTURE", cultureCookie).ToString());
if (!value.StartsWith("en"))
{
// Manually generating .resources file since we don't autogenerate .resources file yet.
WriteResourceFile("HomeController." + value + ".resx");
WriteResourceFile("Views.Shared._LocalizationLayout.cshtml." + value + ".resx");
}
WriteResourceFile("Views.Home.Locpage.cshtml." + value + ".resx");
// Act
var body = await client.GetStringAsync("http://localhost/Home/Locpage");
// Assert
Assert.Equal(expected, body.Trim());
}
private void WriteResourceFile(string resxFileName)
{
var resxFilePath = Path.Combine("..", "WebSites", SiteName, "Resources");
var resxFullFileName = Path.Combine(resxFilePath, resxFileName);
if (File.Exists(resxFullFileName))
{
using (var fs = File.OpenRead(resxFullFileName))
{
var document = XDocument.Load(fs);
var binDirPath = Path.Combine(resxFilePath, "bin");
if (!Directory.Exists(binDirPath))
{
Directory.CreateDirectory(binDirPath);
}
// Put in "bin" sub-folder of resx file
var targetPath = Path.Combine(
binDirPath,
Path.ChangeExtension(resxFileName, ".resources"));
using (var targetStream = File.Create(targetPath))
{
var rw = new ResourceWriter(targetStream);
foreach (var e in document.Root.Elements("data"))
{
var name = e.Attribute("name").Value;
var value = e.Element("value").Value;
rw.AddResource(name, value);
}
rw.Generate();
}
}
}
}
}
}

View File

@ -0,0 +1,63 @@
// 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.Globalization;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.Localization;
using Microsoft.Framework.Runtime;
using Microsoft.Framework.WebEncoders.Testing;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Localization.Test
{
public class HtmlLocalizerOfTTest
{
[Fact]
public void HtmlLocalizerOfTTest_UseIndexer_ReturnsLocalizedString()
{
// Arrange
var localizedString = new LocalizedString("Hello", "Bonjour");
var htmlLocalizer = new Mock<IHtmlLocalizer>();
htmlLocalizer.Setup(h => h["Hello"]).Returns(localizedString);
var htmlLocalizerFactory = new Mock<IHtmlLocalizerFactory>();
htmlLocalizerFactory.Setup(h => h.Create(typeof(TestClass)))
.Returns(htmlLocalizer.Object);
var htmlLocalizerOfT = new HtmlLocalizer<TestClass>(htmlLocalizerFactory.Object);
// Act
var actualLocalizedString = htmlLocalizerOfT["Hello"];
// Assert
Assert.Equal(localizedString, actualLocalizedString);
}
[Fact]
public void HtmlLocalizerOfTTest_UseIndexerWithArguments_ReturnsLocalizedString()
{
// Arrange
var applicationEnvironment = new Mock<IApplicationEnvironment>();
applicationEnvironment.Setup(a => a.ApplicationName).Returns("TestApplication");
var localizedString = new LocalizedString("Hello", "Bonjour test");
var htmlLocalizer = new Mock<IHtmlLocalizer>();
htmlLocalizer.Setup(h => h["Hello", "test"]).Returns(localizedString);
var htmlLocalizerFactory = new Mock<IHtmlLocalizerFactory>();
htmlLocalizerFactory.Setup(h => h.Create(typeof(TestClass)))
.Returns(htmlLocalizer.Object);
var htmlLocalizerOfT = new HtmlLocalizer<TestClass>(htmlLocalizerFactory.Object);
// Act
var actualLocalizedString = htmlLocalizerOfT["Hello", "test"];
// Assert
Assert.Equal(localizedString, actualLocalizedString);
}
}
}

View File

@ -0,0 +1,141 @@
// 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;
using Microsoft.AspNet.Testing;
using Microsoft.Framework.Localization;
using Microsoft.Framework.WebEncoders.Testing;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Localization.Test
{
public class HtmlLocalizerTest
{
[Fact]
public void HtmlLocalizer_UseIndexer_ReturnsLocalizedString()
{
// Arrange
var localizedString = new LocalizedString("Hello", "Bonjour");
var stringLocalizer = new Mock<IStringLocalizer>();
stringLocalizer.Setup(s => s["Hello"]).Returns(localizedString);
var htmlLocalizer = new HtmlLocalizer(stringLocalizer.Object, new CommonTestEncoder());
// Act
var actualLocalizedString = htmlLocalizer["Hello"];
// Assert
Assert.Equal(localizedString, actualLocalizedString);
}
[Fact]
public void HtmlLocalizer_UseIndexerWithArguments_ReturnsLocalizedString()
{
// Arrange
var localizedString = new LocalizedString("Hello", "Bonjour test");
var stringLocalizer = new Mock<IStringLocalizer>();
stringLocalizer.Setup(s => s["Hello", "test"]).Returns(localizedString);
var htmlLocalizer = new HtmlLocalizer(stringLocalizer.Object, new CommonTestEncoder());
// Act
var actualLocalizedString = htmlLocalizer["Hello", "test"];
// Assert
Assert.Equal(localizedString, actualLocalizedString);
}
public static IEnumerable<object[]> HtmlData
{
get
{
yield return new object[] { "Bonjour {0} {{{{ }}", new object[] { "test" }, "Bonjour HtmlEncode[[test]] {{ }" };
yield return new object[] { "Bonjour {{0}}", new object[] { "{0}" }, "Bonjour {0}" };
yield return new object[] { "Bonjour {0:x}", new object[] { 10 }, "Bonjour HtmlEncode[[a]]" };
yield return new object[] { "Bonjour {0:x}}}", new object[] { 10 }, "Bonjour HtmlEncode[[x}]]" };
yield return new object[] { "Bonjour {{0:x}}", new object[] { 10 }, "Bonjour {0:x}" };
yield return new object[] { "{{ Bonjour {{{0:x}}}", new object[] { 10 }, "{ Bonjour {HtmlEncode[[x}]]" };
yield return new object[] { "}} Bonjour {{{0:x}}}", new object[] { 10 }, "} Bonjour {HtmlEncode[[x}]]" };
yield return new object[] { "}} Bonjour", new object[] { }, "} Bonjour" };
yield return new object[] { "{{ {0} }}", new object[] { 10 }, "{ HtmlEncode[[10]] }" };
yield return new object[] {
"Bonjour {{{0:x}}} {1:yyyy}",
new object[] { 10, new DateTime(2015, 10, 10) },
"Bonjour {HtmlEncode[[x}]] HtmlEncode[[2015]]"
};
yield return new object[] {
"Bonjour {{{0:x}}} Bienvenue {{1:yyyy}}",
new object[] { 10, new DateTime(2015, 10, 10) },
"Bonjour {HtmlEncode[[x}]] Bienvenue {1:yyyy}"
};
yield return new object[] {
"Bonjour {0,6} Bienvenue {{1:yyyy}}",
new object[] { 10, new DateTime(2015, 10, 10) },
"Bonjour HtmlEncode[[ 10]] Bienvenue {1:yyyy}"
};
if (!TestPlatformHelper.IsMono)
{
// Mono doesn't deal well with custom format strings, even valid ones
yield return new object[] { "{0:{{000}}}", new object[] { 10 }, "HtmlEncode[[{010}]]" };
yield return new object[] {
"Bonjour {0:'{{characters that should be escaped}}b'###'b'}",
new object[] { 10 },
"Bonjour HtmlEncode[[{characters that should be escaped}b10b]]"
};
}
}
}
[Theory]
[MemberData(nameof(HtmlData))]
public void HtmlLocalizer_HtmlWithArguments_ReturnsLocalizedHtml(
string format,
object[] arguments,
string expectedText)
{
// Arrange
var localizedString = new LocalizedString("Hello", format);
var stringLocalizer = new Mock<IStringLocalizer>();
stringLocalizer.Setup(s => s["Hello"]).Returns(localizedString);
var htmlLocalizer = new HtmlLocalizer(stringLocalizer.Object, new CommonTestEncoder());
// Act
var localizedHtmlString = htmlLocalizer.Html("Hello", arguments);
// Assert
Assert.NotNull(localizedHtmlString);
Assert.Equal(expectedText, localizedHtmlString.Value);
}
[Theory]
[InlineData("{")]
[InlineData("{0")]
public void HtmlLocalizer_HtmlWithInvalidResourcestring_ThrowsException(string format)
{
// Arrange
var localizedString = new LocalizedString("Hello", format);
var stringLocalizer = new Mock<IStringLocalizer>();
stringLocalizer.Setup(s => s["Hello"]).Returns(localizedString);
var htmlLocalizer = new HtmlLocalizer(stringLocalizer.Object, new CommonTestEncoder());
// Act
var exception = Assert.Throws<FormatException>(() => htmlLocalizer.Html("Hello", new object[] { }));
// Assert
Assert.NotNull(exception);
Assert.Equal("Input string was not in a correct format.", exception.Message);
}
}
public class TestClass
{
}
}

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>8fc726b5-e766-44e0-8b38-1313b6d8d9a7</ProjectGuid>
<RootNamespace>Microsoft.AspNet.Mvc.Localization.Test</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -0,0 +1,274 @@
// 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;
using System.Globalization;
using System.Linq;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Localization;
using Microsoft.Framework.OptionsModel;
using Microsoft.Framework.WebEncoders;
using Microsoft.Framework.WebEncoders.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.Localization.Test
{
public class MvcLocalizationServiceCollectionExtensionsTest
{
[Fact]
public void AddMvcLocalization_AddsNeededServices()
{
// Arrange
var collection = new ServiceCollection();
// Act
MvcLocalizationServiceCollectionExtensions.AddMvcLocalization(collection);
// Assert
var services = collection.ToList();
Assert.Equal(7, services.Count);
Assert.Equal(typeof(IConfigureOptions<RazorViewEngineOptions>), services[0].ServiceType);
Assert.Equal(ServiceLifetime.Singleton, services[0].Lifetime);
Assert.Equal(typeof(IHtmlLocalizerFactory), services[1].ServiceType);
Assert.Equal(typeof(HtmlLocalizerFactory), services[1].ImplementationType);
Assert.Equal(ServiceLifetime.Singleton, services[1].Lifetime);
Assert.Equal(typeof(IHtmlLocalizer<>), services[2].ServiceType);
Assert.Equal(typeof(HtmlLocalizer<>), services[2].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[2].Lifetime);
Assert.Equal(typeof(IViewLocalizer), services[3].ServiceType);
Assert.Equal(typeof(ViewLocalizer), services[3].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[3].Lifetime);
Assert.Equal(typeof(IHtmlEncoder), services[4].ServiceType);
Assert.Equal(ServiceLifetime.Singleton, services[4].Lifetime);
Assert.Equal(typeof(IStringLocalizerFactory), services[5].ServiceType);
Assert.Equal(typeof(ResourceManagerStringLocalizerFactory), services[5].ImplementationType);
Assert.Equal(ServiceLifetime.Singleton, services[5].Lifetime);
Assert.Equal(typeof(IStringLocalizer<>), services[6].ServiceType);
Assert.Equal(typeof(StringLocalizer<>), services[6].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[6].Lifetime);
}
[Fact]
public void AddCustomLocalizers_BeforeMvcLocalization_AddsNeededServices()
{
// Arrange
var collection = new ServiceCollection();
// Act
collection.Add(ServiceDescriptor.Singleton(typeof(IHtmlLocalizerFactory), typeof(TestHtmlLocalizerFactory)));
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(TestHtmlLocalizer<>)));
collection.Add(ServiceDescriptor.Transient(typeof(IViewLocalizer), typeof(TestViewLocalizer)));
collection.Add(ServiceDescriptor.Instance(typeof(IHtmlEncoder), typeof(CommonTestEncoder)));
MvcLocalizationServiceCollectionExtensions.AddMvcLocalization(collection);
// Assert
var services = collection.ToList();
Assert.Equal(7, services.Count);
Assert.Equal(typeof(IHtmlLocalizerFactory), services[0].ServiceType);
Assert.Equal(typeof(TestHtmlLocalizerFactory), services[0].ImplementationType);
Assert.Equal(ServiceLifetime.Singleton, services[0].Lifetime);
Assert.Equal(typeof(IHtmlLocalizer<>), services[1].ServiceType);
Assert.Equal(typeof(TestHtmlLocalizer<>), services[1].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[1].Lifetime);
Assert.Equal(typeof(IViewLocalizer), services[2].ServiceType);
Assert.Equal(typeof(TestViewLocalizer), services[2].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[2].Lifetime);
Assert.Equal(typeof(IHtmlEncoder), services[3].ServiceType);
Assert.Equal(typeof(CommonTestEncoder), services[3].ImplementationInstance);
Assert.Equal(ServiceLifetime.Singleton, services[3].Lifetime);
}
[Fact]
public void AddCustomLocalizers_AfterMvcLocalization_AddsNeededServices()
{
// Arrange
var collection = new ServiceCollection();
collection.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new CustomPartialDirectoryViewLocationExpander());
});
// Act
MvcLocalizationServiceCollectionExtensions.AddMvcLocalization(collection);
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(TestHtmlLocalizer<>)));
collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer), typeof(TestViewLocalizer)));
collection.Add(ServiceDescriptor.Instance(typeof(IHtmlEncoder), typeof(CommonTestEncoder)));
// Assert
var services = collection.ToList();
Assert.Equal(11, services.Count);
Assert.Equal(typeof(IConfigureOptions<RazorViewEngineOptions>), services[0].ServiceType);
Assert.Equal(ServiceLifetime.Singleton, services[0].Lifetime);
Assert.Equal(0, ((IConfigureOptions<RazorViewEngineOptions>)services[0].ImplementationInstance).Order);
Assert.Equal(typeof(IConfigureOptions<RazorViewEngineOptions>), services[1].ServiceType);
Assert.Equal(ServiceLifetime.Singleton, services[1].Lifetime);
Assert.Equal(-1000, ((IConfigureOptions<RazorViewEngineOptions>)services[1].ImplementationInstance).Order);
Assert.Equal(typeof(IHtmlLocalizerFactory), services[2].ServiceType);
Assert.Equal(typeof(HtmlLocalizerFactory), services[2].ImplementationType);
Assert.Equal(ServiceLifetime.Singleton, services[2].Lifetime);
Assert.Equal(typeof(IHtmlLocalizer<>), services[3].ServiceType);
Assert.Equal(typeof(HtmlLocalizer<>), services[3].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[3].Lifetime);
Assert.Equal(typeof(IViewLocalizer), services[4].ServiceType);
Assert.Equal(typeof(ViewLocalizer), services[4].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[4].Lifetime);
Assert.Equal(typeof(IHtmlEncoder), services[5].ServiceType);
Assert.Equal(ServiceLifetime.Singleton, services[5].Lifetime);
Assert.Equal(typeof(IStringLocalizerFactory), services[6].ServiceType);
Assert.Equal(typeof(ResourceManagerStringLocalizerFactory), services[6].ImplementationType);
Assert.Equal(ServiceLifetime.Singleton, services[6].Lifetime);
Assert.Equal(typeof(IStringLocalizer<>), services[7].ServiceType);
Assert.Equal(typeof(StringLocalizer<>), services[7].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[7].Lifetime);
Assert.Equal(typeof(IHtmlLocalizer<>), services[8].ServiceType);
Assert.Equal(typeof(TestHtmlLocalizer<>), services[8].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[8].Lifetime);
Assert.Equal(typeof(IHtmlLocalizer), services[9].ServiceType);
Assert.Equal(typeof(TestViewLocalizer), services[9].ImplementationType);
Assert.Equal(ServiceLifetime.Transient, services[9].Lifetime);
Assert.Equal(typeof(IHtmlEncoder), services[10].ServiceType);
Assert.Equal(typeof(CommonTestEncoder), services[10].ImplementationInstance);
Assert.Equal(ServiceLifetime.Singleton, services[10].Lifetime);
}
}
public class TestViewLocalizer : IViewLocalizer
{
public LocalizedString this[string name]
{
get
{
throw new NotImplementedException();
}
}
public LocalizedString this[string name, params object[] arguments]
{
get
{
throw new NotImplementedException();
}
}
public IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures)
{
throw new NotImplementedException();
}
public LocalizedHtmlString Html(string key)
{
throw new NotImplementedException();
}
public LocalizedHtmlString Html(string key, params object[] arguments)
{
throw new NotImplementedException();
}
public IHtmlLocalizer WithCulture(CultureInfo culture)
{
throw new NotImplementedException();
}
IStringLocalizer IStringLocalizer.WithCulture(CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class TestHtmlLocalizer<HomeController> : IHtmlLocalizer<HomeController>
{
public LocalizedString this[string name]
{
get
{
throw new NotImplementedException();
}
}
public LocalizedString this[string name, params object[] arguments]
{
get
{
throw new NotImplementedException();
}
}
public IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures)
{
throw new NotImplementedException();
}
public LocalizedHtmlString Html(string key)
{
throw new NotImplementedException();
}
public LocalizedHtmlString Html(string key, params object[] arguments)
{
throw new NotImplementedException();
}
public IHtmlLocalizer WithCulture(CultureInfo culture)
{
throw new NotImplementedException();
}
IStringLocalizer IStringLocalizer.WithCulture(CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class TestHtmlLocalizerFactory : IHtmlLocalizerFactory
{
public IHtmlLocalizer Create(Type resourceSource)
{
throw new NotImplementedException();
}
public IHtmlLocalizer Create(string baseName, string location)
{
throw new NotImplementedException();
}
}
public class CustomPartialDirectoryViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
throw new NotImplementedException();
}
public void PopulateValues(ViewLocationExpanderContext context)
{
}
}
}

View File

@ -0,0 +1,80 @@
// 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.Globalization;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Framework.Localization;
using Microsoft.Framework.Runtime;
using Microsoft.Framework.WebEncoders.Testing;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Mvc.Localization.Test
{
public class ViewLocalizerTest
{
[Fact]
public void ViewLocalizer_UseIndexer_ReturnsLocalizedString()
{
// Arrange
var applicationEnvironment = new Mock<IApplicationEnvironment>();
applicationEnvironment.Setup(a => a.ApplicationName).Returns("TestApplication");
var localizedString = new LocalizedString("Hello", "Bonjour");
var htmlLocalizer = new Mock<IHtmlLocalizer>();
htmlLocalizer.Setup(h => h["Hello"]).Returns(localizedString);
var htmlLocalizerFactory = new Mock<IHtmlLocalizerFactory>();
htmlLocalizerFactory.Setup(h => h.Create("TestApplication.example", "TestApplication"))
.Returns(htmlLocalizer.Object);
var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object);
var view = new Mock<IView>();
view.Setup(v => v.Path).Returns("example");
var viewContext = new ViewContext();
viewContext.View = view.Object;
viewLocalizer.Contextualize(viewContext);
// Act
var actualLocalizedString = viewLocalizer["Hello"];
// Assert
Assert.Equal(localizedString, actualLocalizedString);
}
[Fact]
public void ViewLocalizer_UseIndexerWithArguments_ReturnsLocalizedString()
{
// Arrange
var applicationEnvironment = new Mock<IApplicationEnvironment>();
applicationEnvironment.Setup(a => a.ApplicationName).Returns("TestApplication");
var localizedString = new LocalizedString("Hello", "Bonjour test");
var htmlLocalizer = new Mock<IHtmlLocalizer>();
htmlLocalizer.Setup(h => h["Hello", "test"]).Returns(localizedString);
var htmlLocalizerFactory = new Mock<IHtmlLocalizerFactory>();
htmlLocalizerFactory.Setup(
h => h.Create("TestApplication.example", "TestApplication")).Returns(htmlLocalizer.Object);
var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object);
var view = new Mock<IView>();
view.Setup(v => v.Path).Returns("example");
var viewContext = new ViewContext();
viewContext.View = view.Object;
viewLocalizer.Contextualize(viewContext);
// Act
var actualLocalizedString = viewLocalizer["Hello", "test"];
// Assert
Assert.Equal(localizedString, actualLocalizedString);
}
}
}

View File

@ -0,0 +1,24 @@
{
"compilationOptions": {
"warningsAsErrors": "true"
},
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.Localization": "6.0.0-*",
"Microsoft.AspNet.Mvc.TestCommon": { "version": "6.0.0-*", "type": "build" },
"Microsoft.AspNet.Testing": "1.0.0-*",
"Microsoft.AspNet.Mvc.Formatters.Xml": "6.0.0-*",
"Microsoft.Framework.WebEncoders.Testing": "1.0.0-*",
"xunit.runner.aspnet": "2.0.0-aspnet-*"
},
"commands": {
"test": "xunit.runner.aspnet"
},
"frameworks": {
"dnx451": {
"dependencies": {
"Moq": "4.2.1312.1622"
}
}
}
}

View File

@ -2,15 +2,28 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Localization;
namespace LocalizationWebSite.Controllers
{
public class HomeController : Controller
{
// GET: /<controller>/
private readonly IHtmlLocalizer _localizer;
public HomeController(IHtmlLocalizer<HomeController> localizer)
{
_localizer = localizer;
}
public IActionResult Index()
{
return View();
}
public IActionResult Locpage()
{
ViewData["Message"] = _localizer["Learn More"];
return View();
}
}
}

View File

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Hello there!!" xml:space="preserve">
<value>Bonjour!</value>
</data>
<data name="Learn how to build ASP.NET apps that can run anywhere." xml:space="preserve">
<value>Apprenez à créer des applications ASP.NET qui peuvent fonctionner ne importe où.</value>
</data>
<data name="Learn More" xml:space="preserve">
<value>apprendre Encore Plus</value>
</data>
</root>

View File

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Hello there!!" xml:space="preserve">
<value>Hello there!!</value>
</data>
<data name="Learn how to build ASP.NET apps that can run anywhere." xml:space="preserve">
<value>Learn how to build ASP.NET apps that can run anywhere.</value>
</data>
<data name="Learn More" xml:space="preserve">
<value>Learn More</value>
</data>
<data name="Hi" xml:space="preserve">
<value>Hi {0,-10}! You are in {1:yyyy} year and today is {2}</value>
</data>
</root>

View File

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Hello there!!" xml:space="preserve">
<value>Bonjour!</value>
</data>
<data name="Learn how to build ASP.NET apps that can run anywhere." xml:space="preserve">
<value>Apprenez à créer des applications ASP.NET qui peuvent fonctionner ne importe où.</value>
</data>
<data name="Learn More" xml:space="preserve">
<value>apprendre Encore Plus</value>
</data>
<data name="Hi" xml:space="preserve">
<value>Salut {0,-10}! Vous êtes en {1:yyyy} an aujourd'hui est {2}</value>
</data>
</root>

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="About" xml:space="preserve">
<value>sur</value>
</data>
<data name="Application name" xml:space="preserve">
<value>Nom de l'application</value>
</data>
<data name="Contact" xml:space="preserve">
<value>communiquer</value>
</data>
<data name="Home" xml:space="preserve">
<value>maison</value>
</data>
<data name="My ASP.NET Application" xml:space="preserve">
<value>Mon application ASP.NET</value>
</data>
<data name="Resources for this view" xml:space="preserve">
<value>Ressources pour ce point de vue</value>
</data>
<data name="Today is: {0}" xml:space="preserve">
<value>Aujourd'hui, ce est: {0}</value>
</data>
</root>

View File

@ -3,6 +3,7 @@
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Framework.Localization;
namespace LocalizationWebSite
{
@ -14,6 +15,10 @@ namespace LocalizationWebSite
// Add MVC services to the services container
services.AddMvc();
services.AddMvcLocalization();
// Adding TestStringLocalizerFactory since ResourceStringLocalizerFactory uses ResourceManager. DNX does
// not support getting non-enu resources from ResourceManager yet.
services.AddSingleton<IStringLocalizerFactory, TestStringLocalizerFactory>();
}
public void Configure(IApplicationBuilder app)

View File

@ -0,0 +1,96 @@
// 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;
using System.Globalization;
using System.IO;
using System.Resources;
using Microsoft.Framework.Localization;
using Microsoft.Framework.Localization.Internal;
namespace LocalizationWebSite
{
public class TestStringLocalizer : IStringLocalizer
{
private readonly IResourceNamesCache _resourceNamesCache;
private ResourceManager _resourceManager;
private readonly AssemblyWrapper _resourceAssemblyWrapper;
private readonly string _resourceBaseName;
private string _applicationBasePath;
public TestStringLocalizer(ResourceManager resourceManager,
AssemblyWrapper resourceAssembly,
string baseName,
IResourceNamesCache resourceNamesCache,
string applicationBasePath)
{
_resourceAssemblyWrapper = resourceAssembly;
_resourceManager = resourceManager;
_resourceBaseName = baseName;
_resourceNamesCache = resourceNamesCache;
_applicationBasePath = applicationBasePath;
}
public virtual LocalizedString this[string name]
{
get
{
var value = GetStringSafely(name, null);
return new LocalizedString(name, value ?? name, resourceNotFound: value == null);
}
}
public virtual LocalizedString this[string name, params object[] arguments]
{
get
{
var format = GetStringSafely(name, null);
var value = string.Format(format ?? name, arguments);
return new LocalizedString(name, value, resourceNotFound: format == null);
}
}
public IStringLocalizer WithCulture(CultureInfo culture)
{
return new TestStringLocalizer(_resourceManager,
_resourceAssemblyWrapper,
_resourceBaseName,
_resourceNamesCache,
_applicationBasePath);
}
public virtual IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures) =>
GetAllStrings(includeAncestorCultures, CultureInfo.CurrentUICulture);
protected IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures, CultureInfo culture)
{
throw new NotImplementedException();
}
protected string GetStringSafely(string name, CultureInfo culture)
{
var resourceValue = string.Empty;
#if DNX451
var cultureName = (culture ?? CultureInfo.CurrentUICulture).Name;
var resourceFile = _resourceManager.BaseName.Substring(_resourceManager.BaseName.IndexOf('.') + 1) + "." + cultureName;
var filePath = Path.Combine(_applicationBasePath, "Resources", "bin");
if (File.Exists(Path.Combine(filePath, resourceFile + ".resources")))
{
_resourceManager = ResourceManager.CreateFileBasedResourceManager(resourceFile, filePath, null);
}
#endif
try
{
// retrieve the value of the specified key
resourceValue = _resourceManager.GetString(name);
}
catch (MissingManifestResourceException)
{
return name;
}
return resourceValue;
}
}
}

View File

@ -0,0 +1,52 @@
// 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.Reflection;
using System.Resources;
using Microsoft.Framework.Localization;
using Microsoft.Framework.Localization.Internal;
using Microsoft.Framework.Runtime;
namespace LocalizationWebSite
{
public class TestStringLocalizerFactory : IStringLocalizerFactory
{
private readonly IApplicationEnvironment _applicationEnvironment;
private readonly IResourceNamesCache _resourceNamesCache = new ResourceNamesCache();
public TestStringLocalizerFactory(IApplicationEnvironment applicationEnvironment)
{
_applicationEnvironment = applicationEnvironment;
}
public IStringLocalizer Create(Type resourceSource)
{
var typeInfo = resourceSource.GetTypeInfo();
var assembly = typeInfo.Assembly;
var baseName = typeInfo.FullName;
return new TestStringLocalizer(
new ResourceManager(resourceSource),
new AssemblyWrapper(assembly),
baseName,
_resourceNamesCache,
_applicationEnvironment.ApplicationBasePath);
}
public IStringLocalizer Create(string baseName, string location)
{
if (string.IsNullOrEmpty(location))
{
location = _applicationEnvironment.ApplicationName;
}
var assembly = Assembly.Load(new AssemblyName(location));
return new TestStringLocalizer(
new ResourceManager(baseName, assembly),
new AssemblyWrapper(assembly),
baseName,
_resourceNamesCache,
_applicationEnvironment.ApplicationBasePath);
}
}
}

View File

@ -0,0 +1,7 @@
@{
Layout = "/Views/Shared/_LocalizationLayout.cshtml";
var date = new DateTime(2015,6,25);
}
@LocString["Hello there!!"]
@ViewBag.Message
@LocString.Html("Hi", "John", @date , @date.DayOfWeek)

View File

@ -0,0 +1 @@
@RenderBody()

View File

@ -0,0 +1,5 @@
@using LocalizationWebSite
@using Microsoft.Framework.Localization
@using Microsoft.AspNet.Mvc.Localization
@inject IViewLocalizer LocString

View File

@ -1,17 +1,15 @@
{
"commands": {
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
"kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5000"
},
"dependencies": {
"Kestrel": "1.0.0-*",
"Microsoft.AspNet.Localization": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
},
"commands": {
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
"kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5000"
},
"dependencies": {
"Kestrel": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
"Microsoft.AspNet.Server.WebListener": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }

View File

@ -3,7 +3,6 @@
using System.Globalization;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Localization;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.Framework.DependencyInjection;

View File

@ -7,6 +7,7 @@
"Kestrel": "1.0.0-*",
"Microsoft.AspNet.Localization": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.Localization": "6.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",