From 5790142f81f2a94ad073834b1534acbf9b02ea3c Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Fri, 25 Oct 2019 18:36:02 +0800 Subject: Add NeutralResourcesLanguage. Conform to best practices. --- Timeline.Tests/Controllers/TokenControllerTest.cs | 4 +- Timeline.Tests/Controllers/UserControllerTest.cs | 4 +- Timeline.Tests/Helpers/UseCultureAttribute.cs | 91 ++++++++++++ Timeline.Tests/IntegratedTests/I18nTest.cs | 63 ++++++++ .../Mock/Services/TestStringLocalizerFactory.cs | 25 ---- Timeline.Tests/UsernameValidatorUnitTest.cs | 8 +- Timeline/Authentication/AuthHandler.cs | 9 +- .../Controllers/Testing/TestingI18nController.cs | 36 +++++ Timeline/Controllers/TokenController.cs | 29 ++-- Timeline/Controllers/UserAvatarController.cs | 57 ++++---- Timeline/Controllers/UserController.cs | 27 ++-- Timeline/Filters/ContentHeaderAttributes.cs | 9 +- Timeline/GlobalSuppressions.cs | 1 - Timeline/Models/Http/Common.cs | 61 ++++---- Timeline/Models/Validation/UsernameValidator.cs | 17 +-- Timeline/Models/Validation/Validator.cs | 41 ++---- Timeline/Program.cs | 2 + .../Testing/TestingI18nController.Designer.cs | 72 +++++++++ .../Controllers/Testing/TestingI18nController.resx | 123 ++++++++++++++++ .../Testing/TestingI18nController.zh.resx | 123 ++++++++++++++++ .../Controllers/TokenController.Designer.cs | 45 ++++++ .../Resources/Controllers/TokenController.en.resx | 135 ----------------- .../Resources/Controllers/TokenController.resx | 15 ++ .../Controllers/UserAvatarController.Designer.cs | 72 +++++++++ .../Controllers/UserAvatarController.en.resx | 144 ------------------ .../Controllers/UserAvatarController.resx | 24 +++ .../Controllers/UserController.Designer.cs | 54 +++++++ .../Resources/Controllers/UserController.en.resx | 138 ------------------ Timeline/Resources/Controllers/UserController.resx | 18 +++ Timeline/Resources/Models/Http/Common.Designer.cs | 162 +++++++++++++++++++++ Timeline/Resources/Models/Http/Common.en.resx | 153 ------------------- Timeline/Resources/Models/Http/Common.resx | 153 +++++++++++++++++++ Timeline/Resources/Models/Http/Common.zh.resx | 22 +-- .../Validation/UsernameValidator.Designer.cs | 14 +- .../Models/Validation/UsernameValidator.en.resx | 129 ---------------- .../Models/Validation/UsernameValidator.resx | 8 +- .../Models/Validation/UsernameValidator.zh.resx | 6 +- .../Models/Validation/Validator.Designer.cs | 30 ++-- .../Resources/Models/Validation/Validator.en.resx | 129 ---------------- .../Resources/Models/Validation/Validator.resx | 18 +-- .../Services/UserAvatarService.Designer.cs | 12 +- Timeline/Resources/Services/UserAvatarService.resx | 6 +- Timeline/Services/DatabaseExtensions.cs | 5 +- Timeline/Services/UserAvatarService.cs | 6 +- Timeline/Services/UserService.cs | 10 +- Timeline/Timeline.csproj | 24 ++- 46 files changed, 1248 insertions(+), 1086 deletions(-) create mode 100644 Timeline.Tests/Helpers/UseCultureAttribute.cs create mode 100644 Timeline.Tests/IntegratedTests/I18nTest.cs delete mode 100644 Timeline.Tests/Mock/Services/TestStringLocalizerFactory.cs create mode 100644 Timeline/Controllers/Testing/TestingI18nController.cs create mode 100644 Timeline/Resources/Controllers/Testing/TestingI18nController.Designer.cs create mode 100644 Timeline/Resources/Controllers/Testing/TestingI18nController.resx create mode 100644 Timeline/Resources/Controllers/Testing/TestingI18nController.zh.resx delete mode 100644 Timeline/Resources/Controllers/TokenController.en.resx delete mode 100644 Timeline/Resources/Controllers/UserAvatarController.en.resx delete mode 100644 Timeline/Resources/Controllers/UserController.en.resx create mode 100644 Timeline/Resources/Models/Http/Common.Designer.cs delete mode 100644 Timeline/Resources/Models/Http/Common.en.resx create mode 100644 Timeline/Resources/Models/Http/Common.resx delete mode 100644 Timeline/Resources/Models/Validation/UsernameValidator.en.resx delete mode 100644 Timeline/Resources/Models/Validation/Validator.en.resx diff --git a/Timeline.Tests/Controllers/TokenControllerTest.cs b/Timeline.Tests/Controllers/TokenControllerTest.cs index 53b6c606..4a08ca0f 100644 --- a/Timeline.Tests/Controllers/TokenControllerTest.cs +++ b/Timeline.Tests/Controllers/TokenControllerTest.cs @@ -25,9 +25,7 @@ namespace Timeline.Tests.Controllers public TokenControllerTest() { - _controller = new TokenController(_mockUserService.Object, - NullLogger.Instance, _mockClock, - TestStringLocalizerFactory.Create().Create()); + _controller = new TokenController(_mockUserService.Object, NullLogger.Instance, _mockClock); } public void Dispose() diff --git a/Timeline.Tests/Controllers/UserControllerTest.cs b/Timeline.Tests/Controllers/UserControllerTest.cs index 781ec111..a9cce970 100644 --- a/Timeline.Tests/Controllers/UserControllerTest.cs +++ b/Timeline.Tests/Controllers/UserControllerTest.cs @@ -27,9 +27,7 @@ namespace Timeline.Tests.Controllers public UserControllerTest() { - _controller = new UserController(NullLogger.Instance, - _mockUserService.Object, - TestStringLocalizerFactory.Create()); + _controller = new UserController(NullLogger.Instance, _mockUserService.Object); } public void Dispose() diff --git a/Timeline.Tests/Helpers/UseCultureAttribute.cs b/Timeline.Tests/Helpers/UseCultureAttribute.cs new file mode 100644 index 00000000..f0064c01 --- /dev/null +++ b/Timeline.Tests/Helpers/UseCultureAttribute.cs @@ -0,0 +1,91 @@ +using System; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Threading; +using Xunit.Sdk; + +// Copied from https://github.com/xunit/samples.xunit/blob/master/UseCulture/UseCultureAttribute.cs + +/// +/// Apply this attribute to your test method to replace the +/// and +/// with another culture. +/// +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] +public class UseCultureAttribute : BeforeAfterTestAttribute +{ + readonly Lazy culture; + readonly Lazy uiCulture; + + CultureInfo originalCulture; + CultureInfo originalUICulture; + + /// + /// Replaces the culture and UI culture of the current thread with + /// + /// + /// The name of the culture. + /// + /// + /// This constructor overload uses for both + /// and . + /// + /// + public UseCultureAttribute(string culture) + : this(culture, culture) { } + + /// + /// Replaces the culture and UI culture of the current thread with + /// and + /// + /// The name of the culture. + /// The name of the UI culture. + public UseCultureAttribute(string culture, string uiCulture) + { + this.culture = new Lazy(() => new CultureInfo(culture, false)); + this.uiCulture = new Lazy(() => new CultureInfo(uiCulture, false)); + } + + /// + /// Gets the culture. + /// + public CultureInfo Culture { get { return culture.Value; } } + + /// + /// Gets the UI culture. + /// + public CultureInfo UICulture { get { return uiCulture.Value; } } + + /// + /// Stores the current + /// and + /// and replaces them with the new cultures defined in the constructor. + /// + /// The method under test + public override void Before(MethodInfo methodUnderTest) + { + originalCulture = Thread.CurrentThread.CurrentCulture; + originalUICulture = Thread.CurrentThread.CurrentUICulture; + + Thread.CurrentThread.CurrentCulture = Culture; + Thread.CurrentThread.CurrentUICulture = UICulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } + + /// + /// Restores the original and + /// to + /// + /// The method under test + public override void After(MethodInfo methodUnderTest) + { + Thread.CurrentThread.CurrentCulture = originalCulture; + Thread.CurrentThread.CurrentUICulture = originalUICulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } +} diff --git a/Timeline.Tests/IntegratedTests/I18nTest.cs b/Timeline.Tests/IntegratedTests/I18nTest.cs new file mode 100644 index 00000000..67bbea5c --- /dev/null +++ b/Timeline.Tests/IntegratedTests/I18nTest.cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Mvc.Testing; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Threading.Tasks; +using Timeline.Tests.Helpers; +using Xunit; +using FluentAssertions; + +namespace Timeline.Tests.IntegratedTests +{ + [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1054:Uri parameters should not be strings")] + public class I18nTest : IClassFixture>, IDisposable + { + private readonly TestApplication _testApp; + private readonly HttpClient _client; + + public I18nTest(WebApplicationFactory factory) + { + _testApp = new TestApplication(factory); + _client = _testApp.Factory.CreateDefaultClient(); + } + + public void Dispose() + { + _client.Dispose(); + _testApp.Dispose(); + } + + private const string DirectUrl = "testing/i18n/direct"; + private const string LocalizerUrl = "testing/i18n/localizer"; + + [Theory] + [InlineData(DirectUrl)] + [InlineData(LocalizerUrl)] + public async Task DefaultShouldReturnEnglish(string url) + { + (await _client.GetStringAsync(url)).Should().ContainEquivalentOf("English"); + } + + [Theory] + [InlineData(DirectUrl, "en", true)] + [InlineData(LocalizerUrl, "en", true)] + [InlineData(DirectUrl, "en-US", true)] + [InlineData(LocalizerUrl, "en-US", true)] + [InlineData(DirectUrl, "zh", false)] + [InlineData(LocalizerUrl, "zh", false)] + public async Task ShouldWork(string url, string acceptLanguage, bool english) + { + var request = new HttpRequestMessage + { + Method = HttpMethod.Get, + RequestUri = new Uri(url, UriKind.RelativeOrAbsolute) + }; + request.Headers.AcceptLanguage.Add(new StringWithQualityHeaderValue(acceptLanguage)); + var body = await (await _client.SendAsync(request)).Content.ReadAsStringAsync(); + body.Should().ContainEquivalentOf(english ? "English" : "中文"); + request.Dispose(); + } + } +} diff --git a/Timeline.Tests/Mock/Services/TestStringLocalizerFactory.cs b/Timeline.Tests/Mock/Services/TestStringLocalizerFactory.cs deleted file mode 100644 index 4084dd8f..00000000 --- a/Timeline.Tests/Mock/Services/TestStringLocalizerFactory.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Logging.Abstractions; -using Microsoft.Extensions.Options; - -namespace Timeline.Tests.Mock.Services -{ - internal static class TestStringLocalizerFactory - { - internal static IStringLocalizerFactory Create() - { - return new ResourceManagerStringLocalizerFactory( - Options.Create(new LocalizationOptions() - { - ResourcesPath = "Resource" - }), - NullLoggerFactory.Instance - ); - } - - internal static IStringLocalizer Create(this IStringLocalizerFactory factory) - { - return new StringLocalizer(factory); - } - } -} diff --git a/Timeline.Tests/UsernameValidatorUnitTest.cs b/Timeline.Tests/UsernameValidatorUnitTest.cs index 283e18e2..d02367be 100644 --- a/Timeline.Tests/UsernameValidatorUnitTest.cs +++ b/Timeline.Tests/UsernameValidatorUnitTest.cs @@ -4,6 +4,7 @@ using Xunit; namespace Timeline.Tests { + [UseCulture("en")] public class UsernameValidatorUnitTest : IClassFixture { private readonly UsernameValidator _validator; @@ -15,9 +16,9 @@ namespace Timeline.Tests private string FailAndMessage(string username) { - var (result, messageGenerator) = _validator.Validate(username); + var (result, message) = _validator.Validate(username); result.Should().BeFalse(); - return messageGenerator(null); + return message; } [Fact] @@ -29,9 +30,8 @@ namespace Timeline.Tests [Fact] public void NotString() { - var (result, messageGenerator) = _validator.Validate(123); + var (result, message) = _validator.Validate(123); result.Should().BeFalse(); - var message = messageGenerator(null); message.Should().ContainEquivalentOf("type"); } diff --git a/Timeline/Authentication/AuthHandler.cs b/Timeline/Authentication/AuthHandler.cs index 602a44db..2b457eb1 100644 --- a/Timeline/Authentication/AuthHandler.cs +++ b/Timeline/Authentication/AuthHandler.cs @@ -9,6 +9,7 @@ using System.Text.Encodings.Web; using System.Threading.Tasks; using Timeline.Models; using Timeline.Services; +using static Timeline.Resources.Authentication.AuthHandler; namespace Timeline.Authentication { @@ -46,7 +47,7 @@ namespace Timeline.Authentication if (!string.IsNullOrEmpty(header) && header.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase)) { var token = header.Substring("Bearer ".Length).Trim(); - _logger.LogInformation(Resources.Authentication.AuthHandler.LogTokenFoundInHeader, token); + _logger.LogInformation(LogTokenFoundInHeader, token); return token; } @@ -57,7 +58,7 @@ namespace Timeline.Authentication string token = Request.Query[paramQueryKey]; if (!string.IsNullOrEmpty(token)) { - _logger.LogInformation(Resources.Authentication.AuthHandler.LogTokenFoundInQuery, paramQueryKey, token); + _logger.LogInformation(LogTokenFoundInQuery, paramQueryKey, token); return token; } } @@ -71,7 +72,7 @@ namespace Timeline.Authentication var token = ExtractToken(); if (string.IsNullOrEmpty(token)) { - _logger.LogInformation(Resources.Authentication.AuthHandler.LogTokenNotFound); + _logger.LogInformation(LogTokenNotFound); return AuthenticateResult.NoResult(); } @@ -90,7 +91,7 @@ namespace Timeline.Authentication } catch (Exception e) when (!(e is ArgumentException)) { - _logger.LogInformation(e, Resources.Authentication.AuthHandler.LogTokenValidationFail); + _logger.LogInformation(e, LogTokenValidationFail); return AuthenticateResult.Fail(e); } } diff --git a/Timeline/Controllers/Testing/TestingI18nController.cs b/Timeline/Controllers/Testing/TestingI18nController.cs new file mode 100644 index 00000000..febb56a5 --- /dev/null +++ b/Timeline/Controllers/Testing/TestingI18nController.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Localization; + +// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 + +namespace Timeline.Controllers.Testing +{ + [Route("testing/i18n")] + [ApiController] + public class TestingI18nController : Controller + { + private readonly IStringLocalizer _stringLocalizer; + + public TestingI18nController(IStringLocalizer stringLocalizer) + { + _stringLocalizer = stringLocalizer; + } + + [HttpGet("direct")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1822:Mark members as static")] + public ActionResult Direct() + { + return Resources.Controllers.Testing.TestingI18nController.TestString; + } + + [HttpGet("localizer")] + public ActionResult Localizer() + { + return _stringLocalizer["TestString"].Value; + } + } +} diff --git a/Timeline/Controllers/TokenController.cs b/Timeline/Controllers/TokenController.cs index 4e32d26f..01f4778f 100644 --- a/Timeline/Controllers/TokenController.cs +++ b/Timeline/Controllers/TokenController.cs @@ -3,12 +3,11 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.IdentityModel.Tokens; using System; +using System.Globalization; using System.Threading.Tasks; +using Timeline.Helpers; using Timeline.Models.Http; using Timeline.Services; -using Timeline.Helpers; -using Microsoft.Extensions.Localization; -using System.Globalization; using static Timeline.Resources.Controllers.TokenController; namespace Timeline @@ -45,14 +44,12 @@ namespace Timeline.Controllers private readonly IUserService _userService; private readonly ILogger _logger; private readonly IClock _clock; - private readonly IStringLocalizer _localizer; - public TokenController(IUserService userService, ILogger logger, IClock clock, IStringLocalizer localizer) + public TokenController(IUserService userService, ILogger logger, IClock clock) { _userService = userService; _logger = logger; _clock = clock; - _localizer = localizer; } [HttpPost("create")] @@ -79,7 +76,7 @@ namespace Timeline.Controllers _logger.LogInformation(Log.Format(LogCreateSuccess, ("Username", request.Username), - ("Expire At", expireTime?.ToString(CultureInfo.CurrentUICulture.DateTimeFormat) ?? "default") + ("Expire At", expireTime?.ToString(CultureInfo.CurrentCulture.DateTimeFormat) ?? "default") )); return Ok(new CreateTokenResponse { @@ -90,14 +87,16 @@ namespace Timeline.Controllers catch (UserNotExistException e) { LogFailure(LogUserNotExist, e); - return BadRequest(new CommonResponse(ErrorCodes.Http.Token.Create.BadCredential, - _localizer["ErrorBadCredential"])); + return BadRequest(new CommonResponse( + ErrorCodes.Http.Token.Create.BadCredential, + ErrorBadCredential)); } catch (BadPasswordException e) { LogFailure(LogBadPassword, e); - return BadRequest(new CommonResponse(ErrorCodes.Http.Token.Create.BadCredential, - _localizer["ErrorBadCredential"])); + return BadRequest(new CommonResponse( + ErrorCodes.Http.Token.Create.BadCredential, + ErrorBadCredential)); } } @@ -132,7 +131,7 @@ namespace Timeline.Controllers LogFailure(LogVerifyExpire, e, ("Expires", innerException?.Expires), ("Current Time", _clock.GetCurrentTime())); return BadRequest(new CommonResponse( - ErrorCodes.Http.Token.Verify.Expired, _localizer["ErrorVerifyExpire"])); + ErrorCodes.Http.Token.Verify.Expired, ErrorVerifyExpire)); } else if (e.ErrorCode == JwtVerifyException.ErrorCodes.OldVersion) { @@ -140,20 +139,20 @@ namespace Timeline.Controllers LogFailure(LogVerifyOldVersion, e, ("Token Version", innerException?.TokenVersion), ("Required Version", innerException?.RequiredVersion)); return BadRequest(new CommonResponse( - ErrorCodes.Http.Token.Verify.OldVersion, _localizer["ErrorVerifyOldVersion"])); + ErrorCodes.Http.Token.Verify.OldVersion, ErrorVerifyOldVersion)); } else { LogFailure(LogVerifyBadFormat, e); return BadRequest(new CommonResponse( - ErrorCodes.Http.Token.Verify.BadFormat, _localizer["ErrorVerifyBadFormat"])); + ErrorCodes.Http.Token.Verify.BadFormat, ErrorVerifyBadFormat)); } } catch (UserNotExistException e) { LogFailure(LogVerifyUserNotExist, e); return BadRequest(new CommonResponse( - ErrorCodes.Http.Token.Verify.UserNotExist, _localizer["ErrorVerifyUserNotExist"])); + ErrorCodes.Http.Token.Verify.UserNotExist, ErrorVerifyUserNotExist)); } } } diff --git a/Timeline/Controllers/UserAvatarController.cs b/Timeline/Controllers/UserAvatarController.cs index 838a3928..7c77897d 100644 --- a/Timeline/Controllers/UserAvatarController.cs +++ b/Timeline/Controllers/UserAvatarController.cs @@ -1,7 +1,6 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; using System; @@ -13,6 +12,7 @@ using Timeline.Helpers; using Timeline.Models.Http; using Timeline.Models.Validation; using Timeline.Services; +using static Timeline.Resources.Controllers.UserAvatarController; namespace Timeline { @@ -56,15 +56,10 @@ namespace Timeline.Controllers private readonly IUserAvatarService _service; - private readonly IStringLocalizerFactory _localizerFactory; - private readonly IStringLocalizer _localizer; - - public UserAvatarController(ILogger logger, IUserAvatarService service, IStringLocalizerFactory localizerFactory) + public UserAvatarController(ILogger logger, IUserAvatarService service) { _logger = logger; _service = service; - _localizerFactory = localizerFactory; - _localizer = new StringLocalizer(localizerFactory); } [HttpGet("users/{username}/avatar")] @@ -82,15 +77,15 @@ namespace Timeline.Controllers { if (!EntityTagHeaderValue.TryParseStrictList(value, out var eTagList)) { - _logger.LogInformation(Log.Format(Resources.Controllers.UserAvatarController.LogGetBadIfNoneMatch, + _logger.LogInformation(Log.Format(LogGetBadIfNoneMatch, ("Username", username), ("If-None-Match", value))); - return BadRequest(HeaderErrorResponse.BadIfNonMatch(_localizerFactory)); + return BadRequest(HeaderErrorResponse.BadIfNonMatch()); } if (eTagList.FirstOrDefault(e => e.Equals(eTag)) != null) { Response.Headers.Add("ETag", eTagValue); - _logger.LogInformation(Log.Format(Resources.Controllers.UserAvatarController.LogGetReturnNotModify, ("Username", username))); + _logger.LogInformation(Log.Format(LogGetReturnNotModify, ("Username", username))); return StatusCode(StatusCodes.Status304NotModified); } } @@ -98,13 +93,13 @@ namespace Timeline.Controllers var avatarInfo = await _service.GetAvatar(username); var avatar = avatarInfo.Avatar; - _logger.LogInformation(Log.Format(Resources.Controllers.UserAvatarController.LogGetReturnData, ("Username", username))); + _logger.LogInformation(Log.Format(LogGetReturnData, ("Username", username))); return File(avatar.Data, avatar.Type, new DateTimeOffset(avatarInfo.LastModified), eTag); } catch (UserNotExistException e) { - _logger.LogInformation(e, Log.Format(Resources.Controllers.UserAvatarController.LogGetUserNotExist, ("Username", username))); - return NotFound(new CommonResponse(ErrorCodes.Http.UserAvatar.Get.UserNotExist, _localizer["ErrorGetUserNotExist"])); + _logger.LogInformation(e, Log.Format(LogGetUserNotExist, ("Username", username))); + return NotFound(new CommonResponse(ErrorCodes.Http.UserAvatar.Get.UserNotExist, ErrorGetUserNotExist)); } } @@ -116,14 +111,14 @@ namespace Timeline.Controllers { var contentLength = Request.ContentLength!.Value; if (contentLength > 1000 * 1000 * 10) - return BadRequest(ContentErrorResponse.TooBig(_localizerFactory, "10MB")); + return BadRequest(ContentErrorResponse.TooBig("10MB")); if (!User.IsAdministrator() && User.Identity.Name != username) { - _logger.LogInformation(Log.Format(Resources.Controllers.UserAvatarController.LogPutForbid, + _logger.LogInformation(Log.Format(LogPutForbid, ("Operator Username", User.Identity.Name), ("Username To Put Avatar", username))); return StatusCode(StatusCodes.Status403Forbidden, - new CommonResponse(ErrorCodes.Http.UserAvatar.Put.Forbid, _localizer["ErrorPutForbid"])); + new CommonResponse(ErrorCodes.Http.UserAvatar.Put.Forbid, ErrorPutForbid)); } try @@ -132,11 +127,11 @@ namespace Timeline.Controllers var bytesRead = await Request.Body.ReadAsync(data); if (bytesRead != contentLength) - return BadRequest(ContentErrorResponse.UnmatchedLength_Smaller(_localizerFactory)); + return BadRequest(ContentErrorResponse.UnmatchedLength_Smaller()); var extraByte = new byte[1]; if (await Request.Body.ReadAsync(extraByte) != 0) - return BadRequest(ContentErrorResponse.UnmatchedLength_Bigger(_localizerFactory)); + return BadRequest(ContentErrorResponse.UnmatchedLength_Bigger()); await _service.SetAvatar(username, new Avatar { @@ -144,30 +139,30 @@ namespace Timeline.Controllers Type = Request.ContentType }); - _logger.LogInformation(Log.Format(Resources.Controllers.UserAvatarController.LogPutSuccess, + _logger.LogInformation(Log.Format(LogPutSuccess, ("Username", username), ("Mime Type", Request.ContentType))); return Ok(); } catch (UserNotExistException e) { - _logger.LogInformation(e, Log.Format(Resources.Controllers.UserAvatarController.LogPutUserNotExist, ("Username", username))); - return BadRequest(new CommonResponse(ErrorCodes.Http.UserAvatar.Put.UserNotExist, _localizer["ErrorPutUserNotExist"])); + _logger.LogInformation(e, Log.Format(LogPutUserNotExist, ("Username", username))); + return BadRequest(new CommonResponse(ErrorCodes.Http.UserAvatar.Put.UserNotExist, ErrorPutUserNotExist)); } catch (AvatarFormatException e) { var (code, message) = e.Error switch { AvatarFormatException.ErrorReason.CantDecode => - (ErrorCodes.Http.UserAvatar.Put.BadFormat_CantDecode, _localizer["ErrorPutBadFormatCantDecode"]), + (ErrorCodes.Http.UserAvatar.Put.BadFormat_CantDecode, ErrorPutBadFormatCantDecode), AvatarFormatException.ErrorReason.UnmatchedFormat => - (ErrorCodes.Http.UserAvatar.Put.BadFormat_UnmatchedFormat, _localizer["ErrorPutBadFormatUnmatchedFormat"]), + (ErrorCodes.Http.UserAvatar.Put.BadFormat_UnmatchedFormat, ErrorPutBadFormatUnmatchedFormat), AvatarFormatException.ErrorReason.BadSize => - (ErrorCodes.Http.UserAvatar.Put.BadFormat_BadSize, _localizer["ErrorPutBadFormatBadSize"]), + (ErrorCodes.Http.UserAvatar.Put.BadFormat_BadSize, ErrorPutBadFormatBadSize), _ => - throw new Exception(Resources.Controllers.UserAvatarController.ExceptionUnknownAvatarFormatError) + throw new Exception(ExceptionUnknownAvatarFormatError) }; - _logger.LogInformation(e, Log.Format(Resources.Controllers.UserAvatarController.LogPutUserBadFormat, ("Username", username))); + _logger.LogInformation(e, Log.Format(LogPutUserBadFormat, ("Username", username))); return BadRequest(new CommonResponse(code, message)); } } @@ -178,23 +173,23 @@ namespace Timeline.Controllers { if (!User.IsAdministrator() && User.Identity.Name != username) { - _logger.LogInformation(Log.Format(Resources.Controllers.UserAvatarController.LogPutUserBadFormat, + _logger.LogInformation(Log.Format(LogPutUserBadFormat, ("Operator Username", User.Identity.Name), ("Username To Delete Avatar", username))); return StatusCode(StatusCodes.Status403Forbidden, - new CommonResponse(ErrorCodes.Http.UserAvatar.Delete.Forbid, _localizer["ErrorDeleteForbid"])); + new CommonResponse(ErrorCodes.Http.UserAvatar.Delete.Forbid, ErrorDeleteForbid)); } try { await _service.SetAvatar(username, null); - _logger.LogInformation(Log.Format(Resources.Controllers.UserAvatarController.LogDeleteSuccess, ("Username", username))); + _logger.LogInformation(Log.Format(LogDeleteSuccess, ("Username", username))); return Ok(); } catch (UserNotExistException e) { - _logger.LogInformation(e, Log.Format(Resources.Controllers.UserAvatarController.LogDeleteNotExist, ("Username", username))); - return BadRequest(new CommonResponse(ErrorCodes.Http.UserAvatar.Delete.UserNotExist, _localizer["ErrorDeleteUserNotExist"])); + _logger.LogInformation(e, Log.Format(LogDeleteNotExist, ("Username", username))); + return BadRequest(new CommonResponse(ErrorCodes.Http.UserAvatar.Delete.UserNotExist, ErrorDeleteUserNotExist)); } } } diff --git a/Timeline/Controllers/UserController.cs b/Timeline/Controllers/UserController.cs index 1771dc85..7b441c3a 100644 --- a/Timeline/Controllers/UserController.cs +++ b/Timeline/Controllers/UserController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; +using System.Globalization; using System.Threading.Tasks; using Timeline.Authentication; using Timeline.Helpers; @@ -56,15 +56,11 @@ namespace Timeline.Controllers private readonly ILogger _logger; private readonly IUserService _userService; - private readonly IStringLocalizerFactory _localizerFactory; - private readonly IStringLocalizer _localizer; - public UserController(ILogger logger, IUserService userService, IStringLocalizerFactory localizerFactory) + public UserController(ILogger logger, IUserService userService) { _logger = logger; _userService = userService; - _localizerFactory = localizerFactory; - _localizer = localizerFactory.Create(GetType()); } [HttpGet("users"), AdminAuthorize] @@ -80,7 +76,7 @@ namespace Timeline.Controllers if (user == null) { _logger.LogInformation(Log.Format(LogGetUserNotExist, ("Username", username))); - return NotFound(new CommonResponse(ErrorCodes.Http.User.Get.NotExist, _localizer["ErrorGetUserNotExist"])); + return NotFound(new CommonResponse(ErrorCodes.Http.User.Get.NotExist, ErrorGetUserNotExist)); } return Ok(user); } @@ -93,10 +89,10 @@ namespace Timeline.Controllers { case PutResult.Create: _logger.LogInformation(Log.Format(LogPutCreate, ("Username", username))); - return CreatedAtAction("Get", new { username }, CommonPutResponse.Create(_localizerFactory)); + return CreatedAtAction("Get", new { username }, CommonPutResponse.Create()); case PutResult.Modify: _logger.LogInformation(Log.Format(LogPutModify, ("Username", username))); - return Ok(CommonPutResponse.Modify(_localizerFactory)); + return Ok(CommonPutResponse.Modify()); default: throw new InvalidBranchException(); } @@ -113,7 +109,7 @@ namespace Timeline.Controllers catch (UserNotExistException e) { _logger.LogInformation(e, Log.Format(LogPatchUserNotExist, ("Username", username))); - return NotFound(new CommonResponse(ErrorCodes.Http.User.Patch.NotExist, _localizer["ErrorPatchUserNotExist"])); + return NotFound(new CommonResponse(ErrorCodes.Http.User.Patch.NotExist, ErrorPatchUserNotExist)); } } @@ -124,12 +120,12 @@ namespace Timeline.Controllers { await _userService.DeleteUser(username); _logger.LogInformation(Log.Format(LogDeleteDelete, ("Username", username))); - return Ok(CommonDeleteResponse.Delete(_localizerFactory)); + return Ok(CommonDeleteResponse.Delete()); } catch (UserNotExistException e) { _logger.LogInformation(e, Log.Format(LogDeleteNotExist, ("Username", username))); - return Ok(CommonDeleteResponse.NotExist(_localizerFactory)); + return Ok(CommonDeleteResponse.NotExist()); } } @@ -147,13 +143,14 @@ namespace Timeline.Controllers { _logger.LogInformation(e, Log.Format(LogChangeUsernameNotExist, ("Old Username", request.OldUsername), ("New Username", request.NewUsername))); - return BadRequest(new CommonResponse(ErrorCodes.Http.User.Op.ChangeUsername.NotExist, _localizer["ErrorChangeUsernameNotExist", request.OldUsername])); + return BadRequest(new CommonResponse(ErrorCodes.Http.User.Op.ChangeUsername.NotExist, + string.Format(CultureInfo.CurrentCulture, ErrorChangeUsernameNotExist, request.OldUsername))); } catch (UsernameConfictException e) { _logger.LogInformation(e, Log.Format(LogChangeUsernameAlreadyExist, ("Old Username", request.OldUsername), ("New Username", request.NewUsername))); - return BadRequest(new CommonResponse(ErrorCodes.Http.User.Op.ChangeUsername.AlreadyExist, _localizer["ErrorChangeUsernameAlreadyExist"])); + return BadRequest(new CommonResponse(ErrorCodes.Http.User.Op.ChangeUsername.AlreadyExist, ErrorChangeUsernameAlreadyExist)); } // there is no need to catch bad format exception because it is already checked in model validation. } @@ -172,7 +169,7 @@ namespace Timeline.Controllers _logger.LogInformation(e, Log.Format(LogChangePasswordBadPassword, ("Username", User.Identity.Name), ("Old Password", request.OldPassword))); return BadRequest(new CommonResponse(ErrorCodes.Http.User.Op.ChangePassword.BadOldPassword, - _localizer["ErrorChangePasswordBadPassword"])); + ErrorChangePasswordBadPassword)); } // User can't be non-existent or the token is bad. } diff --git a/Timeline/Filters/ContentHeaderAttributes.cs b/Timeline/Filters/ContentHeaderAttributes.cs index e3d4eeb2..99bd1540 100644 --- a/Timeline/Filters/ContentHeaderAttributes.cs +++ b/Timeline/Filters/ContentHeaderAttributes.cs @@ -13,8 +13,7 @@ namespace Timeline.Filters { if (context.HttpContext.Request.ContentType == null) { - var localizerFactory = context.HttpContext.RequestServices.GetRequiredService(); - context.Result = new BadRequestObjectResult(HeaderErrorResponse.MissingContentType(localizerFactory)); + context.Result = new BadRequestObjectResult(HeaderErrorResponse.MissingContentType()); } } } @@ -39,15 +38,13 @@ namespace Timeline.Filters { if (context.HttpContext.Request.ContentLength == null) { - var localizerFactory = context.HttpContext.RequestServices.GetRequiredService(); - context.Result = new BadRequestObjectResult(HeaderErrorResponse.MissingContentLength(localizerFactory)); + context.Result = new BadRequestObjectResult(HeaderErrorResponse.MissingContentLength()); return; } if (RequireNonZero && context.HttpContext.Request.ContentLength.Value == 0) { - var localizerFactory = context.HttpContext.RequestServices.GetRequiredService(); - context.Result = new BadRequestObjectResult(HeaderErrorResponse.ZeroContentLength(localizerFactory)); + context.Result = new BadRequestObjectResult(HeaderErrorResponse.ZeroContentLength()); return; } } diff --git a/Timeline/GlobalSuppressions.cs b/Timeline/GlobalSuppressions.cs index e720e5b7..076c2005 100644 --- a/Timeline/GlobalSuppressions.cs +++ b/Timeline/GlobalSuppressions.cs @@ -10,4 +10,3 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Error code constant identifiers.", Scope = "type", Target = "Timeline.ErrorCodes")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1716:Identifiers should not match keywords", Justification = "Error code constant identifiers.", Scope = "type", Target = "Timeline.ErrorCodes")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1724:Type names should not match namespaces", Justification = "Error code constant identifiers.", Scope = "type", Target = "Timeline.ErrorCodes")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1824:Mark assemblies with NeutralResourcesLanguageAttribute", Justification = "Applying this breaks the function of resources in my app.")] diff --git a/Timeline/Models/Http/Common.cs b/Timeline/Models/Http/Common.cs index 39ddddd9..2c9ee9e7 100644 --- a/Timeline/Models/Http/Common.cs +++ b/Timeline/Models/Http/Common.cs @@ -1,5 +1,5 @@ -using Microsoft.Extensions.Localization; -using Timeline.Helpers; +using System.Globalization; +using static Timeline.Resources.Models.Http.Common; namespace Timeline.Models.Http { @@ -27,48 +27,42 @@ namespace Timeline.Models.Http internal static class HeaderErrorResponse { - internal static CommonResponse MissingContentType(IStringLocalizerFactory localizerFactory) + internal static CommonResponse MissingContentType() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonResponse(ErrorCodes.Http.Common.Header.Missing_ContentType, localizer["HeaderMissingContentType"]); + return new CommonResponse(ErrorCodes.Http.Common.Header.Missing_ContentType, MessageHeaderMissingContentType); } - internal static CommonResponse MissingContentLength(IStringLocalizerFactory localizerFactory) + internal static CommonResponse MissingContentLength() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonResponse(ErrorCodes.Http.Common.Header.Missing_ContentLength, localizer["HeaderMissingContentLength"]); + return new CommonResponse(ErrorCodes.Http.Common.Header.Missing_ContentLength, MessageHeaderMissingContentLength); } - internal static CommonResponse ZeroContentLength(IStringLocalizerFactory localizerFactory) + internal static CommonResponse ZeroContentLength() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonResponse(ErrorCodes.Http.Common.Header.Zero_ContentLength, localizer["HeaderZeroContentLength"]); + return new CommonResponse(ErrorCodes.Http.Common.Header.Zero_ContentLength, MessageHeaderZeroContentLength); } - internal static CommonResponse BadIfNonMatch(IStringLocalizerFactory localizerFactory) + internal static CommonResponse BadIfNonMatch() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonResponse(ErrorCodes.Http.Common.Header.BadFormat_IfNonMatch, localizer["HeaderBadIfNonMatch"]); + return new CommonResponse(ErrorCodes.Http.Common.Header.BadFormat_IfNonMatch, MessageHeaderBadIfNonMatch); } } internal static class ContentErrorResponse { - internal static CommonResponse TooBig(IStringLocalizerFactory localizerFactory, string maxLength) + internal static CommonResponse TooBig(string maxLength) { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonResponse(ErrorCodes.Http.Common.Content.TooBig, localizer["ContentTooBig", maxLength]); + return new CommonResponse(ErrorCodes.Http.Common.Content.TooBig, + string.Format(CultureInfo.CurrentCulture, MessageContentTooBig, maxLength)); } - internal static CommonResponse UnmatchedLength_Smaller(IStringLocalizerFactory localizerFactory) + internal static CommonResponse UnmatchedLength_Smaller() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonResponse(ErrorCodes.Http.Common.Content.UnmatchedLength_Smaller, localizer["ContentUnmatchedLengthSmaller"]); + return new CommonResponse(ErrorCodes.Http.Common.Content.UnmatchedLength_Smaller, MessageContentUnmatchedLengthSmaller); } - internal static CommonResponse UnmatchedLength_Bigger(IStringLocalizerFactory localizerFactory) + internal static CommonResponse UnmatchedLength_Bigger() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonResponse(ErrorCodes.Http.Common.Content.UnmatchedLength_Bigger, localizer["ContentUnmatchedLengthBigger"]); + return new CommonResponse(ErrorCodes.Http.Common.Content.UnmatchedLength_Bigger, MessageContentUnmatchedLengthBigger); } } @@ -112,17 +106,14 @@ namespace Timeline.Models.Http } - internal static CommonPutResponse Create(IStringLocalizerFactory localizerFactory) + internal static CommonPutResponse Create() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonPutResponse(0, localizer["PutCreate"], true); + return new CommonPutResponse(0, MessagePutCreate, true); } - internal static CommonPutResponse Modify(IStringLocalizerFactory localizerFactory) + internal static CommonPutResponse Modify() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonPutResponse(0, localizer["PutModify"], false); - + return new CommonPutResponse(0, MessagePutModify, false); } } @@ -149,16 +140,14 @@ namespace Timeline.Models.Http } - internal static CommonDeleteResponse Delete(IStringLocalizerFactory localizerFactory) + internal static CommonDeleteResponse Delete() { - var localizer = localizerFactory.Create("Models.Http.Common"); - return new CommonDeleteResponse(0, localizer["DeleteDelete"], true); + return new CommonDeleteResponse(0, MessageDeleteDelete, true); } - internal static CommonDeleteResponse NotExist(IStringLocalizerFactory localizerFactory) + internal static CommonDeleteResponse NotExist() { - var localizer = localizerFactory.Create("Models.Models.Http.Common"); - return new CommonDeleteResponse(0, localizer["DeleteNotExist"], false); + return new CommonDeleteResponse(0, MessageDeleteNotExist, false); } } } diff --git a/Timeline/Models/Validation/UsernameValidator.cs b/Timeline/Models/Validation/UsernameValidator.cs index dc237add..fc6cdf37 100644 --- a/Timeline/Models/Validation/UsernameValidator.cs +++ b/Timeline/Models/Validation/UsernameValidator.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using static Timeline.Resources.Models.Validation.UsernameValidator; namespace Timeline.Models.Validation { @@ -8,33 +9,27 @@ namespace Timeline.Models.Validation public const int MaxLength = 26; [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "Already checked in base class.")] - protected override (bool, ValidationMessageGenerator) DoValidate(string value) + protected override (bool, string) DoValidate(string value) { if (value.Length == 0) { - return (false, factory => - factory?.Create(typeof(UsernameValidator))?["ValidationMessageEmptyString"] - ?? Resources.Models.Validation.UsernameValidator.InvariantValidationMessageEmptyString); + return (false, MessageEmptyString); } if (value.Length > 26) { - return (false, factory => - factory?.Create(typeof(UsernameValidator))?["ValidationMessageTooLong"] - ?? Resources.Models.Validation.UsernameValidator.InvariantValidationMessageTooLong); + return (false, MessageTooLong); } foreach ((char c, int i) in value.Select((c, i) => (c, i))) { if (!(char.IsLetterOrDigit(c) || c == '-' || c == '_')) { - return (false, factory => - factory?.Create(typeof(UsernameValidator))?["ValidationMessageInvalidChar"] - ?? Resources.Models.Validation.UsernameValidator.InvariantValidationMessageInvalidChar); + return (false, MessageInvalidChar); } } - return (true, SuccessMessageGenerator); + return (true, GetSuccessMessage()); } } diff --git a/Timeline/Models/Validation/Validator.cs b/Timeline/Models/Validation/Validator.cs index d2c7c377..a16f6f81 100644 --- a/Timeline/Models/Validation/Validator.cs +++ b/Timeline/Models/Validation/Validator.cs @@ -3,17 +3,10 @@ using Microsoft.Extensions.Localization; using System; using System.ComponentModel.DataAnnotations; using Timeline.Helpers; +using static Timeline.Resources.Models.Validation.Validator; namespace Timeline.Models.Validation { - /// - /// Generate a message from a localizer factory. - /// If localizerFactory is null, it should return a culture-invariant message. - /// - /// The localizer factory. Could be null. - /// The message. - public delegate string ValidationMessageGenerator(IStringLocalizerFactory? localizerFactory); - /// /// A validator to validate value. /// @@ -23,8 +16,8 @@ namespace Timeline.Models.Validation /// Validate given value. /// /// The value to validate. - /// Validation success or not and the message generator. - (bool, ValidationMessageGenerator) Validate(object? value); + /// Validation success or not and message. + (bool, string) Validate(object? value); } /// @@ -40,14 +33,11 @@ namespace Timeline.Models.Validation /// public abstract class Validator : IValidator { - public (bool, ValidationMessageGenerator) Validate(object? value) + public (bool, string) Validate(object? value) { if (value == null) { - return (false, factory => - factory?.Create("Models.Validation.Validator")?["ValidatorMessageNull"] - ?? Resources.Models.Validation.Validator.InvariantValidatorMessageNull - ); + return (false, ValidatorMessageNull); } if (value is T v) @@ -56,16 +46,13 @@ namespace Timeline.Models.Validation } else { - return (false, factory => - factory?.Create("Models.Validation.Validator")?["ValidatorMessageBadType", typeof(T).FullName] - ?? Resources.Models.Validation.Validator.InvariantValidatorMessageBadType); + return (false, ValidatorMessageBadType); } } - protected static ValidationMessageGenerator SuccessMessageGenerator { get; } = factory => - factory?.Create("Models.Validation.Validator")?["ValidatorMessageSuccess"] ?? Resources.Models.Validation.Validator.InvariantValidatorMessageSuccess; + protected static string GetSuccessMessage() => ValidatorMessageSuccess; - protected abstract (bool, ValidationMessageGenerator) DoValidate(T value); + protected abstract (bool, string) DoValidate(T value); } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, @@ -93,9 +80,7 @@ namespace Timeline.Models.Validation throw new ArgumentNullException(nameof(validatorType)); if (!typeof(IValidator).IsAssignableFrom(validatorType)) - throw new ArgumentException( - Resources.Models.Validation.Validator.ValidateWithAttributeNotValidator, - nameof(validatorType)); + throw new ArgumentException(ValidateWithAttributeExceptionNotValidator, nameof(validatorType)); try { @@ -103,22 +88,20 @@ namespace Timeline.Models.Validation } catch (Exception e) { - throw new ArgumentException( - Resources.Models.Validation.Validator.ValidateWithAttributeCreateFail, e); + throw new ArgumentException(ValidateWithAttributeExceptionCreateFail, e); } } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { - var (result, messageGenerator) = _validator.Validate(value); + var (result, message) = _validator.Validate(value); if (result) { return ValidationResult.Success; } else { - var localizerFactory = validationContext.GetRequiredService(); - return new ValidationResult(messageGenerator(localizerFactory)); + return new ValidationResult(message); } } } diff --git a/Timeline/Program.cs b/Timeline/Program.cs index 4a098adf..b44aafde 100644 --- a/Timeline/Program.cs +++ b/Timeline/Program.cs @@ -5,6 +5,8 @@ using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; using System.Resources; +[assembly: NeutralResourcesLanguage("en")] + namespace Timeline { public static class Program diff --git a/Timeline/Resources/Controllers/Testing/TestingI18nController.Designer.cs b/Timeline/Resources/Controllers/Testing/TestingI18nController.Designer.cs new file mode 100644 index 00000000..e015c5fc --- /dev/null +++ b/Timeline/Resources/Controllers/Testing/TestingI18nController.Designer.cs @@ -0,0 +1,72 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Timeline.Resources.Controllers.Testing { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class TestingI18nController { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal TestingI18nController() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Timeline.Resources.Controllers.Testing.TestingI18nController", typeof(TestingI18nController).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to English test string.. + /// + internal static string TestString { + get { + return ResourceManager.GetString("TestString", resourceCulture); + } + } + } +} diff --git a/Timeline/Resources/Controllers/Testing/TestingI18nController.resx b/Timeline/Resources/Controllers/Testing/TestingI18nController.resx new file mode 100644 index 00000000..57dfd5b9 --- /dev/null +++ b/Timeline/Resources/Controllers/Testing/TestingI18nController.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + English test string. + + \ No newline at end of file diff --git a/Timeline/Resources/Controllers/Testing/TestingI18nController.zh.resx b/Timeline/Resources/Controllers/Testing/TestingI18nController.zh.resx new file mode 100644 index 00000000..6931cdf6 --- /dev/null +++ b/Timeline/Resources/Controllers/Testing/TestingI18nController.zh.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 中文测试字符串。 + + \ No newline at end of file diff --git a/Timeline/Resources/Controllers/TokenController.Designer.cs b/Timeline/Resources/Controllers/TokenController.Designer.cs index a7c2864b..22e6a8be 100644 --- a/Timeline/Resources/Controllers/TokenController.Designer.cs +++ b/Timeline/Resources/Controllers/TokenController.Designer.cs @@ -60,6 +60,51 @@ namespace Timeline.Resources.Controllers { } } + /// + /// Looks up a localized string similar to Username or password is invalid.. + /// + internal static string ErrorBadCredential { + get { + return ResourceManager.GetString("ErrorBadCredential", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The token is of bad format. It might not be created by the server.. + /// + internal static string ErrorVerifyBadFormat { + get { + return ResourceManager.GetString("ErrorVerifyBadFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The token is expired.. + /// + internal static string ErrorVerifyExpire { + get { + return ResourceManager.GetString("ErrorVerifyExpire", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Token has an old version. User might have update some info.. + /// + internal static string ErrorVerifyOldVersion { + get { + return ResourceManager.GetString("ErrorVerifyOldVersion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User does not exist. Administrator might have deleted this user.. + /// + internal static string ErrorVerifyUserNotExist { + get { + return ResourceManager.GetString("ErrorVerifyUserNotExist", resourceCulture); + } + } + /// /// Looks up a localized string similar to The password is wrong.. /// diff --git a/Timeline/Resources/Controllers/TokenController.en.resx b/Timeline/Resources/Controllers/TokenController.en.resx deleted file mode 100644 index 4a3d94f9..00000000 --- a/Timeline/Resources/Controllers/TokenController.en.resx +++ /dev/null @@ -1,135 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Username or password is invalid. - - - The token is of bad format. It might not be created by the server. - - - The token is expired. - - - Token has an old version. User might have update some info. - - - User does not exist. Administrator might have deleted this user. - - \ No newline at end of file diff --git a/Timeline/Resources/Controllers/TokenController.resx b/Timeline/Resources/Controllers/TokenController.resx index 683d6cc9..42e1ff92 100644 --- a/Timeline/Resources/Controllers/TokenController.resx +++ b/Timeline/Resources/Controllers/TokenController.resx @@ -117,6 +117,21 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Username or password is invalid. + + + The token is of bad format. It might not be created by the server. + + + The token is expired. + + + Token has an old version. User might have update some info. + + + User does not exist. Administrator might have deleted this user. + The password is wrong. diff --git a/Timeline/Resources/Controllers/UserAvatarController.Designer.cs b/Timeline/Resources/Controllers/UserAvatarController.Designer.cs index e6eeb1e8..1dacb19f 100644 --- a/Timeline/Resources/Controllers/UserAvatarController.Designer.cs +++ b/Timeline/Resources/Controllers/UserAvatarController.Designer.cs @@ -60,6 +60,78 @@ namespace Timeline.Resources.Controllers { } } + /// + /// Looks up a localized string similar to Normal user can't delete other's avatar.. + /// + internal static string ErrorDeleteForbid { + get { + return ResourceManager.GetString("ErrorDeleteForbid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User does not exist.. + /// + internal static string ErrorDeleteUserNotExist { + get { + return ResourceManager.GetString("ErrorDeleteUserNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User does not exist.. + /// + internal static string ErrorGetUserNotExist { + get { + return ResourceManager.GetString("ErrorGetUserNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image is not a square.. + /// + internal static string ErrorPutBadFormatBadSize { + get { + return ResourceManager.GetString("ErrorPutBadFormatBadSize", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Decoding image failed.. + /// + internal static string ErrorPutBadFormatCantDecode { + get { + return ResourceManager.GetString("ErrorPutBadFormatCantDecode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Image format is not the one in header.. + /// + internal static string ErrorPutBadFormatUnmatchedFormat { + get { + return ResourceManager.GetString("ErrorPutBadFormatUnmatchedFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Normal user can't change other's avatar.. + /// + internal static string ErrorPutForbid { + get { + return ResourceManager.GetString("ErrorPutForbid", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to User does not exist.. + /// + internal static string ErrorPutUserNotExist { + get { + return ResourceManager.GetString("ErrorPutUserNotExist", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unknown AvatarDataException.ErrorReason value.. /// diff --git a/Timeline/Resources/Controllers/UserAvatarController.en.resx b/Timeline/Resources/Controllers/UserAvatarController.en.resx deleted file mode 100644 index cf92ae6d..00000000 --- a/Timeline/Resources/Controllers/UserAvatarController.en.resx +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Normal user can't delete other's avatar. - - - User does not exist. - - - User does not exist. - - - Image is not a square. - - - Decoding image failed. - - - Image format is not the one in header. - - - Normal user can't change other's avatar. - - - User does not exist. - - \ No newline at end of file diff --git a/Timeline/Resources/Controllers/UserAvatarController.resx b/Timeline/Resources/Controllers/UserAvatarController.resx index 58860c83..3f444b04 100644 --- a/Timeline/Resources/Controllers/UserAvatarController.resx +++ b/Timeline/Resources/Controllers/UserAvatarController.resx @@ -117,6 +117,30 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Normal user can't delete other's avatar. + + + User does not exist. + + + User does not exist. + + + Image is not a square. + + + Decoding image failed. + + + Image format is not the one in header. + + + Normal user can't change other's avatar. + + + User does not exist. + Unknown AvatarDataException.ErrorReason value. diff --git a/Timeline/Resources/Controllers/UserController.Designer.cs b/Timeline/Resources/Controllers/UserController.Designer.cs index df9cab4c..0c9ac0d7 100644 --- a/Timeline/Resources/Controllers/UserController.Designer.cs +++ b/Timeline/Resources/Controllers/UserController.Designer.cs @@ -60,6 +60,60 @@ namespace Timeline.Resources.Controllers { } } + /// + /// Looks up a localized string similar to Old password is wrong.. + /// + internal static string ErrorChangePasswordBadPassword { + get { + return ResourceManager.GetString("ErrorChangePasswordBadPassword", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The new username {0} already exists.. + /// + internal static string ErrorChangeUsernameAlreadyExist { + get { + return ResourceManager.GetString("ErrorChangeUsernameAlreadyExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The old username {0} does not exist.. + /// + internal static string ErrorChangeUsernameNotExist { + get { + return ResourceManager.GetString("ErrorChangeUsernameNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The user does not exist.. + /// + internal static string ErrorGetUserNotExist { + get { + return ResourceManager.GetString("ErrorGetUserNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Can't patch a user that does not exist.. + /// + internal static string ErrorPatchUserNotExist { + get { + return ResourceManager.GetString("ErrorPatchUserNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Username is of bad format.. + /// + internal static string ErrorPutBadUsername { + get { + return ResourceManager.GetString("ErrorPutBadUsername", resourceCulture); + } + } + /// /// Looks up a localized string similar to Attempt to change password with wrong old password failed.. /// diff --git a/Timeline/Resources/Controllers/UserController.en.resx b/Timeline/Resources/Controllers/UserController.en.resx deleted file mode 100644 index 0bd1dfe3..00000000 --- a/Timeline/Resources/Controllers/UserController.en.resx +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Old password is wrong. - - - The new username {0} already exists. - - - The old username {0} does not exist. - - - The user does not exist. - - - Can't patch a user that does not exist. - - - Username is of bad format. - - \ No newline at end of file diff --git a/Timeline/Resources/Controllers/UserController.resx b/Timeline/Resources/Controllers/UserController.resx index d720d1c1..50aa13d6 100644 --- a/Timeline/Resources/Controllers/UserController.resx +++ b/Timeline/Resources/Controllers/UserController.resx @@ -117,6 +117,24 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Old password is wrong. + + + The new username {0} already exists. + + + The old username {0} does not exist. + + + The user does not exist. + + + Can't patch a user that does not exist. + + + Username is of bad format. + Attempt to change password with wrong old password failed. diff --git a/Timeline/Resources/Models/Http/Common.Designer.cs b/Timeline/Resources/Models/Http/Common.Designer.cs new file mode 100644 index 00000000..2df1e447 --- /dev/null +++ b/Timeline/Resources/Models/Http/Common.Designer.cs @@ -0,0 +1,162 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Timeline.Resources.Models.Http { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Common { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Common() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Timeline.Resources.Models.Http.Common", typeof(Common).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Body is too big. It can't be bigger than {0}.. + /// + internal static string MessageContentTooBig { + get { + return ResourceManager.GetString("MessageContentTooBig", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Actual body length is bigger than it in header.. + /// + internal static string MessageContentUnmatchedLengthBigger { + get { + return ResourceManager.GetString("MessageContentUnmatchedLengthBigger", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Actual body length is smaller than it in header.. + /// + internal static string MessageContentUnmatchedLengthSmaller { + get { + return ResourceManager.GetString("MessageContentUnmatchedLengthSmaller", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An existent item is deleted.. + /// + internal static string MessageDeleteDelete { + get { + return ResourceManager.GetString("MessageDeleteDelete", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The item does not exist, so nothing is changed.. + /// + internal static string MessageDeleteNotExist { + get { + return ResourceManager.GetString("MessageDeleteNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Header If-Non-Match is of bad format.. + /// + internal static string MessageHeaderBadIfNonMatch { + get { + return ResourceManager.GetString("MessageHeaderBadIfNonMatch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Header Content-Length is missing or of bad format.. + /// + internal static string MessageHeaderMissingContentLength { + get { + return ResourceManager.GetString("MessageHeaderMissingContentLength", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Header Content-Type is required.. + /// + internal static string MessageHeaderMissingContentType { + get { + return ResourceManager.GetString("MessageHeaderMissingContentType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Header Content-Length must not be 0.. + /// + internal static string MessageHeaderZeroContentLength { + get { + return ResourceManager.GetString("MessageHeaderZeroContentLength", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to A new item is created.. + /// + internal static string MessagePutCreate { + get { + return ResourceManager.GetString("MessagePutCreate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to An existent item is modified.. + /// + internal static string MessagePutModify { + get { + return ResourceManager.GetString("MessagePutModify", resourceCulture); + } + } + } +} diff --git a/Timeline/Resources/Models/Http/Common.en.resx b/Timeline/Resources/Models/Http/Common.en.resx deleted file mode 100644 index 10407d76..00000000 --- a/Timeline/Resources/Models/Http/Common.en.resx +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Body is too big. It can't be bigger than {0}. - - - Actual body length is bigger than it in header. - - - Actual body length is smaller than it in header. - - - An existent item is deleted. - - - The item does not exist, so nothing is changed. - - - Header If-Non-Match is of bad format. - - - Header Content-Length is missing or of bad format. - - - Header Content-Type is required. - - - Header Content-Length must not be 0. - - - A new item is created. - - - An existent item is modified. - - \ No newline at end of file diff --git a/Timeline/Resources/Models/Http/Common.resx b/Timeline/Resources/Models/Http/Common.resx new file mode 100644 index 00000000..433c341c --- /dev/null +++ b/Timeline/Resources/Models/Http/Common.resx @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Body is too big. It can't be bigger than {0}. + + + Actual body length is bigger than it in header. + + + Actual body length is smaller than it in header. + + + An existent item is deleted. + + + The item does not exist, so nothing is changed. + + + Header If-Non-Match is of bad format. + + + Header Content-Length is missing or of bad format. + + + Header Content-Type is required. + + + Header Content-Length must not be 0. + + + A new item is created. + + + An existent item is modified. + + \ No newline at end of file diff --git a/Timeline/Resources/Models/Http/Common.zh.resx b/Timeline/Resources/Models/Http/Common.zh.resx index 528dc7ab..cbdd6fb9 100644 --- a/Timeline/Resources/Models/Http/Common.zh.resx +++ b/Timeline/Resources/Models/Http/Common.zh.resx @@ -117,37 +117,37 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + 请求体太大。它不能超过{0}. - + 实际的请求体长度比头中指示的大。 - + 实际的请求体长度比头中指示的小。 - + 删除了一个项目。 - + 要删除的项目不存在,什么都没有修改。 - + 头If-Non-Match格式不对。 - + 头Content-Length缺失或者格式不对。 - + 缺少必需的头Content-Type。 - + 头Content-Length不能为0。 - + 创建了一个新项目。 - + 修改了一个已存在的项目。 \ No newline at end of file diff --git a/Timeline/Resources/Models/Validation/UsernameValidator.Designer.cs b/Timeline/Resources/Models/Validation/UsernameValidator.Designer.cs index a4c35326..ac925504 100644 --- a/Timeline/Resources/Models/Validation/UsernameValidator.Designer.cs +++ b/Timeline/Resources/Models/Validation/UsernameValidator.Designer.cs @@ -63,27 +63,27 @@ namespace Timeline.Resources.Models.Validation { /// /// Looks up a localized string similar to An empty string is not allowed.. /// - internal static string InvariantValidationMessageEmptyString { + internal static string MessageEmptyString { get { - return ResourceManager.GetString("InvariantValidationMessageEmptyString", resourceCulture); + return ResourceManager.GetString("MessageEmptyString", resourceCulture); } } /// - /// Looks up a localized string similar to Invalid character, only alphabet, digit, underscore and hyphen are allowed. . + /// Looks up a localized string similar to Invalid character, only alphabet, digit, underscore and hyphen are allowed.. /// - internal static string InvariantValidationMessageInvalidChar { + internal static string MessageInvalidChar { get { - return ResourceManager.GetString("InvariantValidationMessageInvalidChar", resourceCulture); + return ResourceManager.GetString("MessageInvalidChar", resourceCulture); } } /// /// Looks up a localized string similar to Too long, more than 26 characters is not premitted.. /// - internal static string InvariantValidationMessageTooLong { + internal static string MessageTooLong { get { - return ResourceManager.GetString("InvariantValidationMessageTooLong", resourceCulture); + return ResourceManager.GetString("MessageTooLong", resourceCulture); } } } diff --git a/Timeline/Resources/Models/Validation/UsernameValidator.en.resx b/Timeline/Resources/Models/Validation/UsernameValidator.en.resx deleted file mode 100644 index 9171b856..00000000 --- a/Timeline/Resources/Models/Validation/UsernameValidator.en.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - An empty string is not allowed. - - - Invalid character, only alphabet, digit, underscore and hyphen are allowed. - - - Too long, more than 26 characters is not premitted. - - \ No newline at end of file diff --git a/Timeline/Resources/Models/Validation/UsernameValidator.resx b/Timeline/Resources/Models/Validation/UsernameValidator.resx index 80cae2d5..08a814d0 100644 --- a/Timeline/Resources/Models/Validation/UsernameValidator.resx +++ b/Timeline/Resources/Models/Validation/UsernameValidator.resx @@ -117,13 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + An empty string is not allowed. - - Invalid character, only alphabet, digit, underscore and hyphen are allowed. + + Invalid character, only alphabet, digit, underscore and hyphen are allowed. - + Too long, more than 26 characters is not premitted. \ No newline at end of file diff --git a/Timeline/Resources/Models/Validation/UsernameValidator.zh.resx b/Timeline/Resources/Models/Validation/UsernameValidator.zh.resx index 1c8a936c..89d519b0 100644 --- a/Timeline/Resources/Models/Validation/UsernameValidator.zh.resx +++ b/Timeline/Resources/Models/Validation/UsernameValidator.zh.resx @@ -117,13 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + 空字符串是不允许的。 - + 无效的字符,只能使用字母、数字、下划线和连字符。 - + 太长了,不能大于26个字符。 \ No newline at end of file diff --git a/Timeline/Resources/Models/Validation/Validator.Designer.cs b/Timeline/Resources/Models/Validation/Validator.Designer.cs index 4cbc13de..74d4c169 100644 --- a/Timeline/Resources/Models/Validation/Validator.Designer.cs +++ b/Timeline/Resources/Models/Validation/Validator.Designer.cs @@ -61,47 +61,47 @@ namespace Timeline.Resources.Models.Validation { } /// - /// Looks up a localized string similar to Value is not of type {0}.. + /// Looks up a localized string similar to Failed to create a validator instance from default constructor. See inner exception.. /// - internal static string InvariantValidatorMessageBadType { + internal static string ValidateWithAttributeExceptionCreateFail { get { - return ResourceManager.GetString("InvariantValidatorMessageBadType", resourceCulture); + return ResourceManager.GetString("ValidateWithAttributeExceptionCreateFail", resourceCulture); } } /// - /// Looks up a localized string similar to Value can't be null.. + /// Looks up a localized string similar to Given type is not assignable to IValidator.. /// - internal static string InvariantValidatorMessageNull { + internal static string ValidateWithAttributeExceptionNotValidator { get { - return ResourceManager.GetString("InvariantValidatorMessageNull", resourceCulture); + return ResourceManager.GetString("ValidateWithAttributeExceptionNotValidator", resourceCulture); } } /// - /// Looks up a localized string similar to Validation succeeded.. + /// Looks up a localized string similar to Value is not of type {0}.. /// - internal static string InvariantValidatorMessageSuccess { + internal static string ValidatorMessageBadType { get { - return ResourceManager.GetString("InvariantValidatorMessageSuccess", resourceCulture); + return ResourceManager.GetString("ValidatorMessageBadType", resourceCulture); } } /// - /// Looks up a localized string similar to Failed to create a validator instance from default constructor. See inner exception.. + /// Looks up a localized string similar to Value can't be null.. /// - internal static string ValidateWithAttributeCreateFail { + internal static string ValidatorMessageNull { get { - return ResourceManager.GetString("ValidateWithAttributeCreateFail", resourceCulture); + return ResourceManager.GetString("ValidatorMessageNull", resourceCulture); } } /// - /// Looks up a localized string similar to Given type is not assignable to IValidator.. + /// Looks up a localized string similar to Validation succeeded.. /// - internal static string ValidateWithAttributeNotValidator { + internal static string ValidatorMessageSuccess { get { - return ResourceManager.GetString("ValidateWithAttributeNotValidator", resourceCulture); + return ResourceManager.GetString("ValidatorMessageSuccess", resourceCulture); } } } diff --git a/Timeline/Resources/Models/Validation/Validator.en.resx b/Timeline/Resources/Models/Validation/Validator.en.resx deleted file mode 100644 index 8d2fbede..00000000 --- a/Timeline/Resources/Models/Validation/Validator.en.resx +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Value is not of type {0}. - - - Value can't be null. - - - Validation succeeded. - - \ No newline at end of file diff --git a/Timeline/Resources/Models/Validation/Validator.resx b/Timeline/Resources/Models/Validation/Validator.resx index 0e8f53a6..8317e3eb 100644 --- a/Timeline/Resources/Models/Validation/Validator.resx +++ b/Timeline/Resources/Models/Validation/Validator.resx @@ -117,19 +117,19 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + + Failed to create a validator instance from default constructor. See inner exception. + + + Given type is not assignable to IValidator. + + Value is not of type {0}. - + Value can't be null. - + Validation succeeded. - - Failed to create a validator instance from default constructor. See inner exception. - - - Given type is not assignable to IValidator. - \ No newline at end of file diff --git a/Timeline/Resources/Services/UserAvatarService.Designer.cs b/Timeline/Resources/Services/UserAvatarService.Designer.cs index 6ee6fef9..c72d4215 100644 --- a/Timeline/Resources/Services/UserAvatarService.Designer.cs +++ b/Timeline/Resources/Services/UserAvatarService.Designer.cs @@ -63,27 +63,27 @@ namespace Timeline.Resources.Services { /// /// Looks up a localized string similar to Data of avatar is null.. /// - internal static string ArgumentAvatarDataNull { + internal static string ExceptionAvatarDataNull { get { - return ResourceManager.GetString("ArgumentAvatarDataNull", resourceCulture); + return ResourceManager.GetString("ExceptionAvatarDataNull", resourceCulture); } } /// /// Looks up a localized string similar to Type of avatar is null or empty.. /// - internal static string ArgumentAvatarTypeNullOrEmpty { + internal static string ExceptionAvatarTypeNullOrEmpty { get { - return ResourceManager.GetString("ArgumentAvatarTypeNullOrEmpty", resourceCulture); + return ResourceManager.GetString("ExceptionAvatarTypeNullOrEmpty", resourceCulture); } } /// /// Looks up a localized string similar to Database corupted! One of type and data of a avatar is null but the other is not.. /// - internal static string DatabaseCorruptedDataAndTypeNotSame { + internal static string ExceptionDatabaseCorruptedDataAndTypeNotSame { get { - return ResourceManager.GetString("DatabaseCorruptedDataAndTypeNotSame", resourceCulture); + return ResourceManager.GetString("ExceptionDatabaseCorruptedDataAndTypeNotSame", resourceCulture); } } diff --git a/Timeline/Resources/Services/UserAvatarService.resx b/Timeline/Resources/Services/UserAvatarService.resx index 3269bf13..da9d7203 100644 --- a/Timeline/Resources/Services/UserAvatarService.resx +++ b/Timeline/Resources/Services/UserAvatarService.resx @@ -117,13 +117,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - + Data of avatar is null. - + Type of avatar is null or empty. - + Database corupted! One of type and data of a avatar is null but the other is not. diff --git a/Timeline/Services/DatabaseExtensions.cs b/Timeline/Services/DatabaseExtensions.cs index 62b22f00..8cbc8fef 100644 --- a/Timeline/Services/DatabaseExtensions.cs +++ b/Timeline/Services/DatabaseExtensions.cs @@ -1,6 +1,5 @@ using Microsoft.EntityFrameworkCore; using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Timeline.Entities; @@ -22,9 +21,9 @@ namespace Timeline.Services { if (username == null) throw new ArgumentNullException(nameof(username)); - var (result, messageGenerator) = validator.Validate(username); + var (result, message) = validator.Validate(username); if (!result) - throw new UsernameBadFormatException(username, messageGenerator(null)); + throw new UsernameBadFormatException(username, message); var userId = await userDbSet.Where(u => u.Name == username).Select(u => u.Id).SingleOrDefaultAsync(); if (userId == 0) diff --git a/Timeline/Services/UserAvatarService.cs b/Timeline/Services/UserAvatarService.cs index ff80003c..2afe9093 100644 --- a/Timeline/Services/UserAvatarService.cs +++ b/Timeline/Services/UserAvatarService.cs @@ -219,7 +219,7 @@ namespace Timeline.Services { if (!LanguageHelper.AreSame(avatarEntity.Data == null, avatarEntity.Type == null)) { - var message = Resources.Services.UserAvatarService.DatabaseCorruptedDataAndTypeNotSame; + var message = Resources.Services.UserAvatarService.ExceptionDatabaseCorruptedDataAndTypeNotSame; _logger.LogCritical(message); throw new DatabaseCorruptedException(message); } @@ -248,9 +248,9 @@ namespace Timeline.Services if (avatar != null) { if (avatar.Data == null) - throw new ArgumentException(Resources.Services.UserAvatarService.ArgumentAvatarDataNull, nameof(avatar)); + throw new ArgumentException(Resources.Services.UserAvatarService.ExceptionAvatarDataNull, nameof(avatar)); if (string.IsNullOrEmpty(avatar.Type)) - throw new ArgumentException(Resources.Services.UserAvatarService.ArgumentAvatarTypeNullOrEmpty, nameof(avatar)); + throw new ArgumentException(Resources.Services.UserAvatarService.ExceptionAvatarTypeNullOrEmpty, nameof(avatar)); } var userId = await DatabaseExtensions.CheckAndGetUser(_database.Users, _usernameValidator, username); diff --git a/Timeline/Services/UserService.cs b/Timeline/Services/UserService.cs index 8f354fc7..4012539f 100644 --- a/Timeline/Services/UserService.cs +++ b/Timeline/Services/UserService.cs @@ -164,15 +164,15 @@ namespace Timeline.Services _logger.LogInformation(Log.Format(Resources.Services.UserService.LogCacheRemove, ("Key", key))); } - private void CheckUsernameFormat(string username, string? message = null) + private void CheckUsernameFormat(string username, string? additionalMessage = null) { - var (result, messageGenerator) = _usernameValidator.Validate(username); + var (result, message) = _usernameValidator.Validate(username); if (!result) { - if (message == null) - throw new UsernameBadFormatException(username, messageGenerator(null)); + if (additionalMessage == null) + throw new UsernameBadFormatException(username, message); else - throw new UsernameBadFormatException(username, message + messageGenerator(null)); + throw new UsernameBadFormatException(username, additionalMessage + message); } } diff --git a/Timeline/Timeline.csproj b/Timeline/Timeline.csproj index 519a802d..b989cd3b 100644 --- a/Timeline/Timeline.csproj +++ b/Timeline/Timeline.csproj @@ -44,6 +44,11 @@ True Common.resx + + True + True + TestingI18nController.resx + True True @@ -59,6 +64,11 @@ True UserController.resx + + True + True + Common.resx + True True @@ -95,6 +105,10 @@ ResXFileCodeGenerator Common.Designer.cs + + ResXFileCodeGenerator + TestingI18nController.Designer.cs + Designer ResXFileCodeGenerator @@ -104,9 +118,6 @@ Designer - - - ResXFileCodeGenerator UserAvatarController.Designer.cs @@ -115,13 +126,14 @@ ResXFileCodeGenerator UserController.Designer.cs + + ResXFileCodeGenerator + Common.Designer.cs + ResXFileCodeGenerator UsernameValidator.Designer.cs - - - ResXFileCodeGenerator Validator.Designer.cs -- cgit v1.2.3