День 2558. #ВопросыНаСобеседовании
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
19. Глобализация и локализация
«Объясните, как реализовать глобализацию и локализацию в проекте веб-сайта ASP.NET Core MVC для поддержки нескольких языков и культур?»
Хороший ответ
Глобализация и локализация являются ключевыми факторами при разработке приложений, способных поддерживать несколько языков и культурных форматов. В ASP.NET Core это включает в себя настройку сервисов и промежуточного ПО для поддержки различных культур в целях локализации контента и форматирования данных в соответствии с предпочтениями пользователя.
Для реализации локализации в проекте веб-сайта ASP.NET Core необходимо настроить сервисы в файле Program.cs, добавив поддержку локализации для различных культур:
Далее создадим файлы ресурсов для каждого языка в каталоге
Затем внедрим IStringLocalizer в MVC-контроллеры или компоненты представления для получения локализованных строк:
Преимущества
- Гибкость и расширяемость: Лёгкое добавление поддержки дополнительных языков путем добавления новых файлов ресурсов.
- Улучшенный пользовательский опыт: Пользователи видят контент на предпочитаемом ими языке, что повышает удобство использования.
- Точность культуры: Правильно отформатированные даты, числа и валюты в соответствии с языковыми особенностями пользователя.
Эта конфигурация поддерживает не только контент, отображаемый на стороне сервера, но и может быть расширена для сценариев на стороне клиента с использованием библиотек JavaScript или вызовов API, возвращающих локализованный контент.
Часто встречающийся неправильный ответ
«Для поддержки нескольких языков в веб-приложении можно использовать перевод текста на стороне клиента, используя JavaScript или клиентскую библиотеку».
Почему это неправильно:
- Зависимость от клиентской стороны: Этот подход предполагает чрезмерно упрощённый метод, полагаясь исключительно на перевод на стороне клиента, что может привести к несоответствиям и не обрабатывает рендеринг на стороне сервера или форматирование данных (например, дат и чисел) должным образом.
- Игнорирование возможностей ASP.NET Core: Подход игнорирует встроенную поддержку локализации в ASP.NET Core, которая разработана для интеграции с серверной архитектурой, обеспечивая согласованное сохранение настроек локализации во всём приложении.
- Игнорирование доступности и SEO: Локализация на стороне сервера имеет решающее значение для доступности и поисковой оптимизации - областей, которые рендеринг на стороне клиента не может в полной мере учитывать.
Обычно эта ошибка возникает из-за недостаточного понимания инструментов и конфигураций, предоставляемых ASP.NET Core для обработки локализации и глобализации как на стороне клиента, так и на стороне сервера.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
Марк Прайс предложил свой набор из 60 вопросов (как технических, так и на софт-скилы), которые могут задать на собеседовании.
19. Глобализация и локализация
«Объясните, как реализовать глобализацию и локализацию в проекте веб-сайта ASP.NET Core MVC для поддержки нескольких языков и культур?»
Хороший ответ
Глобализация и локализация являются ключевыми факторами при разработке приложений, способных поддерживать несколько языков и культурных форматов. В ASP.NET Core это включает в себя настройку сервисов и промежуточного ПО для поддержки различных культур в целях локализации контента и форматирования данных в соответствии с предпочтениями пользователя.
Для реализации локализации в проекте веб-сайта ASP.NET Core необходимо настроить сервисы в файле Program.cs, добавив поддержку локализации для различных культур:
// Чтобы использовать RequestCulture
using Microsoft.AspNetCore.Localization;
var builder = WebApplication.CreateBuilder(args);
// Добавляем сервисы локализации
builder.Services.AddLocalization(options =>
options.ResourcesPath = "Resources");
// Настраиваем поддерживаемые культуры
string[] cultures = ["en-US", "fr-FR", "ru-RU"];
builder.Services
.Configure<RequestLocalizationOptions>(opts =>
{
opts.DefaultRequestCulture =
new RequestCulture("ru-RU ");
opts.SupportedCultures = cultures;
opts.SupportedUICultures = cultures;
});
var app = builder.Build();
app.UseRequestLocalization();
app.MapGet("/", (IStringLocalizer<Program> localizer) =>
localizer["WelcomeMessage"]);
app.Run();
Далее создадим файлы ресурсов для каждого языка в каталоге
Resources, назвав их <ClassName>.<Culture>.resx, например, Program.en-US.resx, Program.ru-RU.resx.Затем внедрим IStringLocalizer в MVC-контроллеры или компоненты представления для получения локализованных строк:
public class HomeController : Controller
{
private readonly
IStringLocalizer<HomeController> _localizer;
public HomeController(
IStringLocalizer<HomeController> localizer)
{
_localizer = localizer;
}
public IActionResult Index()
{
ViewData["Message"] = _localizer["HomePageWelcome"];
return View();
}
}
Преимущества
- Гибкость и расширяемость: Лёгкое добавление поддержки дополнительных языков путем добавления новых файлов ресурсов.
- Улучшенный пользовательский опыт: Пользователи видят контент на предпочитаемом ими языке, что повышает удобство использования.
- Точность культуры: Правильно отформатированные даты, числа и валюты в соответствии с языковыми особенностями пользователя.
Эта конфигурация поддерживает не только контент, отображаемый на стороне сервера, но и может быть расширена для сценариев на стороне клиента с использованием библиотек JavaScript или вызовов API, возвращающих локализованный контент.
Часто встречающийся неправильный ответ
«Для поддержки нескольких языков в веб-приложении можно использовать перевод текста на стороне клиента, используя JavaScript или клиентскую библиотеку».
Почему это неправильно:
- Зависимость от клиентской стороны: Этот подход предполагает чрезмерно упрощённый метод, полагаясь исключительно на перевод на стороне клиента, что может привести к несоответствиям и не обрабатывает рендеринг на стороне сервера или форматирование данных (например, дат и чисел) должным образом.
- Игнорирование возможностей ASP.NET Core: Подход игнорирует встроенную поддержку локализации в ASP.NET Core, которая разработана для интеграции с серверной архитектурой, обеспечивая согласованное сохранение настроек локализации во всём приложении.
- Игнорирование доступности и SEO: Локализация на стороне сервера имеет решающее значение для доступности и поисковой оптимизации - областей, которые рендеринг на стороне клиента не может в полной мере учитывать.
Обычно эта ошибка возникает из-за недостаточного понимания инструментов и конфигураций, предоставляемых ASP.NET Core для обработки локализации и глобализации как на стороне клиента, так и на стороне сервера.
Источник: https://github.com/markjprice/tools-skills-net8/blob/main/docs/interview-qa/readme.md
👍2
День 2559. #ЗаметкиНаПолях
Когда для Моделирования Объектов не Обойтись без Методов Расширения
Иногда "обычный" подход к моделированию сущности достигает своего предела, и приходится прибегать к методам расширения.
Проблема
Есть фронтенд-часть, которая позволяет частично обновлять сущность. Представьте, что в JIRA вы можете обновлять заголовок, автора и так далее в одном пользовательском интерфейсе. Для этого не нужен отдельный DTO для каждого варианта использования, достаточно одного DTO, который позволял бы частично обновлять сущность.
Во фронтенде (TypeScript/Angular):
Который используется в DTO:
На бэкэнде это позволяет сделать так:
Затем в методе обновления:
Это работает. Но что, если мы добавим propFour с обнуляемым типом:
Но в UpdateModel мы хотели бы иметь (потому что в случае обновления значение обязательно):
Теперь, если мы попытаемся выполнить:
Мы получим:
Argument type 'int?' is not assignable to parameter type 'int' (Тип аргумента 'int?' не может быть присвоен параметру типа 'int')
Решение
Проблема в том, что мы не можем легко переопределить возможность присвоения значения null в методе GetValueOrDefault. Здесь помогут методы расширения:
Теперь:
работает, как ожидалось.
Источник: https://steven-giesel.com/blogPost/7f6e2ade-b5b9-4de6-a060-281e45b2448e/sometimes-you-just-need-extensions-methods-to-model-your-stuff
Когда для Моделирования Объектов не Обойтись без Методов Расширения
Иногда "обычный" подход к моделированию сущности достигает своего предела, и приходится прибегать к методам расширения.
Проблема
Есть фронтенд-часть, которая позволяет частично обновлять сущность. Представьте, что в JIRA вы можете обновлять заголовок, автора и так далее в одном пользовательском интерфейсе. Для этого не нужен отдельный DTO для каждого варианта использования, достаточно одного DTO, который позволял бы частично обновлять сущность.
Во фронтенде (TypeScript/Angular):
export type Optional<T> = {
hasValue: boolean;
value: T;
};Который используется в DTO:
export type UpdateModel = {
propOne: Optional<number | null>;
propTwo: Optional<string | null>;
propThree: Optional<string>;
};На бэкэнде это позволяет сделать так:
/// <summary>
/// Структура, представляющая необязательное значение
/// </summary>
public readonly record struct
Optional<T>(bool HasValue, T Value)
{
/// <summary>
/// Возвращает значение, если оно есть, либо значение по умолчанию.
/// </summary>
public T GetValueOrDefault(T current)
=> HasValue ? Value : current;
}
Затем в методе обновления:
public void
UpdateEntity(UpdateModel model)
{
PropOne = model.PropOne
.GetValueOrDefault(entity.PropOne);
PropTwo = model.PropTwo
.GetValueOrDefault(entity.PropTwo);
PropThree = model.PropThree
.GetValueOrDefault(entity.PropThree);
}
Это работает. Но что, если мы добавим propFour с обнуляемым типом:
public int? PropFour { get; set; }Но в UpdateModel мы хотели бы иметь (потому что в случае обновления значение обязательно):
public Optional<int> PropFour { get; set; }Теперь, если мы попытаемся выполнить:
PropFour = model.PropFour
.GetValueOrDefault(entity.PropFour);
Мы получим:
Argument type 'int?' is not assignable to parameter type 'int' (Тип аргумента 'int?' не может быть присвоен параметру типа 'int')
Решение
Проблема в том, что мы не можем легко переопределить возможность присвоения значения null в методе GetValueOrDefault. Здесь помогут методы расширения:
public static class OptionalExtensions
{
/// <summary>
/// Возвращает значение, если оно есть, либо значение по умолчанию
/// </summary>
public static T? GetValueOrDefault<T>(
this Optional<T> opt,
T? value) where T : struct
=> opt.HasValue ? opt.Value : value;
}
Теперь:
PropFour = model.PropFour
.GetValueOrDefault(entity.PropFour);
работает, как ожидалось.
Источник: https://steven-giesel.com/blogPost/7f6e2ade-b5b9-4de6-a060-281e45b2448e/sometimes-you-just-need-extensions-methods-to-model-your-stuff