// 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.IO; using System.Text; using System.Text.Encodings.Web; using Microsoft.AspNet.Html; namespace Microsoft.AspNet.Mvc.Localization { /// /// An with localized content. /// public class LocalizedHtmlString : IHtmlContent { #if DOTNET5_5 private static readonly object[] EmptyArguments = Array.Empty(); #else private static readonly object[] EmptyArguments = new object[0]; #endif private readonly object[] _arguments; /// /// Creates an instance of . /// /// The name of the string resource. /// The string resource. public LocalizedHtmlString(string name, string value) : this(name, value, isResourceNotFound: false, arguments: EmptyArguments) { } /// /// Creates an instance of . /// /// The name of the string resource. /// The string resource. /// A flag that indicates if the resource is not found. public LocalizedHtmlString(string name, string value, bool isResourceNotFound) : this(name, value, isResourceNotFound, arguments: EmptyArguments) { } /// /// Creates an instance of . /// /// The name of the string resource. /// The string resource. /// A flag that indicates if the resource is not found. /// The values to format the with. public LocalizedHtmlString(string name, string value, bool isResourceNotFound, params object[] arguments) { if (name == null) { throw new ArgumentNullException(nameof(name)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } if (arguments == null) { throw new ArgumentNullException(nameof(arguments)); } Name = name; Value = value; IsResourceNotFound = isResourceNotFound; _arguments = arguments; } /// /// The name of the string resource. /// public string Name { get; } /// /// The string resource. /// public string Value { get; } /// /// Gets a flag that indicates if the resource is not found. /// public bool IsResourceNotFound { get; } /// public void WriteTo(TextWriter writer, HtmlEncoder encoder) { if (writer == null) { throw new ArgumentNullException(nameof(writer)); } if (encoder == null) { throw new ArgumentNullException(nameof(encoder)); } var htmlTextWriter = writer as HtmlTextWriter; if (htmlTextWriter == null) { FormatValue(writer, encoder, Value, _arguments); } else { htmlTextWriter.Write(this); } } private static void FormatValue( TextWriter writer, HtmlEncoder encoder, string resourceString, object[] arguments) { var position = 0; var length = resourceString.Length; StringBuilder tokenBuffer = null; var isToken = false; while (position < length) { var currentCharacter = resourceString[position]; position++; if (currentCharacter == '}') { if (position < length && resourceString[position] == '}') { // Escaped curly brace: "}}". AppendCurlyBrace(isToken, currentCharacter, tokenBuffer, writer); position++; } else { // End of a token. Append(isToken, '}', tokenBuffer, writer); if (position == length) { break; } AppendToOutput(tokenBuffer, arguments, writer, encoder); isToken = false; tokenBuffer = null; } } else if (currentCharacter == '{') { if (position < length && resourceString[position] == '{') { // Escaped curly brace: "{{". AppendCurlyBrace(isToken, currentCharacter, tokenBuffer, writer); position++; } else { // Start of a new token. tokenBuffer = new StringBuilder(); tokenBuffer.Append('{'); isToken = true; } } else { Append(isToken, currentCharacter, tokenBuffer, writer); } } AppendToOutput(tokenBuffer, arguments, writer, encoder); } private static void Append( bool isToken, char value, StringBuilder tokenBuffer, TextWriter writer) { if (isToken) { tokenBuffer.Append(value); } else { writer.Write(value); } } private static void AppendCurlyBrace( bool isToken, char curlyBrace, StringBuilder tokenBuffer, TextWriter writer) { if (isToken) { tokenBuffer .Append(curlyBrace) .Append(curlyBrace); } else { writer.Write(curlyBrace); } } private static void AppendToOutput( StringBuilder tokenBuffer, object[] arguments, TextWriter writer, HtmlEncoder encoder) { if (tokenBuffer != null && tokenBuffer.Length > 0) { encoder.Encode(writer, string.Format(tokenBuffer.ToString(), arguments)); } } } }