Локализация на основе URL-адресов в .NET core Razor – как это сделать? ⇐ C#
Локализация на основе URL-адресов в .NET core Razor – как это сделать?
Я создаю сайт .NET 8.0 Razor Page, где локализация/интернационализация осуществляется с помощью таких URL-адресов:
example.org/us // США example.org/fr // Франция example.org/pt // Португалия example.org/se // Швеция ... example.org/us/contact // страница контактов для США (текст отображается на английском языке) example.org/fr/contact // страница контактов для Франции (текст отображается на французском языке) т.е. URL-адреса содержат коды ISO 3166-1 альфа-2 для стран (например, us, fr, pt, se и т. д.). Текст поступает из стандартных файлов ресурсов (resx).
Большая часть моей реализации работает, но у меня есть небольшая проблема: несуществующие страницы возвращают StatusCode 200 вместо 404. Я погуглил, посмотрел другие примеры, но они либо устарели, либо больше не работают, либо работают только для MVC. Этот вопрос предназначен для Razor Pages, использующих директиву @page "/...".
Мне нужна помощь и советы по реализации.
Все мои страницы Razor содержат {lang} в маршруте страницы. Маршрут страницы контактов будет /{lang}/contact. {lang относится к коду ISO 3166-1 альфа-2.
Следующий код добавляет параметр {lang} ко всем страницам веб-приложения:
публичный класс CultureTemplatePageRouteModelConvention: IPageRouteModelConvention { public void Apply (модель PageRouteModel) { foreach (селектор var в model.Selectors) { вар шаблон = селектор.AttributeRouteModel.Template; если (template.StartsWith("MicrosoftIdentity")) продолжить; // Пропустить страницы MicrosoftIdentity // Добавление {lang}/ к маршрутам страницы позволяет осуществлять локализацию на основе маршрутов selector.AttributeRouteModel.Order = -1; selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{lang}", шаблон); } } } ...экземпляр program.cs с помощью:
builder.Services.AddRazorPages(options => { // украшаем все маршруты страниц {lang}, например. @page "/{lang}..." options.Conventions.Add(new CultureTemplatePageRouteModelConvention()); }); Чтобы установить фактическую культуру для запрошенной страницы, я реализовал собственный RequestCultureProvider со следующим:
публичный класс CustomRouteDataRequestCultureProvider: RequestCultureProvider { общедоступные SupportedAppLanguages SupportedAppLanguages; общедоступное переопределение Task DefinitiveProviderCultureResult(HttpContext httpContext) { var lang = (строка)httpContext.GetRouteValue("lang"); вар urlCulture = httpContext.Request.Path.Value.Split('/')[1]; строка [] контейнер = [lang, urlCulture]; var Culture = SupportedAppLanguages.Dict.Values.SingleOrDefault(langInApp =>Container.Contains(langInApp.Icc)); если (культура != ноль) { return Task.FromResult(новый ProviderCultureResult(cultural.Culture)); } // если совпадений нет, возвращаем 404 httpContext.Response.StatusCode = StatusCodes.Status404NotFound; return Task.FromResult(new ProviderCultureResult(Options.DefaultRequestCulture.Culture.TwoLetterISOLanguageName)); } } ...создается с помощью program.cs:
// получаем все языки, поддерживаемые приложением, через `appsettings.json`: var supportAppLanguages = builder.Configuration.GetSection("SupportedAppLanguages").Get(); var supportCultures = supportAppLanguages.Dict.Values.Select(langInApp => new CultureInfo(langInApp.Culture)).ToList(); builder.Services.Configure(параметры => { options.DefaultRequestCulture = новый RequestCulture (культура: «en-us», uiCulture: «en-us»); options.SupportedCultures =supportedCultures; options.SupportedUICultures = supportCultures; options.FallBackToParentCultures = true; options.RequestCultureProviders.Clear(); options.RequestCultureProviders.Insert(0, new CustomRouteDataRequestCultureProvider() {Options = options, SupportedAppLanguages =supportAppLanguages}); }); Чтобы пользователи не вводили странные коды локали/страны (и не вводили в заблуждение поисковые системы/предотвращали плохое SEO), я создал фильтр MiddlewareFilter для таких случаев:
публичный класс RouteConstraintMiddleware (RequestDelegate следующий, SupportedAppLanguages supportAppLanguages) { общедоступный асинхронный вызов задачи (контекст HttpContext) { // Context.Response.StatusCode для таких страниц, как example.org/us/non-existing, равен 200, а не правильному 404. // Как реализовать правильную проверку? if (context.Response.StatusCode == StatusCodes.Status404NotFound) return; if (string.IsNullOrEmpty(context?.GetRouteValue("lang")?.ToString())) return; //проверяем совпадение var lang = context.GetRouteValue("lang").ToString(); var поддерживается = поддерживаетсяAppLanguages.Dict.Values.Any(langInApp => lang == langInApp.Icc); если (! поддерживается) { context.Response.StatusCode = StatusCodes.Status404NotFound; возвращаться; } ждать следующего (контекст); } } Текущее состояние приложения:
example.org/us // 200. (правильно) example.org/fr // 200. (правильно) example.org/nonsense/contact // 404. (правильно) example.org/nonsense // 404. (правильно) example.org/us/non-existing // 200. (неверно, должно вернуть 404) Как это исправить? Это тоже хорошая реализация (мне кажется неуклюжей)? Можно ли решить проблему лучше? Упрощенная версия Github доступна здесь: https://github.com/shapeh/TestLocalization
Надеюсь на некоторые подсказки.
Я создаю сайт .NET 8.0 Razor Page, где локализация/интернационализация осуществляется с помощью таких URL-адресов:
example.org/us // США example.org/fr // Франция example.org/pt // Португалия example.org/se // Швеция ... example.org/us/contact // страница контактов для США (текст отображается на английском языке) example.org/fr/contact // страница контактов для Франции (текст отображается на французском языке) т.е. URL-адреса содержат коды ISO 3166-1 альфа-2 для стран (например, us, fr, pt, se и т. д.). Текст поступает из стандартных файлов ресурсов (resx).
Большая часть моей реализации работает, но у меня есть небольшая проблема: несуществующие страницы возвращают StatusCode 200 вместо 404. Я погуглил, посмотрел другие примеры, но они либо устарели, либо больше не работают, либо работают только для MVC. Этот вопрос предназначен для Razor Pages, использующих директиву @page "/...".
Мне нужна помощь и советы по реализации.
Все мои страницы Razor содержат {lang} в маршруте страницы. Маршрут страницы контактов будет /{lang}/contact. {lang относится к коду ISO 3166-1 альфа-2.
Следующий код добавляет параметр {lang} ко всем страницам веб-приложения:
публичный класс CultureTemplatePageRouteModelConvention: IPageRouteModelConvention { public void Apply (модель PageRouteModel) { foreach (селектор var в model.Selectors) { вар шаблон = селектор.AttributeRouteModel.Template; если (template.StartsWith("MicrosoftIdentity")) продолжить; // Пропустить страницы MicrosoftIdentity // Добавление {lang}/ к маршрутам страницы позволяет осуществлять локализацию на основе маршрутов selector.AttributeRouteModel.Order = -1; selector.AttributeRouteModel.Template = AttributeRouteModel.CombineTemplates("{lang}", шаблон); } } } ...экземпляр program.cs с помощью:
builder.Services.AddRazorPages(options => { // украшаем все маршруты страниц {lang}, например. @page "/{lang}..." options.Conventions.Add(new CultureTemplatePageRouteModelConvention()); }); Чтобы установить фактическую культуру для запрошенной страницы, я реализовал собственный RequestCultureProvider со следующим:
публичный класс CustomRouteDataRequestCultureProvider: RequestCultureProvider { общедоступные SupportedAppLanguages SupportedAppLanguages; общедоступное переопределение Task DefinitiveProviderCultureResult(HttpContext httpContext) { var lang = (строка)httpContext.GetRouteValue("lang"); вар urlCulture = httpContext.Request.Path.Value.Split('/')[1]; строка [] контейнер = [lang, urlCulture]; var Culture = SupportedAppLanguages.Dict.Values.SingleOrDefault(langInApp =>Container.Contains(langInApp.Icc)); если (культура != ноль) { return Task.FromResult(новый ProviderCultureResult(cultural.Culture)); } // если совпадений нет, возвращаем 404 httpContext.Response.StatusCode = StatusCodes.Status404NotFound; return Task.FromResult(new ProviderCultureResult(Options.DefaultRequestCulture.Culture.TwoLetterISOLanguageName)); } } ...создается с помощью program.cs:
// получаем все языки, поддерживаемые приложением, через `appsettings.json`: var supportAppLanguages = builder.Configuration.GetSection("SupportedAppLanguages").Get(); var supportCultures = supportAppLanguages.Dict.Values.Select(langInApp => new CultureInfo(langInApp.Culture)).ToList(); builder.Services.Configure(параметры => { options.DefaultRequestCulture = новый RequestCulture (культура: «en-us», uiCulture: «en-us»); options.SupportedCultures =supportedCultures; options.SupportedUICultures = supportCultures; options.FallBackToParentCultures = true; options.RequestCultureProviders.Clear(); options.RequestCultureProviders.Insert(0, new CustomRouteDataRequestCultureProvider() {Options = options, SupportedAppLanguages =supportAppLanguages}); }); Чтобы пользователи не вводили странные коды локали/страны (и не вводили в заблуждение поисковые системы/предотвращали плохое SEO), я создал фильтр MiddlewareFilter для таких случаев:
публичный класс RouteConstraintMiddleware (RequestDelegate следующий, SupportedAppLanguages supportAppLanguages) { общедоступный асинхронный вызов задачи (контекст HttpContext) { // Context.Response.StatusCode для таких страниц, как example.org/us/non-existing, равен 200, а не правильному 404. // Как реализовать правильную проверку? if (context.Response.StatusCode == StatusCodes.Status404NotFound) return; if (string.IsNullOrEmpty(context?.GetRouteValue("lang")?.ToString())) return; //проверяем совпадение var lang = context.GetRouteValue("lang").ToString(); var поддерживается = поддерживаетсяAppLanguages.Dict.Values.Any(langInApp => lang == langInApp.Icc); если (! поддерживается) { context.Response.StatusCode = StatusCodes.Status404NotFound; возвращаться; } ждать следующего (контекст); } } Текущее состояние приложения:
example.org/us // 200. (правильно) example.org/fr // 200. (правильно) example.org/nonsense/contact // 404. (правильно) example.org/nonsense // 404. (правильно) example.org/us/non-existing // 200. (неверно, должно вернуть 404) Как это исправить? Это тоже хорошая реализация (мне кажется неуклюжей)? Можно ли решить проблему лучше? Упрощенная версия Github доступна здесь: https://github.com/shapeh/TestLocalization
Надеюсь на некоторые подсказки.
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение
-
-
Как перенаправить одну структуру URL-адресов на другую структуру URL-адресов?
Anonymous » » в форуме Php - 0 Ответы
- 131 Просмотры
-
Последнее сообщение Anonymous
-
-
-
Как перенаправить одну структуру URL-адресов на другую структуру URL-адресов?
Anonymous » » в форуме Apache - 0 Ответы
- 151 Просмотры
-
Последнее сообщение Anonymous
-