├── .appveyor.yml
├── .gitattributes
├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── .travis.yml
├── .vsts-pipelines
└── builds
│ ├── ci-internal.yml
│ └── ci-public.yml
├── CONTRIBUTING.md
├── Directory.Build.props
├── Directory.Build.targets
├── LICENSE.txt
├── Localization.sln
├── NuGet.config
├── NuGetPackageVerifier.json
├── README.md
├── build.cmd
├── build.sh
├── build
├── Key.snk
├── dependencies.props
├── repo.props
└── sources.props
├── korebuild-lock.txt
├── korebuild.json
├── run.cmd
├── run.ps1
├── run.sh
├── samples
└── LocalizationSample
│ ├── LocalizationSample.csproj
│ ├── My
│ └── Resources
│ │ ├── Startup.es-ES.resx
│ │ ├── Startup.fr-FR.resx
│ │ ├── Startup.ja-JP.resx
│ │ ├── Startup.zh-CN.resx
│ │ └── Startup.zh.resx
│ └── Startup.cs
├── src
├── Directory.Build.props
├── Microsoft.AspNetCore.Localization.Routing
│ ├── Microsoft.AspNetCore.Localization.Routing.csproj
│ ├── RouteDataRequestCultureProvider.cs
│ └── baseline.netcore.json
├── Microsoft.AspNetCore.Localization
│ ├── AcceptLanguageHeaderRequestCultureProvider.cs
│ ├── ApplicationBuilderExtensions.cs
│ ├── CookieRequestCultureProvider.cs
│ ├── CustomRequestCultureProvider.cs
│ ├── IRequestCultureFeature.cs
│ ├── IRequestCultureProvider.cs
│ ├── Internal
│ │ └── RequestCultureProviderLoggerExtensions.cs
│ ├── Microsoft.AspNetCore.Localization.csproj
│ ├── Properties
│ │ └── Resources.Designer.cs
│ ├── ProviderCultureResult.cs
│ ├── QueryStringRequestCultureProvider.cs
│ ├── RequestCulture.cs
│ ├── RequestCultureFeature.cs
│ ├── RequestCultureProvider.cs
│ ├── RequestLocalizationMiddleware.cs
│ ├── RequestLocalizationOptions.cs
│ ├── RequestLocalizationOptionsExtensions.cs
│ ├── Resources.resx
│ └── baseline.netcore.json
├── Microsoft.Extensions.Localization.Abstractions
│ ├── IStringLocalizer.cs
│ ├── IStringLocalizerFactory.cs
│ ├── IStringLocalizerOfT.cs
│ ├── LocalizedString.cs
│ ├── Microsoft.Extensions.Localization.Abstractions.csproj
│ ├── StringLocalizerExtensions.cs
│ ├── StringLocalizerOfT.cs
│ └── baseline.netcore.json
└── Microsoft.Extensions.Localization
│ ├── IResourceNamesCache.cs
│ ├── Internal
│ ├── AssemblyWrapper.cs
│ ├── IResourceStringProvider.cs
│ ├── ResourceManagerStringLocalizerLoggerExtensions.cs
│ └── ResourceManagerStringProvider.cs
│ ├── LocalizationOptions.cs
│ ├── LocalizationServiceCollectionExtensions.cs
│ ├── Microsoft.Extensions.Localization.csproj
│ ├── Properties
│ ├── AssemblyInfo.cs
│ └── Resources.Designer.cs
│ ├── ResourceLocationAttribute.cs
│ ├── ResourceManagerStringLocalizer.cs
│ ├── ResourceManagerStringLocalizerFactory.cs
│ ├── ResourceManagerWithCultureStringLocalizer.cs
│ ├── ResourceNamesCache.cs
│ ├── Resources.resx
│ ├── RootNamespaceAttribute.cs
│ └── baseline.netcore.json
├── test
├── Directory.Build.props
├── LocalizationWebsite
│ ├── LocalizationWebsite.csproj
│ ├── Models
│ │ ├── Customer.cs
│ │ └── Customer.fr-FR.resx
│ ├── Program.cs
│ ├── Resources
│ │ ├── Models.Customer.fr-FR.resx
│ │ ├── StartupCustomCulturePreserved.en-US.resx
│ │ ├── StartupResourcesInFolder.fr-FR.resx
│ │ └── Test.fr-FR.resx
│ ├── StartupBuilderAPIs.cs
│ ├── StartupCustomCulturePreserved.cs
│ ├── StartupGetAllStrings.cs
│ ├── StartupResourcesAtRootFolder.cs
│ ├── StartupResourcesAtRootFolder.fr-FR.resx
│ ├── StartupResourcesInClassLibrary.cs
│ ├── StartupResourcesInFolder.cs
│ └── Test.fr-FR.resx
├── Microsoft.AspNetCore.Localization.FunctionalTests
│ ├── LocalizationSampleTest.cs
│ ├── LocalizationTest.cs
│ └── Microsoft.AspNetCore.Localization.FunctionalTests.csproj
├── Microsoft.AspNetCore.Localization.Routing.Tests
│ ├── Microsoft.AspNetCore.Localization.Routing.Tests.csproj
│ └── RouteDataRequestCultureProviderTest.cs
├── Microsoft.AspNetCore.Localization.Tests
│ ├── AcceptLanguageHeaderRequestCultureProviderTest.cs
│ ├── CookieRequestCultureProviderTest.cs
│ ├── CustomRequestCultureProviderTest.cs
│ ├── Microsoft.AspNetCore.Localization.Tests.csproj
│ ├── QueryStringRequestCultureProviderTest.cs
│ ├── RequestLocalizationOptionsExtensionsTest.cs
│ └── RequestLocalizationOptionsTest.cs
├── Microsoft.Extensions.Localization.Tests
│ ├── LocalizationServiceCollectionExtensionsTest.cs
│ ├── Microsoft.Extensions.Localization.Tests.csproj
│ ├── ResourceManagerStringLocalizerFactoryTest.cs
│ └── ResourceManagerStringLocalizerTest.cs
├── ResourcesClassLibraryNoAttribute
│ ├── Model.cs
│ ├── Resources
│ │ └── Model.resx
│ └── ResourcesClassLibraryNoAttribute.csproj
└── ResourcesClassLibraryWithAttribute
│ ├── AssemblyInfo.cs
│ ├── Model.cs
│ ├── ResourceFolder
│ └── Model.resx
│ └── ResourcesClassLibraryWithAttribute.csproj
└── version.props
/.appveyor.yml:
--------------------------------------------------------------------------------
1 | init:
2 | - git config --global core.autocrlf true
3 | branches:
4 | only:
5 | - master
6 | - /^release\/.*$/
7 | - /^(.*\/)?ci-.*$/
8 | build_script:
9 | - ps: .\run.ps1 default-build
10 | clone_depth: 1
11 | environment:
12 | global:
13 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
14 | DOTNET_CLI_TELEMETRY_OPTOUT: 1
15 | test: 'off'
16 | deploy: 'off'
17 | os: Visual Studio 2017
18 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.doc diff=astextplain
2 | *.DOC diff=astextplain
3 | *.docx diff=astextplain
4 | *.DOCX diff=astextplain
5 | *.dot diff=astextplain
6 | *.DOT diff=astextplain
7 | *.pdf diff=astextplain
8 | *.PDF diff=astextplain
9 | *.rtf diff=astextplain
10 | *.RTF diff=astextplain
11 |
12 | *.jpg binary
13 | *.png binary
14 | *.gif binary
15 |
16 | *.cs text=auto diff=csharp
17 | *.vb text=auto
18 | *.resx text=auto
19 | *.c text=auto
20 | *.cpp text=auto
21 | *.cxx text=auto
22 | *.h text=auto
23 | *.hxx text=auto
24 | *.py text=auto
25 | *.rb text=auto
26 | *.java text=auto
27 | *.html text=auto
28 | *.htm text=auto
29 | *.css text=auto
30 | *.scss text=auto
31 | *.sass text=auto
32 | *.less text=auto
33 | *.js text=auto
34 | *.lisp text=auto
35 | *.clj text=auto
36 | *.sql text=auto
37 | *.php text=auto
38 | *.lua text=auto
39 | *.m text=auto
40 | *.asm text=auto
41 | *.erl text=auto
42 | *.fs text=auto
43 | *.fsx text=auto
44 | *.hs text=auto
45 |
46 | *.csproj text=auto
47 | *.vbproj text=auto
48 | *.fsproj text=auto
49 | *.dbproj text=auto
50 | *.sln text=auto eol=crlf
51 |
52 | *.sh eol=lf
53 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | THIS ISSUE TRACKER IS CLOSED - please log new issues here: https://github.com/aspnet/Home/issues
2 |
3 | For information about this change, see https://github.com/aspnet/Announcements/issues/283
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | [Oo]bj/
2 | [Bb]in/
3 | TestResults/
4 | .nuget/
5 | .build/
6 | .testPublish/
7 | *.sln.ide/
8 | _ReSharper.*/
9 | packages/
10 | artifacts/
11 | PublishProfiles/
12 | .vs/
13 | debugSettings.json
14 | project.lock.json
15 | *.user
16 | *.suo
17 | *.cache
18 | *.docstates
19 | _ReSharper.*
20 | nuget.exe
21 | *net45.csproj
22 | *net451.csproj
23 | *k10.csproj
24 | *.psess
25 | *.vsp
26 | *.pidb
27 | *.userprefs
28 | *DS_Store
29 | *.ncrunchsolution
30 | *.*sdf
31 | *.ipch
32 | *.sln.ide
33 | *launchSettings.json
34 | **/Resources/*.Designer.cs
35 | .vscode/
36 | global.json
37 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: csharp
2 | sudo: false
3 | dist: trusty
4 | env:
5 | global:
6 | - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
7 | - DOTNET_CLI_TELEMETRY_OPTOUT: 1
8 | mono: none
9 | os:
10 | - linux
11 | - osx
12 | osx_image: xcode8.2
13 | addons:
14 | apt:
15 | packages:
16 | - libunwind8
17 | branches:
18 | only:
19 | - master
20 | - /^release\/.*$/
21 | - /^(.*\/)?ci-.*$/
22 | before_install:
23 | - if test "$TRAVIS_OS_NAME" == "osx"; then brew update; brew install openssl; ln -s
24 | /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/; ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib
25 | /usr/local/lib/; fi
26 | script:
27 | - ./build.sh
28 |
--------------------------------------------------------------------------------
/.vsts-pipelines/builds/ci-internal.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | - master
3 | - release/*
4 |
5 | resources:
6 | repositories:
7 | - repository: buildtools
8 | type: git
9 | name: aspnet-BuildTools
10 | ref: refs/heads/master
11 |
12 | phases:
13 | - template: .vsts-pipelines/templates/project-ci.yml@buildtools
14 |
--------------------------------------------------------------------------------
/.vsts-pipelines/builds/ci-public.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | - master
3 | - release/*
4 |
5 | # See https://github.com/aspnet/BuildTools
6 | resources:
7 | repositories:
8 | - repository: buildtools
9 | type: github
10 | endpoint: DotNet-Bot GitHub Connection
11 | name: aspnet/BuildTools
12 | ref: refs/heads/master
13 |
14 | phases:
15 | - template: .vsts-pipelines/templates/project-ci.yml@buildtools
16 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ======
3 |
4 | Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/master/CONTRIBUTING.md) in the Home repo.
5 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | https://github.com/aspnet/Localization
12 | git
13 | $(MSBuildThisFileDirectory)
14 | $(MSBuildThisFileDirectory)build\Key.snk
15 | true
16 | true
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(MicrosoftNETCoreAppPackageVersion)
4 | $(NETStandardLibrary20PackageVersion)
5 |
6 |
7 |
--------------------------------------------------------------------------------
/NuGet.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/NuGetPackageVerifier.json:
--------------------------------------------------------------------------------
1 | {
2 | "Default": {
3 | "rules": [
4 | "DefaultCompositeRule"
5 | ]
6 | }
7 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Localization [Archived]
2 | =======================
3 |
4 | **This GitHub project has been archived.** Ongoing development on this project can be found in .
5 |
6 | Localization abstractions and implementations for ASP.NET Core applications.
7 |
8 | This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [AspNetCore](https://github.com/aspnet/AspNetCore) repo.
9 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 | PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' default-build %*; exit $LASTEXITCODE"
3 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | set -euo pipefail
4 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
5 |
6 | # Call "sync" between "chmod" and execution to prevent "text file busy" error in Docker (aufs)
7 | chmod +x "$DIR/run.sh"; sync
8 | "$DIR/run.sh" default-build "$@"
9 |
--------------------------------------------------------------------------------
/build/Key.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aspnet/Localization/c283dfb56cd9620edfae644f1229d8231e9cfc0e/build/Key.snk
--------------------------------------------------------------------------------
/build/dependencies.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
4 |
5 |
6 | 3.0.0-build-20181114.5
7 | 3.0.0-alpha1-10742
8 | 3.0.0-alpha1-10742
9 | 3.0.0-alpha1-10742
10 | 3.0.0-alpha1-10742
11 | 3.0.0-alpha1-10742
12 | 3.0.0-alpha1-10742
13 | 3.0.0-preview-181113-11
14 | 3.0.0-preview-181113-11
15 | 3.0.0-preview-181113-11
16 | 3.0.0-preview-181113-11
17 | 3.0.0-preview-181113-11
18 | 3.0.0-preview-181113-11
19 | 3.0.0-preview-181113-11
20 | 3.0.0-preview-181113-11
21 | 3.0.0-preview-181113-11
22 | 3.0.0-preview1-26907-05
23 | 15.6.1
24 | 4.10.0
25 | 2.0.3
26 | 2.3.1
27 | 2.4.0
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/build/repo.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Internal.AspNetCore.Universe.Lineup
11 | https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/build/sources.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $(DotNetRestoreSources)
6 |
7 | $(RestoreSources);
8 | https://dotnet.myget.org/F/dotnet-core/api/v3/index.json;
9 | https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json;
10 | https://dotnet.myget.org/F/aspnetcore-tools/api/v3/index.json;
11 |
12 |
13 | $(RestoreSources);
14 | https://api.nuget.org/v3/index.json;
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/korebuild-lock.txt:
--------------------------------------------------------------------------------
1 | version:3.0.0-build-20181114.5
2 | commithash:880e9a204d4ee4a18dfd83c9fb05a192a28bca60
3 |
--------------------------------------------------------------------------------
/korebuild.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://raw.githubusercontent.com/aspnet/BuildTools/master/tools/korebuild.schema.json",
3 | "channel": "master"
4 | }
5 |
--------------------------------------------------------------------------------
/run.cmd:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 | PowerShell -NoProfile -NoLogo -ExecutionPolicy unrestricted -Command "[System.Threading.Thread]::CurrentThread.CurrentCulture = ''; [System.Threading.Thread]::CurrentThread.CurrentUICulture = '';& '%~dp0run.ps1' %*; exit $LASTEXITCODE"
3 |
--------------------------------------------------------------------------------
/samples/LocalizationSample/LocalizationSample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/LocalizationSample/My/Resources/Startup.es-ES.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Hola
122 |
123 |
--------------------------------------------------------------------------------
/samples/LocalizationSample/My/Resources/Startup.fr-FR.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour
122 |
123 |
--------------------------------------------------------------------------------
/samples/LocalizationSample/My/Resources/Startup.ja-JP.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | こんにちは
122 |
123 |
--------------------------------------------------------------------------------
/samples/LocalizationSample/My/Resources/Startup.zh-CN.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 您好
122 |
123 |
--------------------------------------------------------------------------------
/samples/LocalizationSample/My/Resources/Startup.zh.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | 您好
122 |
123 |
--------------------------------------------------------------------------------
/src/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization.Routing/Microsoft.AspNetCore.Localization.Routing.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft ASP.NET Core
5 | Provides a request culture provider which gets culture and ui-culture from request's route data.
6 | netcoreapp3.0
7 | $(NoWarn);CS1591
8 | true
9 | aspnetcore;localization
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization.Routing/RouteDataRequestCultureProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Http;
7 | using Microsoft.AspNetCore.Routing;
8 | using Microsoft.Extensions.Internal;
9 |
10 | namespace Microsoft.AspNetCore.Localization.Routing
11 | {
12 | ///
13 | /// Determines the culture information for a request via values in the route data.
14 | ///
15 | public class RouteDataRequestCultureProvider : RequestCultureProvider
16 | {
17 | ///
18 | /// The key that contains the culture name.
19 | /// Defaults to "culture".
20 | ///
21 | public string RouteDataStringKey { get; set; } = "culture";
22 |
23 | ///
24 | /// The key that contains the UI culture name. If not specified or no value is found,
25 | /// will be used.
26 | /// Defaults to "ui-culture".
27 | ///
28 | public string UIRouteDataStringKey { get; set; } = "ui-culture";
29 |
30 | ///
31 | public override Task DetermineProviderCultureResult(HttpContext httpContext)
32 | {
33 | if (httpContext == null)
34 | {
35 | throw new ArgumentNullException(nameof(httpContext));
36 | }
37 |
38 | string culture = null;
39 | string uiCulture = null;
40 |
41 | if (!string.IsNullOrEmpty(RouteDataStringKey))
42 | {
43 | culture = httpContext.GetRouteValue(RouteDataStringKey)?.ToString();
44 | }
45 |
46 | if (!string.IsNullOrEmpty(UIRouteDataStringKey))
47 | {
48 | uiCulture = httpContext.GetRouteValue(UIRouteDataStringKey)?.ToString();
49 | }
50 |
51 | if (culture == null && uiCulture == null)
52 | {
53 | // No values specified for either so no match
54 | return NullProviderCultureResult;
55 | }
56 |
57 | if (culture != null && uiCulture == null)
58 | {
59 | // Value for culture but not for UI culture so default to culture value for both
60 | uiCulture = culture;
61 | }
62 |
63 | if (culture == null && uiCulture != null)
64 | {
65 | // Value for UI culture but not for culture so default to UI culture value for both
66 | culture = uiCulture;
67 | }
68 |
69 | var providerResultCulture = new ProviderCultureResult(culture, uiCulture);
70 |
71 | return Task.FromResult(providerResultCulture);
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization.Routing/baseline.netcore.json:
--------------------------------------------------------------------------------
1 | {
2 | "AssemblyIdentity": "Microsoft.AspNetCore.Localization.Routing, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60",
3 | "Types": [
4 | {
5 | "Name": "Microsoft.AspNetCore.Localization.Routing.RouteDataRequestCultureProvider",
6 | "Visibility": "Public",
7 | "Kind": "Class",
8 | "BaseType": "Microsoft.AspNetCore.Localization.RequestCultureProvider",
9 | "ImplementedInterfaces": [],
10 | "Members": [
11 | {
12 | "Kind": "Method",
13 | "Name": "DetermineProviderCultureResult",
14 | "Parameters": [
15 | {
16 | "Name": "httpContext",
17 | "Type": "Microsoft.AspNetCore.Http.HttpContext"
18 | }
19 | ],
20 | "ReturnType": "System.Threading.Tasks.Task",
21 | "Virtual": true,
22 | "Override": true,
23 | "ImplementedInterface": "Microsoft.AspNetCore.Localization.IRequestCultureProvider",
24 | "Visibility": "Public",
25 | "GenericParameter": []
26 | },
27 | {
28 | "Kind": "Method",
29 | "Name": "get_RouteDataStringKey",
30 | "Parameters": [],
31 | "ReturnType": "System.String",
32 | "Visibility": "Public",
33 | "GenericParameter": []
34 | },
35 | {
36 | "Kind": "Method",
37 | "Name": "set_RouteDataStringKey",
38 | "Parameters": [
39 | {
40 | "Name": "value",
41 | "Type": "System.String"
42 | }
43 | ],
44 | "ReturnType": "System.Void",
45 | "Visibility": "Public",
46 | "GenericParameter": []
47 | },
48 | {
49 | "Kind": "Method",
50 | "Name": "get_UIRouteDataStringKey",
51 | "Parameters": [],
52 | "ReturnType": "System.String",
53 | "Visibility": "Public",
54 | "GenericParameter": []
55 | },
56 | {
57 | "Kind": "Method",
58 | "Name": "set_UIRouteDataStringKey",
59 | "Parameters": [
60 | {
61 | "Name": "value",
62 | "Type": "System.String"
63 | }
64 | ],
65 | "ReturnType": "System.Void",
66 | "Visibility": "Public",
67 | "GenericParameter": []
68 | },
69 | {
70 | "Kind": "Constructor",
71 | "Name": ".ctor",
72 | "Parameters": [],
73 | "Visibility": "Public",
74 | "GenericParameter": []
75 | }
76 | ],
77 | "GenericParameters": []
78 | }
79 | ]
80 | }
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/AcceptLanguageHeaderRequestCultureProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.Extensions.Internal;
9 | using Microsoft.Net.Http.Headers;
10 |
11 | namespace Microsoft.AspNetCore.Localization
12 | {
13 | ///
14 | /// Determines the culture information for a request via the value of the Accept-Language header.
15 | ///
16 | public class AcceptLanguageHeaderRequestCultureProvider : RequestCultureProvider
17 | {
18 | ///
19 | /// The maximum number of values in the Accept-Language header to attempt to create a
20 | /// from for the current request.
21 | /// Defaults to 3.
22 | ///
23 | public int MaximumAcceptLanguageHeaderValuesToTry { get; set; } = 3;
24 |
25 | ///
26 | public override Task DetermineProviderCultureResult(HttpContext httpContext)
27 | {
28 | if (httpContext == null)
29 | {
30 | throw new ArgumentNullException(nameof(httpContext));
31 | }
32 |
33 | var acceptLanguageHeader = httpContext.Request.GetTypedHeaders().AcceptLanguage;
34 |
35 | if (acceptLanguageHeader == null || acceptLanguageHeader.Count == 0)
36 | {
37 | return NullProviderCultureResult;
38 | }
39 |
40 | var languages = acceptLanguageHeader.AsEnumerable();
41 |
42 | if (MaximumAcceptLanguageHeaderValuesToTry > 0)
43 | {
44 | // We take only the first configured number of languages from the header and then order those that we
45 | // attempt to parse as a CultureInfo to mitigate potentially spinning CPU on lots of parse attempts.
46 | languages = languages.Take(MaximumAcceptLanguageHeaderValuesToTry);
47 | }
48 |
49 | var orderedLanguages = languages.OrderByDescending(h => h, StringWithQualityHeaderValueComparer.QualityComparer)
50 | .Select(x => x.Value).ToList();
51 |
52 | if (orderedLanguages.Count > 0)
53 | {
54 | return Task.FromResult(new ProviderCultureResult(orderedLanguages));
55 | }
56 |
57 | return NullProviderCultureResult;
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/ApplicationBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using Microsoft.AspNetCore.Localization;
6 | using Microsoft.Extensions.Options;
7 |
8 | namespace Microsoft.AspNetCore.Builder
9 | {
10 | ///
11 | /// Extension methods for adding the to an application.
12 | ///
13 | public static class ApplicationBuilderExtensions
14 | {
15 | ///
16 | /// Adds the to automatically set culture information for
17 | /// requests based on information provided by the client.
18 | ///
19 | /// The .
20 | /// The .
21 | public static IApplicationBuilder UseRequestLocalization(this IApplicationBuilder app)
22 | {
23 | if (app == null)
24 | {
25 | throw new ArgumentNullException(nameof(app));
26 | }
27 |
28 | return app.UseMiddleware();
29 | }
30 |
31 | ///
32 | /// Adds the to automatically set culture information for
33 | /// requests based on information provided by the client.
34 | ///
35 | /// The .
36 | /// The to configure the middleware with.
37 | /// The .
38 | public static IApplicationBuilder UseRequestLocalization(
39 | this IApplicationBuilder app,
40 | RequestLocalizationOptions options)
41 | {
42 | if (app == null)
43 | {
44 | throw new ArgumentNullException(nameof(app));
45 | }
46 |
47 | if (options == null)
48 | {
49 | throw new ArgumentNullException(nameof(options));
50 | }
51 |
52 | return app.UseMiddleware(Options.Create(options));
53 | }
54 |
55 | ///
56 | /// Adds the to automatically set culture information for
57 | /// requests based on information provided by the client.
58 | ///
59 | /// The .
60 | ///
61 | ///
62 | /// This will going to instantiate a new that doesn't come from the services.
63 | ///
64 | /// The .
65 | public static IApplicationBuilder UseRequestLocalization(
66 | this IApplicationBuilder app,
67 | Action optionsAction)
68 | {
69 | if (app == null)
70 | {
71 | throw new ArgumentNullException(nameof(app));
72 | }
73 |
74 | if (optionsAction == null)
75 | {
76 | throw new ArgumentNullException(nameof(optionsAction));
77 | }
78 |
79 | var options = new RequestLocalizationOptions();
80 | optionsAction.Invoke(options);
81 |
82 | return app.UseMiddleware(Options.Create(options));
83 | }
84 |
85 | ///
86 | /// Adds the to automatically set culture information for
87 | /// requests based on information provided by the client.
88 | ///
89 | /// The .
90 | /// The culture names to be added by the application, which is represents both supported cultures and UI cultures.
91 | /// The .
92 | ///
93 | /// Note that the first culture is the default culture name.
94 | ///
95 | public static IApplicationBuilder UseRequestLocalization(
96 | this IApplicationBuilder app,
97 | params string[] cultures)
98 | {
99 | if (app == null)
100 | {
101 | throw new ArgumentNullException(nameof(app));
102 | }
103 |
104 | if (cultures == null)
105 | {
106 | throw new ArgumentNullException(nameof(cultures));
107 | }
108 |
109 | if (cultures.Length == 0)
110 | {
111 | throw new ArgumentException(Resources.Exception_CulturesShouldNotBeEmpty);
112 | }
113 |
114 | var options = new RequestLocalizationOptions()
115 | .AddSupportedCultures(cultures)
116 | .AddSupportedUICultures(cultures)
117 | .SetDefaultCulture(cultures[0]);
118 |
119 | return app.UseMiddleware(Options.Create(options));
120 | }
121 | }
122 | }
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/CookieRequestCultureProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Http;
7 | using Microsoft.Extensions.Internal;
8 |
9 | namespace Microsoft.AspNetCore.Localization
10 | {
11 | ///
12 | /// Determines the culture information for a request via the value of a cookie.
13 | ///
14 | public class CookieRequestCultureProvider : RequestCultureProvider
15 | {
16 | private static readonly char[] _cookieSeparator = new[] { '|' };
17 | private static readonly string _culturePrefix = "c=";
18 | private static readonly string _uiCulturePrefix = "uic=";
19 |
20 | ///
21 | /// Represent the default cookie name used to track the user's preferred culture information, which is ".AspNetCore.Culture".
22 | ///
23 | public static readonly string DefaultCookieName = ".AspNetCore.Culture";
24 |
25 | ///
26 | /// The name of the cookie that contains the user's preferred culture information.
27 | /// Defaults to .
28 | ///
29 | public string CookieName { get; set; } = DefaultCookieName;
30 |
31 | ///
32 | public override Task DetermineProviderCultureResult(HttpContext httpContext)
33 | {
34 | if (httpContext == null)
35 | {
36 | throw new ArgumentNullException(nameof(httpContext));
37 | }
38 |
39 | var cookie = httpContext.Request.Cookies[CookieName];
40 |
41 | if (string.IsNullOrEmpty(cookie))
42 | {
43 | return NullProviderCultureResult;
44 | }
45 |
46 | var providerResultCulture = ParseCookieValue(cookie);
47 |
48 | return Task.FromResult(providerResultCulture);
49 | }
50 |
51 | ///
52 | /// Creates a string representation of a for placement in a cookie.
53 | ///
54 | /// The .
55 | /// The cookie value.
56 | public static string MakeCookieValue(RequestCulture requestCulture)
57 | {
58 | if (requestCulture == null)
59 | {
60 | throw new ArgumentNullException(nameof(requestCulture));
61 | }
62 |
63 | var seperator = _cookieSeparator[0].ToString();
64 |
65 | return string.Join(seperator,
66 | $"{_culturePrefix}{requestCulture.Culture.Name}",
67 | $"{_uiCulturePrefix}{requestCulture.UICulture.Name}");
68 | }
69 |
70 | ///
71 | /// Parses a from the specified cookie value.
72 | /// Returns null if parsing fails.
73 | ///
74 | /// The cookie value to parse.
75 | /// The or null if parsing fails.
76 | public static ProviderCultureResult ParseCookieValue(string value)
77 | {
78 | if (string.IsNullOrWhiteSpace(value))
79 | {
80 | return null;
81 | }
82 |
83 | var parts = value.Split(_cookieSeparator, StringSplitOptions.RemoveEmptyEntries);
84 |
85 | if (parts.Length != 2)
86 | {
87 | return null;
88 | }
89 |
90 | var potentialCultureName = parts[0];
91 | var potentialUICultureName = parts[1];
92 |
93 | if (!potentialCultureName.StartsWith(_culturePrefix) || !potentialUICultureName.StartsWith(_uiCulturePrefix))
94 | {
95 | return null;
96 | }
97 |
98 | var cultureName = potentialCultureName.Substring(_culturePrefix.Length);
99 | var uiCultureName = potentialUICultureName.Substring(_uiCulturePrefix.Length);
100 |
101 | if (cultureName == null && uiCultureName == null)
102 | {
103 | // No values specified for either so no match
104 | return null;
105 | }
106 |
107 | if (cultureName != null && uiCultureName == null)
108 | {
109 | // Value for culture but not for UI culture so default to culture value for both
110 | uiCultureName = cultureName;
111 | }
112 |
113 | if (cultureName == null && uiCultureName != null)
114 | {
115 | // Value for UI culture but not for culture so default to UI culture value for both
116 | cultureName = uiCultureName;
117 | }
118 |
119 | return new ProviderCultureResult(cultureName, uiCultureName);
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/CustomRequestCultureProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Http;
7 |
8 | namespace Microsoft.AspNetCore.Localization
9 | {
10 | ///
11 | /// Determines the culture information for a request via the configured delegate.
12 | ///
13 | public class CustomRequestCultureProvider : RequestCultureProvider
14 | {
15 | private readonly Func> _provider;
16 |
17 | ///
18 | /// Creates a new using the specified delegate.
19 | ///
20 | /// The provider delegate.
21 | public CustomRequestCultureProvider(Func> provider)
22 | {
23 | if (provider == null)
24 | {
25 | throw new ArgumentNullException(nameof(provider));
26 | }
27 |
28 | _provider = provider;
29 | }
30 |
31 | ///
32 | public override Task DetermineProviderCultureResult(HttpContext httpContext)
33 | {
34 | if (httpContext == null)
35 | {
36 | throw new ArgumentNullException(nameof(httpContext));
37 | }
38 |
39 | return _provider(httpContext);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/IRequestCultureFeature.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | namespace Microsoft.AspNetCore.Localization
5 | {
6 | ///
7 | /// Represents the feature that provides the current request's culture information.
8 | ///
9 | public interface IRequestCultureFeature
10 | {
11 | ///
12 | /// The of the request.
13 | ///
14 | RequestCulture RequestCulture { get; }
15 |
16 | ///
17 | /// The that determined the request's culture information.
18 | /// If the value is null then no provider was used and the request's culture was set to the value of
19 | /// .
20 | ///
21 | IRequestCultureProvider Provider { get; }
22 | }
23 | }
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/IRequestCultureProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Http;
6 |
7 | namespace Microsoft.AspNetCore.Localization
8 | {
9 | ///
10 | /// Represents a provider for determining the culture information of an .
11 | ///
12 | public interface IRequestCultureProvider
13 | {
14 | ///
15 | /// Implements the provider to determine the culture of the given request.
16 | ///
17 | /// The for the request.
18 | ///
19 | /// The determined .
20 | /// Returns null if the provider couldn't determine a .
21 | ///
22 | Task DetermineProviderCultureResult(HttpContext httpContext);
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/Internal/RequestCultureProviderLoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using Microsoft.Extensions.Logging;
7 | using Microsoft.Extensions.Primitives;
8 |
9 | namespace Microsoft.AspNetCore.Localization.Internal
10 | {
11 | internal static class RequestCultureProviderLoggerExtensions
12 | {
13 | private static readonly Action, Exception> _unsupportedCulture;
14 | private static readonly Action, Exception> _unsupportedUICulture;
15 |
16 | static RequestCultureProviderLoggerExtensions()
17 | {
18 | _unsupportedCulture = LoggerMessage.Define>(
19 | LogLevel.Warning,
20 | 1,
21 | "{requestCultureProvider} returned the following unsupported cultures '{cultures}'.");
22 | _unsupportedUICulture = LoggerMessage.Define>(
23 | LogLevel.Warning,
24 | 2,
25 | "{requestCultureProvider} returned the following unsupported UI Cultures '{uiCultures}'.");
26 | }
27 |
28 | public static void UnsupportedCultures(this ILogger logger, string requestCultureProvider, IList cultures)
29 | {
30 | _unsupportedCulture(logger, requestCultureProvider, cultures, null);
31 | }
32 |
33 | public static void UnsupportedUICultures(this ILogger logger, string requestCultureProvider, IList uiCultures)
34 | {
35 | _unsupportedUICulture(logger, requestCultureProvider, uiCultures, null);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/Microsoft.AspNetCore.Localization.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft ASP.NET Core
5 | ASP.NET Core middleware for automatically applying culture information to HTTP requests. Culture information can be specified in the HTTP header, query string, cookie, or custom source.
6 | netcoreapp3.0
7 | $(NoWarn);CS1591
8 | true
9 | aspnetcore;localization
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | namespace Microsoft.AspNetCore.Localization
3 | {
4 | using System.Reflection;
5 | using System.Resources;
6 |
7 | internal static class Resources
8 | {
9 | private static readonly ResourceManager _resourceManager
10 | = new ResourceManager("Microsoft.AspNetCore.Localization.Resources", typeof(Resources).GetTypeInfo().Assembly);
11 |
12 | ///
13 | /// Please provide at least one culture.
14 | ///
15 | internal static string Exception_CulturesShouldNotBeEmpty
16 | {
17 | get { return GetString("Exception_CulturesShouldNotBeEmpty"); }
18 | }
19 |
20 | private static string GetString(string name, params string[] formatterNames)
21 | {
22 | var value = _resourceManager.GetString(name);
23 |
24 | System.Diagnostics.Debug.Assert(value != null);
25 |
26 | if (formatterNames != null)
27 | {
28 | for (var i = 0; i < formatterNames.Length; i++)
29 | {
30 | value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
31 | }
32 | }
33 |
34 | return value;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/ProviderCultureResult.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections.Generic;
5 | using Microsoft.Extensions.Primitives;
6 |
7 | namespace Microsoft.AspNetCore.Localization
8 | {
9 | ///
10 | /// Details about the cultures obtained from .
11 | ///
12 | public class ProviderCultureResult
13 | {
14 | ///
15 | /// Creates a new object that has its and
16 | /// properties set to the same culture value.
17 | ///
18 | /// The name of the culture to be used for formatting, text, i.e. language.
19 | public ProviderCultureResult(StringSegment culture)
20 | : this(new List { culture }, new List { culture })
21 | {
22 | }
23 |
24 | ///
25 | /// Creates a new object has its and
26 | /// properties set to the respective culture values provided.
27 | ///
28 | /// The name of the culture to be used for formatting.
29 | /// The name of the ui culture to be used for text, i.e. language.
30 | public ProviderCultureResult(StringSegment culture, StringSegment uiCulture)
31 | : this(new List { culture }, new List { uiCulture })
32 | {
33 | }
34 |
35 | ///
36 | /// Creates a new object that has its and
37 | /// properties set to the same culture value.
38 | ///
39 | /// The list of cultures to be used for formatting, text, i.e. language.
40 | public ProviderCultureResult(IList cultures)
41 | : this(cultures, cultures)
42 | {
43 | }
44 |
45 | ///
46 | /// Creates a new object has its and
47 | /// properties set to the respective culture values provided.
48 | ///
49 | /// The list of cultures to be used for formatting.
50 | /// The list of ui cultures to be used for text, i.e. language.
51 | public ProviderCultureResult(IList cultures, IList uiCultures)
52 | {
53 | Cultures = cultures;
54 | UICultures = uiCultures;
55 | }
56 |
57 | ///
58 | /// Gets the list of cultures to be used for formatting.
59 | ///
60 | public IList Cultures { get; }
61 |
62 | ///
63 | /// Gets the list of ui cultures to be used for text, i.e. language;
64 | ///
65 | public IList UICultures { get; }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/QueryStringRequestCultureProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Http;
7 | using Microsoft.Extensions.Internal;
8 |
9 | namespace Microsoft.AspNetCore.Localization
10 | {
11 | ///
12 | /// Determines the culture information for a request via values in the query string.
13 | ///
14 | public class QueryStringRequestCultureProvider : RequestCultureProvider
15 | {
16 | ///
17 | /// The key that contains the culture name.
18 | /// Defaults to "culture".
19 | ///
20 | public string QueryStringKey { get; set; } = "culture";
21 |
22 | ///
23 | /// The key that contains the UI culture name. If not specified or no value is found,
24 | /// will be used.
25 | /// Defaults to "ui-culture".
26 | ///
27 | public string UIQueryStringKey { get; set; } = "ui-culture";
28 |
29 | ///
30 | public override Task DetermineProviderCultureResult(HttpContext httpContext)
31 | {
32 | if (httpContext == null)
33 | {
34 | throw new ArgumentNullException(nameof(httpContext));
35 | }
36 |
37 | var request = httpContext.Request;
38 | if (!request.QueryString.HasValue)
39 | {
40 | return NullProviderCultureResult;
41 | }
42 |
43 | string queryCulture = null;
44 | string queryUICulture = null;
45 |
46 | if (!string.IsNullOrWhiteSpace(QueryStringKey))
47 | {
48 | queryCulture = request.Query[QueryStringKey];
49 | }
50 |
51 | if (!string.IsNullOrWhiteSpace(UIQueryStringKey))
52 | {
53 | queryUICulture = request.Query[UIQueryStringKey];
54 | }
55 |
56 | if (queryCulture == null && queryUICulture == null)
57 | {
58 | // No values specified for either so no match
59 | return NullProviderCultureResult;
60 | }
61 |
62 | if (queryCulture != null && queryUICulture == null)
63 | {
64 | // Value for culture but not for UI culture so default to culture value for both
65 | queryUICulture = queryCulture;
66 | }
67 |
68 | if (queryCulture == null && queryUICulture != null)
69 | {
70 | // Value for UI culture but not for culture so default to UI culture value for both
71 | queryCulture = queryUICulture;
72 | }
73 |
74 | var providerResultCulture = new ProviderCultureResult(queryCulture, queryUICulture);
75 |
76 | return Task.FromResult(providerResultCulture);
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/RequestCulture.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Globalization;
6 |
7 | namespace Microsoft.AspNetCore.Localization
8 | {
9 | ///
10 | /// Details about the culture for an .
11 | ///
12 | public class RequestCulture
13 | {
14 | ///
15 | /// Creates a new object has its and
16 | /// properties set to the same value.
17 | ///
18 | /// The for the request.
19 | public RequestCulture(CultureInfo culture)
20 | : this(culture, culture)
21 | {
22 | }
23 |
24 | ///
25 | /// Creates a new object has its and
26 | /// properties set to the same value.
27 | ///
28 | /// The culture for the request.
29 | public RequestCulture(string culture)
30 | : this(culture, culture)
31 | {
32 | }
33 |
34 | ///
35 | /// Creates a new object has its and
36 | /// properties set to the respective values provided.
37 | ///
38 | /// The culture for the request to be used for formatting.
39 | /// The culture for the request to be used for text, i.e. language.
40 | public RequestCulture(string culture, string uiCulture)
41 | : this (new CultureInfo(culture), new CultureInfo(uiCulture))
42 | {
43 | }
44 |
45 | ///
46 | /// Creates a new object has its and
47 | /// properties set to the respective values provided.
48 | ///
49 | /// The for the request to be used for formatting.
50 | /// The for the request to be used for text, i.e. language.
51 | public RequestCulture(CultureInfo culture, CultureInfo uiCulture)
52 | {
53 | if (culture == null)
54 | {
55 | throw new ArgumentNullException(nameof(culture));
56 | }
57 |
58 | if (uiCulture == null)
59 | {
60 | throw new ArgumentNullException(nameof(uiCulture));
61 | }
62 |
63 | Culture = culture;
64 | UICulture = uiCulture;
65 | }
66 |
67 | ///
68 | /// Gets the for the request to be used for formatting.
69 | ///
70 | public CultureInfo Culture { get; }
71 |
72 | ///
73 | /// Gets the for the request to be used for text, i.e. language;
74 | ///
75 | public CultureInfo UICulture { get; }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/RequestCultureFeature.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 |
6 | namespace Microsoft.AspNetCore.Localization
7 | {
8 | ///
9 | /// Provides the current request's culture information.
10 | ///
11 | public class RequestCultureFeature : IRequestCultureFeature
12 | {
13 | ///
14 | /// Creates a new with the specified .
15 | ///
16 | /// The .
17 | /// The .
18 | public RequestCultureFeature(RequestCulture requestCulture, IRequestCultureProvider provider)
19 | {
20 | if (requestCulture == null)
21 | {
22 | throw new ArgumentNullException(nameof(requestCulture));
23 | }
24 |
25 | RequestCulture = requestCulture;
26 | Provider = provider;
27 | }
28 |
29 | ///
30 | public RequestCulture RequestCulture { get; }
31 |
32 | ///
33 | public IRequestCultureProvider Provider { get; }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/RequestCultureProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Http;
7 |
8 | namespace Microsoft.AspNetCore.Localization
9 | {
10 | ///
11 | /// An abstract base class provider for determining the culture information of an .
12 | ///
13 | public abstract class RequestCultureProvider : IRequestCultureProvider
14 | {
15 | ///
16 | /// Result that indicates that this instance of could not determine the
17 | /// request culture.
18 | ///
19 | protected static readonly Task NullProviderCultureResult = Task.FromResult(default(ProviderCultureResult));
20 |
21 | ///
22 | /// The current options for the .
23 | ///
24 | public RequestLocalizationOptions Options { get; set; }
25 |
26 | ///
27 | public abstract Task DetermineProviderCultureResult(HttpContext httpContext);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Microsoft.AspNetCore.Localization/RequestLocalizationOptionsExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using Microsoft.AspNetCore.Localization;
6 |
7 | namespace Microsoft.AspNetCore.Builder
8 | {
9 | ///
10 | /// Extension methods for the .
11 | ///
12 | public static class RequestLocalizationOptionsExtensions
13 | {
14 | ///
15 | /// Adds a new to the .
16 | ///
17 | /// The cultures to be added.
18 | /// The cultures to be added.
19 | /// The .
20 | /// This method ensures that has priority over other instances in .
21 | public static RequestLocalizationOptions AddInitialRequestCultureProvider(
22 | this RequestLocalizationOptions requestLocalizationOptions,
23 | RequestCultureProvider requestCultureProvider)
24 | {
25 | if (requestLocalizationOptions == null)
26 | {
27 | throw new ArgumentNullException(nameof(requestLocalizationOptions));
28 | }
29 |
30 | if (requestCultureProvider == null)
31 | {
32 | throw new ArgumentNullException(nameof(requestCultureProvider));
33 | }
34 |
35 | requestLocalizationOptions.RequestCultureProviders.Insert(0, requestCultureProvider);
36 |
37 | return requestLocalizationOptions;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization.Abstractions/IStringLocalizer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 |
7 | namespace Microsoft.Extensions.Localization
8 | {
9 | ///
10 | /// Represents a service that provides localized strings.
11 | ///
12 | public interface IStringLocalizer
13 | {
14 | ///
15 | /// Gets the string resource with the given name.
16 | ///
17 | /// The name of the string resource.
18 | /// The string resource as a .
19 | LocalizedString this[string name] { get; }
20 |
21 | ///
22 | /// Gets the string resource with the given name and formatted with the supplied arguments.
23 | ///
24 | /// The name of the string resource.
25 | /// The values to format the string with.
26 | /// The formatted string resource as a .
27 | LocalizedString this[string name, params object[] arguments] { get; }
28 |
29 | ///
30 | /// Gets all string resources.
31 | ///
32 | ///
33 | /// A indicating whether to include strings from parent cultures.
34 | ///
35 | /// The strings.
36 | IEnumerable GetAllStrings(bool includeParentCultures);
37 |
38 | ///
39 | /// Creates a new for a specific .
40 | ///
41 | /// The to use.
42 | /// A culture-specific .
43 | IStringLocalizer WithCulture(CultureInfo culture);
44 | }
45 | }
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization.Abstractions/IStringLocalizerFactory.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 |
6 | namespace Microsoft.Extensions.Localization
7 | {
8 | ///
9 | /// Represents a factory that creates instances.
10 | ///
11 | public interface IStringLocalizerFactory
12 | {
13 | ///
14 | /// Creates an using the and
15 | /// of the specified .
16 | ///
17 | /// The .
18 | /// The .
19 | IStringLocalizer Create(Type resourceSource);
20 |
21 | ///
22 | /// Creates an .
23 | ///
24 | /// The base name of the resource to load strings from.
25 | /// The location to load resources from.
26 | /// The .
27 | IStringLocalizer Create(string baseName, string location);
28 | }
29 | }
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization.Abstractions/IStringLocalizerOfT.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | namespace Microsoft.Extensions.Localization
5 | {
6 | ///
7 | /// Represents an that provides strings for .
8 | ///
9 | /// The to provide strings for.
10 | public interface IStringLocalizer : IStringLocalizer
11 | {
12 |
13 | }
14 | }
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization.Abstractions/LocalizedString.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 |
6 | namespace Microsoft.Extensions.Localization
7 | {
8 | ///
9 | /// A locale specific string.
10 | ///
11 | public class LocalizedString
12 | {
13 | ///
14 | /// Creates a new .
15 | ///
16 | /// The name of the string in the resource it was loaded from.
17 | /// The actual string.
18 | public LocalizedString(string name, string value)
19 | : this(name, value, resourceNotFound: false)
20 | {
21 | }
22 |
23 | ///
24 | /// Creates a new .
25 | ///
26 | /// The name of the string in the resource it was loaded from.
27 | /// The actual string.
28 | /// Whether the string was not found in a resource. Set this to true to indicate an alternate string value was used.
29 | public LocalizedString(string name, string value, bool resourceNotFound)
30 | : this(name, value, resourceNotFound, searchedLocation: null)
31 | {
32 | }
33 |
34 | ///
35 | /// Creates a new .
36 | ///
37 | /// The name of the string in the resource it was loaded from.
38 | /// The actual string.
39 | /// Whether the string was not found in a resource. Set this to true to indicate an alternate string value was used.
40 | /// The location which was searched for a localization value.
41 | public LocalizedString(string name, string value, bool resourceNotFound, string searchedLocation)
42 | {
43 | if (name == null)
44 | {
45 | throw new ArgumentNullException(nameof(name));
46 | }
47 |
48 | if (value == null)
49 | {
50 | throw new ArgumentNullException(nameof(value));
51 | }
52 |
53 | Name = name;
54 | Value = value;
55 | ResourceNotFound = resourceNotFound;
56 | SearchedLocation = searchedLocation;
57 | }
58 |
59 | public static implicit operator string(LocalizedString localizedString)
60 | {
61 | return localizedString?.Value;
62 | }
63 |
64 | ///
65 | /// The name of the string in the resource it was loaded from.
66 | ///
67 | public string Name { get; }
68 |
69 | ///
70 | /// The actual string.
71 | ///
72 | public string Value { get; }
73 |
74 | ///
75 | /// Whether the string was not found in a resource. If true, an alternate string value was used.
76 | ///
77 | public bool ResourceNotFound { get; }
78 |
79 | ///
80 | /// The location which was searched for a localization value.
81 | ///
82 | public string SearchedLocation { get; }
83 |
84 | ///
85 | /// Returns the actual string.
86 | ///
87 | /// The actual string.
88 | public override string ToString() => Value;
89 | }
90 | }
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization.Abstractions/Microsoft.Extensions.Localization.Abstractions.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft .NET Extensions
5 | Abstractions of application localization services.
6 | Commonly used types:
7 | Microsoft.Extensions.Localization.IStringLocalizer
8 | Microsoft.Extensions.Localization.IStringLocalizer<T>
9 | netstandard2.0
10 | $(NoWarn);CS1591
11 | true
12 | localization
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization.Abstractions/StringLocalizerExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | namespace Microsoft.Extensions.Localization
8 | {
9 | public static class StringLocalizerExtensions
10 | {
11 | ///
12 | /// Gets the string resource with the given name.
13 | ///
14 | /// The .
15 | /// The name of the string resource.
16 | /// The string resource as a .
17 | public static LocalizedString GetString(
18 | this IStringLocalizer stringLocalizer,
19 | string name)
20 | {
21 | if (stringLocalizer == null)
22 | {
23 | throw new ArgumentNullException(nameof(stringLocalizer));
24 | }
25 |
26 | if (name == null)
27 | {
28 | throw new ArgumentNullException(nameof(name));
29 | }
30 |
31 | return stringLocalizer[name];
32 | }
33 |
34 | ///
35 | /// Gets the string resource with the given name and formatted with the supplied arguments.
36 | ///
37 | /// The .
38 | /// The name of the string resource.
39 | /// The values to format the string with.
40 | /// The formatted string resource as a .
41 | public static LocalizedString GetString(
42 | this IStringLocalizer stringLocalizer,
43 | string name,
44 | params object[] arguments)
45 | {
46 | if (stringLocalizer == null)
47 | {
48 | throw new ArgumentNullException(nameof(stringLocalizer));
49 | }
50 |
51 | if (name == null)
52 | {
53 | throw new ArgumentNullException(nameof(name));
54 | }
55 |
56 | return stringLocalizer[name, arguments];
57 | }
58 |
59 | ///
60 | /// Gets all string resources including those for parent cultures.
61 | ///
62 | /// The .
63 | /// The string resources.
64 | public static IEnumerable GetAllStrings(this IStringLocalizer stringLocalizer)
65 | {
66 | if (stringLocalizer == null)
67 | {
68 | throw new ArgumentNullException(nameof(stringLocalizer));
69 | }
70 |
71 | return stringLocalizer.GetAllStrings(includeParentCultures: true);
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization.Abstractions/StringLocalizerOfT.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Globalization;
7 |
8 | namespace Microsoft.Extensions.Localization
9 | {
10 | ///
11 | /// Provides strings for .
12 | ///
13 | /// The to provide strings for.
14 | public class StringLocalizer : IStringLocalizer
15 | {
16 | private IStringLocalizer _localizer;
17 |
18 | ///
19 | /// Creates a new .
20 | ///
21 | /// The to use.
22 | public StringLocalizer(IStringLocalizerFactory factory)
23 | {
24 | if (factory == null)
25 | {
26 | throw new ArgumentNullException(nameof(factory));
27 | }
28 |
29 | _localizer = factory.Create(typeof(TResourceSource));
30 | }
31 |
32 | ///
33 | public virtual IStringLocalizer WithCulture(CultureInfo culture) => _localizer.WithCulture(culture);
34 |
35 | ///
36 | public virtual LocalizedString this[string name]
37 | {
38 | get
39 | {
40 | if (name == null)
41 | {
42 | throw new ArgumentNullException(nameof(name));
43 | }
44 |
45 | return _localizer[name];
46 | }
47 | }
48 |
49 | ///
50 | public virtual LocalizedString this[string name, params object[] arguments]
51 | {
52 | get
53 | {
54 | if (name == null)
55 | {
56 | throw new ArgumentNullException(nameof(name));
57 | }
58 |
59 | return _localizer[name, arguments];
60 | }
61 | }
62 |
63 | ///
64 | public IEnumerable GetAllStrings(bool includeParentCultures) =>
65 | _localizer.GetAllStrings(includeParentCultures);
66 | }
67 | }
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/IResourceNamesCache.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | namespace Microsoft.Extensions.Localization
8 | {
9 | ///
10 | /// Represents a cache of string names in resources.
11 | ///
12 | public interface IResourceNamesCache
13 | {
14 | ///
15 | /// Adds a set of resource names to the cache by using the specified function, if the name does not already exist.
16 | ///
17 | /// The resource name to add string names for.
18 | /// The function used to generate the string names for the resource.
19 | /// The string names for the resource.
20 | IList GetOrAdd(string name, Func> valueFactory);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/Internal/AssemblyWrapper.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.IO;
6 | using System.Reflection;
7 |
8 | namespace Microsoft.Extensions.Localization.Internal
9 | {
10 | public class AssemblyWrapper
11 | {
12 | public AssemblyWrapper(Assembly assembly)
13 | {
14 | if (assembly == null)
15 | {
16 | throw new ArgumentNullException(nameof(assembly));
17 | }
18 |
19 | Assembly = assembly;
20 | }
21 |
22 | public Assembly Assembly { get; }
23 |
24 | public virtual string FullName => Assembly.FullName;
25 |
26 | public virtual Stream GetManifestResourceStream(string name) => Assembly.GetManifestResourceStream(name);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/Internal/IResourceStringProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 |
7 | namespace Microsoft.Extensions.Localization.Internal
8 | {
9 | public interface IResourceStringProvider
10 | {
11 | IList GetAllResourceStrings(CultureInfo culture, bool throwOnMissing);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/Internal/ResourceManagerStringLocalizerLoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Globalization;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace Microsoft.Extensions.Localization.Internal
9 | {
10 | internal static class ResourceManagerStringLocalizerLoggerExtensions
11 | {
12 | private static readonly Action _searchedLocation;
13 |
14 | static ResourceManagerStringLocalizerLoggerExtensions()
15 | {
16 | _searchedLocation = LoggerMessage.Define(
17 | LogLevel.Debug,
18 | 1,
19 | $"{nameof(ResourceManagerStringLocalizer)} searched for '{{Key}}' in '{{LocationSearched}}' with culture '{{Culture}}'.");
20 | }
21 |
22 | public static void SearchedLocation(this ILogger logger, string key, string searchedLocation, CultureInfo culture)
23 | {
24 | _searchedLocation(logger, key, searchedLocation, culture, null);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/Internal/ResourceManagerStringProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections;
5 | using System.Collections.Generic;
6 | using System.Globalization;
7 | using System.Reflection;
8 | using System.Resources;
9 |
10 | namespace Microsoft.Extensions.Localization.Internal
11 | {
12 | public class ResourceManagerStringProvider : IResourceStringProvider
13 | {
14 | private readonly IResourceNamesCache _resourceNamesCache;
15 | private readonly ResourceManager _resourceManager;
16 | private readonly Assembly _assembly;
17 | private readonly string _resourceBaseName;
18 |
19 | public ResourceManagerStringProvider(
20 | IResourceNamesCache resourceCache,
21 | ResourceManager resourceManager,
22 | Assembly assembly,
23 | string baseName)
24 | {
25 | _resourceManager = resourceManager;
26 | _resourceNamesCache = resourceCache;
27 | _assembly = assembly;
28 | _resourceBaseName = baseName;
29 | }
30 |
31 | private string GetResourceCacheKey(CultureInfo culture)
32 | {
33 | var resourceName = _resourceManager.BaseName;
34 |
35 | return $"Culture={culture.Name};resourceName={resourceName};Assembly={_assembly.FullName}";
36 | }
37 |
38 | private string GetResourceName(CultureInfo culture)
39 | {
40 | var resourceStreamName = _resourceBaseName;
41 | if (!string.IsNullOrEmpty(culture.Name))
42 | {
43 | resourceStreamName += "." + culture.Name;
44 | }
45 | resourceStreamName += ".resources";
46 |
47 | return resourceStreamName;
48 | }
49 |
50 | public IList GetAllResourceStrings(CultureInfo culture, bool throwOnMissing)
51 | {
52 | var cacheKey = GetResourceCacheKey(culture);
53 |
54 | return _resourceNamesCache.GetOrAdd(cacheKey, _ =>
55 | {
56 | // We purposly don't dispose the ResourceSet because it causes an ObjectDisposedException when you try to read the values later.
57 | var resourceSet = _resourceManager.GetResourceSet(culture, createIfNotExists: true, tryParents: false);
58 | if (resourceSet == null)
59 | {
60 | if (throwOnMissing)
61 | {
62 | throw new MissingManifestResourceException(Resources.FormatLocalization_MissingManifest(GetResourceName(culture)));
63 | }
64 | else
65 | {
66 | return null;
67 | }
68 | }
69 |
70 | var names = new List();
71 | foreach (DictionaryEntry entry in resourceSet)
72 | {
73 | names.Add((string)entry.Key);
74 | }
75 |
76 | return names;
77 | });
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/LocalizationOptions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | namespace Microsoft.Extensions.Localization
5 | {
6 | ///
7 | /// Provides programmatic configuration for localization.
8 | ///
9 | public class LocalizationOptions
10 | {
11 | ///
12 | /// The relative path under application root where resource files are located.
13 | ///
14 | public string ResourcesPath { get; set; } = string.Empty;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/LocalizationServiceCollectionExtensions.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using Microsoft.Extensions.DependencyInjection.Extensions;
6 | using Microsoft.Extensions.Localization;
7 |
8 | namespace Microsoft.Extensions.DependencyInjection
9 | {
10 | ///
11 | /// Extension methods for setting up localization services in an .
12 | ///
13 | public static class LocalizationServiceCollectionExtensions
14 | {
15 | ///
16 | /// Adds services required for application localization.
17 | ///
18 | /// The to add the services to.
19 | /// The so that additional calls can be chained.
20 | public static IServiceCollection AddLocalization(this IServiceCollection services)
21 | {
22 | if (services == null)
23 | {
24 | throw new ArgumentNullException(nameof(services));
25 | }
26 |
27 | services.AddOptions();
28 |
29 | AddLocalizationServices(services);
30 |
31 | return services;
32 | }
33 |
34 | ///
35 | /// Adds services required for application localization.
36 | ///
37 | /// The to add the services to.
38 | ///
39 | /// An to configure the .
40 | ///
41 | /// The so that additional calls can be chained.
42 | public static IServiceCollection AddLocalization(
43 | this IServiceCollection services,
44 | Action setupAction)
45 | {
46 | if (services == null)
47 | {
48 | throw new ArgumentNullException(nameof(services));
49 | }
50 |
51 | if (setupAction == null)
52 | {
53 | throw new ArgumentNullException(nameof(setupAction));
54 | }
55 |
56 | AddLocalizationServices(services, setupAction);
57 |
58 | return services;
59 | }
60 |
61 | // To enable unit testing
62 | internal static void AddLocalizationServices(IServiceCollection services)
63 | {
64 | services.TryAddSingleton();
65 | services.TryAddTransient(typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
66 | }
67 |
68 | internal static void AddLocalizationServices(
69 | IServiceCollection services,
70 | Action setupAction)
71 | {
72 | AddLocalizationServices(services);
73 | services.Configure(setupAction);
74 | }
75 | }
76 | }
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/Microsoft.Extensions.Localization.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Microsoft .NET Extensions
5 | Application localization services and default implementation based on ResourceManager to load localized assembly resources.
6 | netstandard2.0
7 | $(NoWarn);CS1591
8 | true
9 | localization
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Runtime.CompilerServices;
5 |
6 | [assembly: InternalsVisibleTo("Microsoft.Extensions.Localization.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
7 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //
2 | namespace Microsoft.Extensions.Localization
3 | {
4 | using System.Globalization;
5 | using System.Reflection;
6 | using System.Resources;
7 |
8 | internal static class Resources
9 | {
10 | private static readonly ResourceManager _resourceManager
11 | = new ResourceManager("Microsoft.Extensions.Localization.Resources", typeof(Resources).GetTypeInfo().Assembly);
12 |
13 | ///
14 | /// The manifest '{0}' was not found.
15 | ///
16 | internal static string Localization_MissingManifest
17 | {
18 | get { return GetString("Localization_MissingManifest"); }
19 | }
20 |
21 | ///
22 | /// The manifest '{0}' was not found.
23 | ///
24 | internal static string FormatLocalization_MissingManifest(object p0)
25 | {
26 | return string.Format(CultureInfo.CurrentCulture, GetString("Localization_MissingManifest"), p0);
27 | }
28 |
29 | ///
30 | /// No manifests exist for the current culture.
31 | ///
32 | internal static string Localization_MissingManifest_Parent
33 | {
34 | get { return GetString("Localization_MissingManifest_Parent"); }
35 | }
36 |
37 | ///
38 | /// No manifests exist for the current culture.
39 | ///
40 | internal static string FormatLocalization_MissingManifest_Parent()
41 | {
42 | return GetString("Localization_MissingManifest_Parent");
43 | }
44 |
45 | private static string GetString(string name, params string[] formatterNames)
46 | {
47 | var value = _resourceManager.GetString(name);
48 |
49 | System.Diagnostics.Debug.Assert(value != null);
50 |
51 | if (formatterNames != null)
52 | {
53 | for (var i = 0; i < formatterNames.Length; i++)
54 | {
55 | value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
56 | }
57 | }
58 |
59 | return value;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/ResourceLocationAttribute.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 |
6 | namespace Microsoft.Extensions.Localization
7 | {
8 | ///
9 | /// Provides the location of resources for an Assembly.
10 | ///
11 | [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
12 | public class ResourceLocationAttribute : Attribute
13 | {
14 | ///
15 | /// Creates a new .
16 | ///
17 | /// The location of resources for this Assembly.
18 | public ResourceLocationAttribute(string resourceLocation)
19 | {
20 | if (string.IsNullOrEmpty(resourceLocation))
21 | {
22 | throw new ArgumentNullException(nameof(resourceLocation));
23 | }
24 |
25 | ResourceLocation = resourceLocation;
26 | }
27 |
28 | ///
29 | /// The location of resources for this Assembly.
30 | ///
31 | public string ResourceLocation { get; }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/ResourceNamesCache.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Concurrent;
6 | using System.Collections.Generic;
7 |
8 | namespace Microsoft.Extensions.Localization
9 | {
10 | ///
11 | /// An implementation of backed by a .
12 | ///
13 | public class ResourceNamesCache : IResourceNamesCache
14 | {
15 | private readonly ConcurrentDictionary> _cache = new ConcurrentDictionary>();
16 |
17 | ///
18 | public IList GetOrAdd(string name, Func> valueFactory)
19 | {
20 | return _cache.GetOrAdd(name, valueFactory);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/Microsoft.Extensions.Localization/RootNamespaceAttribute.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 |
6 | namespace Microsoft.Extensions.Localization
7 | {
8 | ///
9 | /// Provides the RootNamespace of an Assembly. The RootNamespace of the assembly is used by Localization to
10 | /// determine the resource name to look for when RootNamespace differs from the AssemblyName.
11 | ///
12 | [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
13 | public class RootNamespaceAttribute : Attribute
14 | {
15 | ///
16 | /// Creates a new .
17 | ///
18 | /// The RootNamespace for this Assembly.
19 | public RootNamespaceAttribute(string rootNamespace)
20 | {
21 | if (string.IsNullOrEmpty(rootNamespace))
22 | {
23 | throw new ArgumentNullException(nameof(rootNamespace));
24 | }
25 |
26 | RootNamespace = rootNamespace;
27 | }
28 |
29 | ///
30 | /// The RootNamespace of this Assembly. The RootNamespace of the assembly is used by Localization to
31 | /// determine the resource name to look for when RootNamespace differs from the AssemblyName.
32 | ///
33 | public string RootNamespace { get; }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/test/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/LocalizationWebsite.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/Models/Customer.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | namespace LocalizationWebsite.Models
5 | {
6 | public class Customer
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/Models/Customer.fr-FR.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour from Customer in Models folder
122 |
123 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/Program.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using Microsoft.AspNetCore.Hosting;
5 | using Microsoft.Extensions.Configuration;
6 | using Microsoft.Extensions.Logging;
7 |
8 | namespace LocalizationWebsite
9 | {
10 | public static class Program
11 | {
12 | public static void Main(string[] args)
13 | {
14 | var config = new ConfigurationBuilder()
15 | .AddCommandLine(args)
16 | .Build();
17 |
18 | var host = new WebHostBuilder()
19 | .ConfigureLogging((_, factory) =>
20 | {
21 | factory.AddConsole();
22 | factory.AddFilter("Console", level => level >= LogLevel.Warning);
23 | })
24 | .UseKestrel()
25 | .UseConfiguration(config)
26 | .UseStartup("LocalizationWebsite")
27 | .Build();
28 |
29 | host.Run();
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/Resources/Models.Customer.fr-FR.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour from Customer in resources folder
122 |
123 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/Resources/StartupCustomCulturePreserved.en-US.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | We shouldn't get the english hello!
122 |
123 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/Resources/StartupResourcesInFolder.fr-FR.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour from StartupResourcesInFolder
122 |
123 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/Resources/Test.fr-FR.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour from Test in resources folder
122 |
123 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/StartupBuilderAPIs.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using LocalizationWebsite.Models;
5 | using Microsoft.AspNetCore.Builder;
6 | using Microsoft.AspNetCore.Http;
7 | using Microsoft.AspNetCore.Localization;
8 | using Microsoft.Extensions.DependencyInjection;
9 | using Microsoft.Extensions.Localization;
10 | using Microsoft.Extensions.Logging;
11 |
12 | namespace LocalizationWebsite
13 | {
14 | public class StartupBuilderAPIs
15 | {
16 | public void ConfigureServices(IServiceCollection services)
17 | {
18 | services.AddLocalization(options => options.ResourcesPath = "Resources");
19 | }
20 |
21 | public void Configure(
22 | IApplicationBuilder app,
23 | ILoggerFactory loggerFactory,
24 | IStringLocalizer customerStringLocalizer)
25 | {
26 | var supportedCultures = new[] { "en-US", "fr-FR" };
27 | app.UseRequestLocalization(options =>
28 | options
29 | .AddSupportedCultures(supportedCultures)
30 | .AddSupportedUICultures(supportedCultures)
31 | .SetDefaultCulture("ar-YE")
32 | );
33 |
34 | app.Run(async (context) =>
35 | {
36 | var requestCultureFeature = context.Features.Get();
37 | var requestCulture = requestCultureFeature.RequestCulture;
38 | await context.Response.WriteAsync(customerStringLocalizer["Hello"]);
39 | });
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/StartupCustomCulturePreserved.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using Microsoft.AspNetCore.Builder;
7 | using Microsoft.AspNetCore.Http;
8 | using Microsoft.AspNetCore.Localization;
9 | using Microsoft.Extensions.DependencyInjection;
10 |
11 | namespace LocalizationWebsite
12 | {
13 | public class StartupCustomCulturePreserved
14 | {
15 | public void ConfigureServices(IServiceCollection services)
16 | {
17 | services.AddLocalization();
18 | }
19 |
20 | public void Configure(
21 | IApplicationBuilder app)
22 | {
23 | app.UseRequestLocalization(new RequestLocalizationOptions
24 | {
25 | DefaultRequestCulture = new RequestCulture("en-US"),
26 | SupportedCultures = new List()
27 | {
28 | new CultureInfo("en-US") { NumberFormat= { CurrencySymbol = "kr" } }
29 | },
30 | SupportedUICultures = new List()
31 | {
32 | new CultureInfo("en-US") { NumberFormat= { CurrencySymbol = "kr" } }
33 | }
34 | });
35 |
36 | app.Run(async (context) =>
37 | {
38 | await context.Response.WriteAsync(10.ToString("C"));
39 | });
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/StartupGetAllStrings.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.Linq;
7 | using LocalizationWebsite.Models;
8 | using Microsoft.AspNetCore.Builder;
9 | using Microsoft.AspNetCore.Http;
10 | using Microsoft.AspNetCore.Localization;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Localization;
13 | using Microsoft.Extensions.Logging;
14 |
15 | namespace LocalizationWebsite
16 | {
17 | public class StartupGetAllStrings
18 | {
19 | public void ConfigureServices(IServiceCollection services)
20 | {
21 | services.AddLocalization(options => options.ResourcesPath = "Resources");
22 | }
23 |
24 | public void Configure(
25 | IApplicationBuilder app,
26 | ILoggerFactory loggerFactory,
27 | IStringLocalizer customerStringLocalizer)
28 | {
29 | app.UseRequestLocalization(new RequestLocalizationOptions
30 | {
31 | DefaultRequestCulture = new RequestCulture("en-US"),
32 | SupportedCultures = new List()
33 | {
34 | new CultureInfo("fr-FR")
35 | },
36 | SupportedUICultures = new List()
37 | {
38 | new CultureInfo("fr-FR")
39 | }
40 | });
41 |
42 | app.Run(async (context) =>
43 | {
44 | var strings = customerStringLocalizer.GetAllStrings();
45 |
46 | await context.Response.WriteAsync(strings.Count().ToString());
47 | await context.Response.WriteAsync(" ");
48 | await context.Response.WriteAsync(string.Join(" ", strings));
49 | });
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/StartupResourcesAtRootFolder.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.Reflection;
7 | using LocalizationWebsite.Models;
8 | using Microsoft.AspNetCore.Builder;
9 | using Microsoft.AspNetCore.Http;
10 | using Microsoft.AspNetCore.Localization;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Localization;
13 | using Microsoft.Extensions.Logging;
14 |
15 | namespace LocalizationWebsite
16 | {
17 | public class StartupResourcesAtRootFolder
18 | {
19 | public void ConfigureServices(IServiceCollection services)
20 | {
21 | services.AddLocalization();
22 | }
23 |
24 | public void Configure(
25 | IApplicationBuilder app,
26 | ILoggerFactory loggerFactory,
27 | IStringLocalizerFactory stringLocalizerFactory,
28 | IStringLocalizer startupStringLocalizer,
29 | IStringLocalizer customerStringLocalizer)
30 | {
31 | app.UseRequestLocalization(new RequestLocalizationOptions
32 | {
33 | DefaultRequestCulture = new RequestCulture("en-US"),
34 | SupportedCultures = new List()
35 | {
36 | new CultureInfo("fr-FR")
37 | },
38 | SupportedUICultures = new List()
39 | {
40 | new CultureInfo("fr-FR")
41 | }
42 | });
43 |
44 | var location = typeof(LocalizationWebsite.StartupResourcesAtRootFolder).GetTypeInfo().Assembly.GetName().Name;
45 | var stringLocalizer = stringLocalizerFactory.Create("Test", location: location);
46 |
47 | app.Run(async (context) =>
48 | {
49 | await context.Response.WriteAsync(startupStringLocalizer["Hello"]);
50 | await context.Response.WriteAsync(" ");
51 | await context.Response.WriteAsync(stringLocalizer["Hello"]);
52 | await context.Response.WriteAsync(" ");
53 | await context.Response.WriteAsync(customerStringLocalizer["Hello"]);
54 | });
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/StartupResourcesAtRootFolder.fr-FR.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour from StartupResourcesAtRootFolder
122 |
123 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/StartupResourcesInClassLibrary.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.Reflection;
7 | using Microsoft.AspNetCore.Builder;
8 | using Microsoft.AspNetCore.Http;
9 | using Microsoft.AspNetCore.Localization;
10 | using Microsoft.Extensions.DependencyInjection;
11 | using Microsoft.Extensions.Localization;
12 | using Microsoft.Extensions.Logging;
13 |
14 | namespace LocalizationWebsite
15 | {
16 | public class StartupResourcesInClassLibrary
17 | {
18 | public void ConfigureServices(IServiceCollection services)
19 | {
20 | services.AddLocalization(options => options.ResourcesPath = "Resources");
21 | }
22 |
23 | public void Configure(
24 | IApplicationBuilder app,
25 | ILoggerFactory loggerFactory,
26 | IStringLocalizerFactory stringLocalizerFactory)
27 | {
28 | var supportedCultures = new List()
29 | {
30 | new CultureInfo("en-US"),
31 | new CultureInfo("fr-FR")
32 | };
33 |
34 | app.UseRequestLocalization(new RequestLocalizationOptions
35 | {
36 | DefaultRequestCulture = new RequestCulture("en-US"),
37 | SupportedCultures = supportedCultures,
38 | SupportedUICultures = supportedCultures
39 | });
40 |
41 | var noAttributeStringLocalizer = stringLocalizerFactory.Create(typeof(ResourcesClassLibraryNoAttribute.Model));
42 | var withAttributeStringLocalizer = stringLocalizerFactory.Create(typeof(ResourcesClassLibraryWithAttribute.Model));
43 |
44 | var noAttributeAssembly = typeof(ResourcesClassLibraryNoAttribute.Model).GetTypeInfo().Assembly;
45 | var noAttributeName = new AssemblyName(noAttributeAssembly.FullName).Name;
46 | var noAttributeNameStringLocalizer = stringLocalizerFactory.Create(
47 | nameof(ResourcesClassLibraryNoAttribute.Model),
48 | noAttributeName);
49 |
50 | var withAttributeAssembly = typeof(ResourcesClassLibraryWithAttribute.Model).GetTypeInfo().Assembly;
51 | var withAttributeName = new AssemblyName(withAttributeAssembly.FullName).Name;
52 | var withAttributeNameStringLocalizer = stringLocalizerFactory.Create(
53 | nameof(ResourcesClassLibraryWithAttribute.Model),
54 | withAttributeName);
55 |
56 | app.Run(async (context) =>
57 | {
58 | await context.Response.WriteAsync(noAttributeNameStringLocalizer["Hello"]);
59 | await context.Response.WriteAsync(" ");
60 | await context.Response.WriteAsync(noAttributeStringLocalizer["Hello"]);
61 | await context.Response.WriteAsync(" ");
62 | await context.Response.WriteAsync(withAttributeNameStringLocalizer["Hello"]);
63 | await context.Response.WriteAsync(" ");
64 | await context.Response.WriteAsync(withAttributeStringLocalizer["Hello"]);
65 | });
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/StartupResourcesInFolder.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.Reflection;
7 | using LocalizationWebsite.Models;
8 | using Microsoft.AspNetCore.Builder;
9 | using Microsoft.AspNetCore.Http;
10 | using Microsoft.AspNetCore.Localization;
11 | using Microsoft.Extensions.DependencyInjection;
12 | using Microsoft.Extensions.Localization;
13 | using Microsoft.Extensions.Logging;
14 |
15 | namespace LocalizationWebsite
16 | {
17 | public class StartupResourcesInFolder
18 | {
19 | public void ConfigureServices(IServiceCollection services)
20 | {
21 | services.AddLocalization(options => options.ResourcesPath = "Resources");
22 | }
23 |
24 | public void Configure(
25 | IApplicationBuilder app,
26 | ILoggerFactory loggerFactory,
27 | IStringLocalizerFactory stringLocalizerFactory,
28 | IStringLocalizer startupStringLocalizer,
29 | IStringLocalizer custromerStringLocalizer,
30 | // This localizer is used in tests to prevent a regression of https://github.com/aspnet/Localization/issues/293
31 | // Namely that english was always being returned if it existed.
32 | IStringLocalizer customCultureLocalizer)
33 | {
34 | app.UseRequestLocalization(new RequestLocalizationOptions
35 | {
36 | DefaultRequestCulture = new RequestCulture("en-US"),
37 | SupportedCultures = new List()
38 | {
39 | new CultureInfo("fr-FR")
40 | },
41 | SupportedUICultures = new List()
42 | {
43 | new CultureInfo("fr-FR")
44 | }
45 | });
46 |
47 | var assemblyName = typeof(StartupResourcesInFolder).GetTypeInfo().Assembly.GetName().Name;
48 | var stringLocalizer = stringLocalizerFactory.Create("Test", assemblyName);
49 |
50 | app.Run(async (context) =>
51 | {
52 | await context.Response.WriteAsync(startupStringLocalizer["Hello"]);
53 | await context.Response.WriteAsync(" ");
54 | await context.Response.WriteAsync(stringLocalizer["Hello"]);
55 | await context.Response.WriteAsync(" ");
56 | await context.Response.WriteAsync(custromerStringLocalizer["Hello"]);
57 | await context.Response.WriteAsync(" ");
58 | await context.Response.WriteAsync(customCultureLocalizer["Hello"]);
59 | });
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/test/LocalizationWebsite/Test.fr-FR.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour from Test in root folder
122 |
123 |
--------------------------------------------------------------------------------
/test/Microsoft.AspNetCore.Localization.FunctionalTests/LocalizationSampleTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.IO;
6 | using System.Net;
7 | using System.Net.Http;
8 | using System.Threading.Tasks;
9 | using LocalizationSample;
10 | using Microsoft.AspNetCore.Hosting;
11 | using Microsoft.AspNetCore.TestHost;
12 | using Xunit;
13 |
14 | namespace Microsoft.AspNetCore.Localization.FunctionalTests
15 | {
16 | public class LocalizationSampleTest
17 | {
18 | [Fact]
19 | public async Task LocalizationSampleSmokeTest()
20 | {
21 | // Arrange
22 | var webHostBuilder = new WebHostBuilder().UseStartup(typeof(Startup));
23 | var testHost = new TestServer(webHostBuilder);
24 | var locale = "fr-FR";
25 | var client = testHost.CreateClient();
26 | var request = new HttpRequestMessage(HttpMethod.Get, "My/Resources");
27 | var cookieValue = $"c={locale}|uic={locale}";
28 | request.Headers.Add("Cookie", $"{CookieRequestCultureProvider.DefaultCookieName}={cookieValue}");
29 |
30 | // Act
31 | var response = await client.SendAsync(request);
32 |
33 | // Assert
34 | Assert.Equal(HttpStatusCode.OK, response.StatusCode);
35 | Assert.Contains("Bonjour
", await response.Content.ReadAsStringAsync());
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/test/Microsoft.AspNetCore.Localization.FunctionalTests/LocalizationTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Net;
6 | using System.Net.Http;
7 | using System.Threading.Tasks;
8 | using LocalizationWebsite;
9 | using Microsoft.AspNetCore.Hosting;
10 | using Microsoft.AspNetCore.TestHost;
11 | using Xunit;
12 |
13 | namespace Microsoft.AspNetCore.Localization.FunctionalTests
14 | {
15 | public class LocalizationTest
16 | {
17 | [Fact]
18 | public Task Localization_CustomCulture()
19 | {
20 | return RunTest(
21 | typeof(StartupCustomCulturePreserved),
22 | "en-US",
23 | "kr10.00");
24 | }
25 |
26 | [Fact]
27 | public Task Localization_GetAllStrings()
28 | {
29 | return RunTest(
30 | typeof(StartupGetAllStrings),
31 | "fr-FR",
32 | "1 Bonjour from Customer in resources folder");
33 | }
34 |
35 | [Fact]
36 | public Task Localization_ResourcesInClassLibrary_ReturnLocalizedValue()
37 | {
38 | return RunTest(
39 | typeof(StartupResourcesInClassLibrary),
40 | "fr-FR",
41 | "Bonjour from ResourcesClassLibraryNoAttribute Bonjour from ResourcesClassLibraryNoAttribute Bonjour from ResourcesClassLibraryWithAttribute Bonjour from ResourcesClassLibraryWithAttribute");
42 | }
43 |
44 | [Fact]
45 | public Task Localization_ResourcesInFolder_ReturnLocalizedValue()
46 | {
47 | return RunTest(
48 | typeof(StartupResourcesInFolder),
49 | "fr-FR",
50 | "Bonjour from StartupResourcesInFolder Bonjour from Test in resources folder Bonjour from Customer in resources folder Hello");
51 | }
52 |
53 | [Fact]
54 | public Task Localization_ResourcesInFolder_ReturnLocalizedValue_WithCultureFallback()
55 | {
56 | return RunTest(
57 | typeof(StartupResourcesInFolder),
58 | "fr-FR-test",
59 | "Bonjour from StartupResourcesInFolder Bonjour from Test in resources folder Bonjour from Customer in resources folder Hello");
60 | }
61 |
62 | [Fact]
63 | public Task Localization_ResourcesInFolder_ReturnNonLocalizedValue_CultureHierarchyTooDeep()
64 | {
65 | return RunTest(
66 | typeof(StartupResourcesInFolder),
67 | "fr-FR-test-again-too-deep-to-work",
68 | "Hello Hello Hello Hello");
69 | }
70 |
71 | [Fact]
72 | public Task Localization_ResourcesAtRootFolder_ReturnLocalizedValue()
73 | {
74 | return RunTest(
75 | typeof(StartupResourcesAtRootFolder),
76 | "fr-FR",
77 | "Bonjour from StartupResourcesAtRootFolder Bonjour from Test in root folder Bonjour from Customer in Models folder");
78 | }
79 |
80 | [Fact]
81 | public Task Localization_BuilderAPIs()
82 | {
83 | return RunTest(
84 | typeof(StartupBuilderAPIs),
85 | "ar-YE",
86 | "Hello");
87 | }
88 |
89 | private async Task RunTest(Type startupType, string culture, string expected)
90 | {
91 | var webHostBuilder = new WebHostBuilder().UseStartup(startupType);
92 | var testHost = new TestServer(webHostBuilder);
93 |
94 | var client = testHost.CreateClient();
95 | var request = new HttpRequestMessage();
96 | var cookieValue = $"c={culture}|uic={culture}";
97 | request.Headers.Add("Cookie", $"{CookieRequestCultureProvider.DefaultCookieName}={cookieValue}");
98 |
99 | var response = await client.SendAsync(request);
100 |
101 | Assert.Equal(HttpStatusCode.OK, response.StatusCode);
102 | Assert.Equal(expected, await response.Content.ReadAsStringAsync());
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/test/Microsoft.AspNetCore.Localization.FunctionalTests/Microsoft.AspNetCore.Localization.FunctionalTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/test/Microsoft.AspNetCore.Localization.Routing.Tests/Microsoft.AspNetCore.Localization.Routing.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/test/Microsoft.AspNetCore.Localization.Tests/CustomRequestCultureProviderTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Globalization;
7 | using System.Threading.Tasks;
8 | using Microsoft.AspNetCore.Builder;
9 | using Microsoft.AspNetCore.Hosting;
10 | using Microsoft.AspNetCore.Http;
11 | using Microsoft.AspNetCore.Localization;
12 | using Microsoft.AspNetCore.TestHost;
13 | using Xunit;
14 |
15 | namespace Microsoft.Extensions.Localization
16 | {
17 | public class CustomRequestCultureProviderTest
18 | {
19 | [Fact]
20 | public async Task CustomRequestCultureProviderThatGetsCultureInfoFromUrl()
21 | {
22 | var builder = new WebHostBuilder()
23 | .Configure(app =>
24 | {
25 | var options = new RequestLocalizationOptions
26 | {
27 | DefaultRequestCulture = new RequestCulture("en-US"),
28 | SupportedCultures = new List
29 | {
30 | new CultureInfo("ar")
31 | },
32 | SupportedUICultures = new List
33 | {
34 | new CultureInfo("ar")
35 | }
36 | };
37 | options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(context =>
38 | {
39 | var culture = GetCultureInfoFromUrl(context, options.SupportedCultures);
40 | var requestCulture = new ProviderCultureResult(culture);
41 | return Task.FromResult(requestCulture);
42 | }));
43 | app.UseRequestLocalization(options);
44 | app.Run(context =>
45 | {
46 | var requestCultureFeature = context.Features.Get();
47 | var requestCulture = requestCultureFeature.RequestCulture;
48 | Assert.Equal("ar", requestCulture.Culture.Name);
49 | return Task.FromResult(0);
50 | });
51 | });
52 |
53 | using (var server = new TestServer(builder))
54 | {
55 | var client = server.CreateClient();
56 | var response = await client.GetAsync("/ar/page");
57 | }
58 | }
59 |
60 | private string GetCultureInfoFromUrl(HttpContext context, IList supportedCultures)
61 | {
62 | var currentCulture = "en";
63 | var segments = context.Request.Path.Value.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
64 | if (segments.Length > 1 && segments[0].Length == 2)
65 | {
66 | currentCulture = segments[0];
67 | }
68 |
69 | return currentCulture;
70 | }
71 | }
72 | }
--------------------------------------------------------------------------------
/test/Microsoft.AspNetCore.Localization.Tests/Microsoft.AspNetCore.Localization.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/test/Microsoft.AspNetCore.Localization.Tests/RequestLocalizationOptionsExtensionsTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Builder;
6 | using Xunit;
7 |
8 | namespace Microsoft.AspNetCore.Localization
9 | {
10 | public class RequestLocalizationOptionsExtensionsTest
11 | {
12 | [Fact]
13 | public void AddInitialRequestCultureProvider_ShouldBeInsertedAtFirstPostion()
14 | {
15 | // Arrange
16 | var options = new RequestLocalizationOptions();
17 | var provider = new CustomRequestCultureProvider(context => Task.FromResult(new ProviderCultureResult("ar-YE")));
18 |
19 | // Act
20 | options.AddInitialRequestCultureProvider(provider);
21 |
22 | // Assert
23 | Assert.Same(provider, options.RequestCultureProviders[0]);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/Microsoft.AspNetCore.Localization.Tests/RequestLocalizationOptionsTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Globalization;
6 | using System.Linq;
7 | using Microsoft.AspNetCore.Builder;
8 | using Xunit;
9 |
10 | namespace Microsoft.AspNetCore.Localization
11 | {
12 | public class RequestLocalizationOptionsTest : IDisposable
13 | {
14 | private readonly CultureInfo _initialCulture;
15 | private readonly CultureInfo _initialUICulture;
16 |
17 | public RequestLocalizationOptionsTest()
18 | {
19 | _initialCulture = CultureInfo.CurrentCulture;
20 | _initialUICulture = CultureInfo.CurrentUICulture;
21 | }
22 |
23 | [Fact]
24 | public void DefaultRequestCulture_DefaultsToCurrentCulture()
25 | {
26 | // Arrange/Act
27 | var options = new RequestLocalizationOptions();
28 |
29 | // Assert
30 | Assert.NotNull(options.DefaultRequestCulture);
31 | Assert.Equal(CultureInfo.CurrentCulture, options.DefaultRequestCulture.Culture);
32 | Assert.Equal(CultureInfo.CurrentUICulture, options.DefaultRequestCulture.UICulture);
33 | }
34 |
35 | [Fact]
36 | public void DefaultRequestCulture_DefaultsToCurrentCultureWhenExplicitlySet()
37 | {
38 | // Arrange
39 | var explicitCulture = new CultureInfo("fr-FR");
40 | CultureInfo.CurrentCulture = explicitCulture;
41 | CultureInfo.CurrentUICulture = explicitCulture;
42 |
43 | // Act
44 | var options = new RequestLocalizationOptions();
45 |
46 | // Assert
47 | Assert.Equal(explicitCulture, options.DefaultRequestCulture.Culture);
48 | Assert.Equal(explicitCulture, options.DefaultRequestCulture.UICulture);
49 | }
50 |
51 | [Fact]
52 | public void DefaultRequestCulture_ThrowsWhenTryingToSetToNull()
53 | {
54 | // Arrange
55 | var options = new RequestLocalizationOptions();
56 |
57 | // Act/Assert
58 | Assert.Throws(() => options.DefaultRequestCulture = null);
59 | }
60 |
61 | [Fact]
62 | public void SupportedCultures_DefaultsToCurrentCulture()
63 | {
64 | // Arrange/Act
65 | var options = new RequestLocalizationOptions();
66 |
67 | // Assert
68 | Assert.Collection(options.SupportedCultures, item => Assert.Equal(CultureInfo.CurrentCulture, item));
69 | Assert.Collection(options.SupportedUICultures, item => Assert.Equal(CultureInfo.CurrentUICulture, item));
70 | }
71 |
72 | [Fact]
73 | public void SupportedCultures_DefaultsToCurrentCultureWhenExplicitlySet()
74 | {
75 | // Arrange
76 | var explicitCulture = new CultureInfo("fr-FR");
77 | CultureInfo.CurrentCulture = explicitCulture;
78 | CultureInfo.CurrentUICulture = explicitCulture;
79 |
80 | // Act
81 | var options = new RequestLocalizationOptions();
82 |
83 | // Assert
84 | Assert.Collection(options.SupportedCultures, item => Assert.Equal(explicitCulture, item));
85 | Assert.Collection(options.SupportedUICultures, item => Assert.Equal(explicitCulture, item));
86 | }
87 |
88 | [Fact]
89 | public void BuilderAPIs_AddSupportedCultures()
90 | {
91 | // Arrange
92 | var supportedCultures = new[] { "en-US", "ar-YE" };
93 |
94 | // Act
95 | var options = new RequestLocalizationOptions()
96 | .AddSupportedCultures(supportedCultures);
97 |
98 | // Assert
99 | Assert.Equal(supportedCultures, options.SupportedCultures.Select(c => c.Name));
100 | }
101 |
102 | [Fact]
103 | public void BuilderAPIs_AddSupportedUICultures()
104 | {
105 | // Arrange
106 | var supportedUICultures = new[] { "en-US", "ar-YE" };
107 |
108 | // Act
109 | var options = new RequestLocalizationOptions()
110 | .AddSupportedUICultures(supportedUICultures);
111 |
112 | // Assert
113 | Assert.Equal(supportedUICultures, options.SupportedUICultures.Select(c => c.Name));
114 | }
115 |
116 | [Fact]
117 | public void BuilderAPIs_SetDefaultCulture()
118 | {
119 | // Arrange
120 | var defaultCulture = "ar-YE";
121 |
122 | // Act
123 | var options = new RequestLocalizationOptions()
124 | .SetDefaultCulture(defaultCulture);
125 |
126 | // Assert
127 | Assert.Equal(defaultCulture, options.DefaultRequestCulture.Culture.Name);
128 | }
129 |
130 | public void Dispose()
131 | {
132 | CultureInfo.CurrentCulture = _initialCulture;
133 | CultureInfo.CurrentUICulture = _initialUICulture;
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/test/Microsoft.Extensions.Localization.Tests/LocalizationServiceCollectionExtensionsTest.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System;
5 | using System.Linq;
6 | using Microsoft.Extensions.Localization;
7 | using Microsoft.Extensions.Options;
8 | using Xunit;
9 |
10 | namespace Microsoft.Extensions.DependencyInjection
11 | {
12 | public class LocalizationServiceCollectionExtensionsTest
13 | {
14 | [Fact]
15 | public void AddLocalization_AddsNeededServices()
16 | {
17 | // Arrange
18 | var collection = new ServiceCollection();
19 |
20 | // Act
21 | LocalizationServiceCollectionExtensions.AddLocalizationServices(collection);
22 |
23 | // Assert
24 | AssertContainsSingle(collection, typeof(IStringLocalizerFactory), typeof(ResourceManagerStringLocalizerFactory));
25 | AssertContainsSingle(collection, typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
26 | }
27 |
28 | [Fact]
29 | public void AddLocalizationWithLocalizationOptions_AddsNeededServices()
30 | {
31 | // Arrange
32 | var collection = new ServiceCollection();
33 |
34 | // Act
35 | LocalizationServiceCollectionExtensions.AddLocalizationServices(
36 | collection,
37 | options => options.ResourcesPath = "Resources");
38 |
39 | AssertContainsSingle(collection, typeof(IStringLocalizerFactory), typeof(ResourceManagerStringLocalizerFactory));
40 | AssertContainsSingle(collection, typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
41 | }
42 |
43 | private void AssertContainsSingle(
44 | IServiceCollection services,
45 | Type serviceType,
46 | Type implementationType)
47 | {
48 | var matches = services
49 | .Where(sd =>
50 | sd.ServiceType == serviceType &&
51 | sd.ImplementationType == implementationType)
52 | .ToArray();
53 |
54 | if (matches.Length == 0)
55 | {
56 | Assert.True(
57 | false,
58 | $"Could not find an instance of {implementationType} registered as {serviceType}");
59 | }
60 | else if (matches.Length > 1)
61 | {
62 | Assert.True(
63 | false,
64 | $"Found multiple instances of {implementationType} registered as {serviceType}");
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/test/Microsoft.Extensions.Localization.Tests/Microsoft.Extensions.Localization.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.0;net461
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/test/ResourcesClassLibraryNoAttribute/Model.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | namespace ResourcesClassLibraryNoAttribute
5 | {
6 | public class Model
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/ResourcesClassLibraryNoAttribute/Resources/Model.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour from ResourcesClassLibraryNoAttribute
122 |
123 |
--------------------------------------------------------------------------------
/test/ResourcesClassLibraryNoAttribute/ResourcesClassLibraryNoAttribute.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/ResourcesClassLibraryWithAttribute/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | using System.Reflection;
5 | using Microsoft.Extensions.Localization;
6 |
7 | [assembly: ResourceLocation("ResourceFolder")]
8 | [assembly: RootNamespace("Alternate.Namespace")]
--------------------------------------------------------------------------------
/test/ResourcesClassLibraryWithAttribute/Model.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) .NET Foundation. All rights reserved.
2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3 |
4 | namespace ResourcesClassLibraryWithAttribute
5 | {
6 | public class Model
7 | {
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/ResourcesClassLibraryWithAttribute/ResourceFolder/Model.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bonjour from ResourcesClassLibraryWithAttribute
122 |
123 |
--------------------------------------------------------------------------------
/test/ResourcesClassLibraryWithAttribute/ResourcesClassLibraryWithAttribute.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | Alternate.Namespace
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/version.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | 3.0.0
4 | alpha1
5 | $(VersionPrefix)
6 | $(VersionPrefix)-$(VersionSuffix)-final
7 | t000
8 | a-
9 | $(FeatureBranchVersionPrefix)$(VersionSuffix)-$([System.Text.RegularExpressions.Regex]::Replace('$(FeatureBranchVersionSuffix)', '[^\w-]', '-'))
10 | $(VersionSuffix)-$(BuildNumber)
11 |
12 |
13 |
--------------------------------------------------------------------------------