Ответ 1
.NET Core изменил работу файлов ресурсов таким образом, что я чувствую себя неполным и запутанным (мне потребовались дни, чтобы понять), но это то, что вам нужно сделать:
-
Добавьте следующий код в Startup.cs - Примечание. Измените языки, которые вы поддерживаете, и ResourcePath из "Ресурсов" будет только папкой, в которой хранятся файлы.resx позже.
services.AddLocalization(o => o.ResourcesPath = "Resources"); services.Configure<RequestLocalizationOptions>(options => { var supportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("en-GB"), new CultureInfo("de-DE") }; options.DefaultRequestCulture = new RequestCulture("en-US", "en-US"); // You must explicitly state which cultures your application supports. // These are the cultures the app supports for formatting // numbers, dates, etc. options.SupportedCultures = supportedCultures; // These are the cultures the app supports for UI strings, // i.e. we have localized resources for. options.SupportedUICultures = supportedCultures; });
-
Создайте папку в любом проекте, в котором вы хотите сохранить файлы resx по умолчанию, назовите его "Ресурсы".
-
Создайте новый файл resx с определенной культурой и именем файла, который вы просмотрите позже: если у вас есть общий, вы можете сделать это: SharedResource.en-US.resx. Затем отключите генерацию автоматического кода, поскольку теперь это бесполезно.
-
Создайте класс под названием "SharedResource" в том же месте, что и ваш файл resx. Он может быть пустым, он просто должен быть там, поэтому вы можете ссылаться на него позже.
-
Где бы вы ни захотели использовать свой ресурс, IoC введет (в этом примере) IStringLocalizer <SharedResource> с именем "_localizer" или что-то в этом роде.
-
Наконец, вы можете ссылаться на запись в файле ресурсов, выполнив _localizer ["My_Resource_Name"]
-
Добавьте другой язык, создав новый файл resx с именем "SharedResource.de-DE.resx" или что-то еще в той же папке.
Папка "Ресурс" будет использоваться во всех сборках, чтобы просмотреть все их. Таким образом, эта папка может оказаться довольно захламленной, особенно если вы начнете получать информацию о конкретном материале здесь.
Я вижу, что разработчики пытались сделать здесь, но они отказались от слишком многого, чтобы добраться туда. Люди могут кодировать и добавлять переводческие материалы, фактически ничего не переводя. Они упростили работу разработчиков с самого начала, но в конечном итоге они стали более эффективными для разработчиков, которые фактически используют переводы. Теперь мы не можем автоматически генерировать что-либо. Мы должны IoC вводить ссылку на переводы для доступа к ним (не более статические, если вы не хотите использовать анти-шаблон ServiceLocater). Все имена являются жестко закодированными строками, поэтому теперь, если вы неправильно произнесете перевод, он просто вертет строку, которую вы ей дали, победив цель перевода в первую очередь, что означает, что вам, вероятно, понадобится обертка вокруг так что вы не полагаетесь на константы повсюду.
Я не могу поверить, что кто-то думал, что это хорошая идея, если честно. Почему бы не наклониться назад для разработчиков, которые не заботятся о переводах?
Я закончил создание обертки вокруг этого стиля. Единственная хорошая вещь в этом состоит в том, что если вы решите, что хотите получить ресурсы из базы данных, не потребуется никаких изменений кода, но теперь вам нужно добавить запись ресурса, добавить ее в интерфейс и затем реализовать ее для вытягивания он снова возвращается. Я использовал nameof(), поэтому мне не нужно было использовать константы, но это все еще хрупко, как если бы имя свойства или имя файла resx изменилось, оно сломает перевод без какого-либо сбоя - мне, вероятно, понадобится интеграционный тест чтобы я не получил то же значение, которое я отправляю:
public interface ICommonResource
{
string ErrorUnexpectedNumberOfRowsSaved { get; }
string ErrorNoRecordsSaved { get; }
string ErrorConcurrency { get; }
string ErrorGeneric { get; }
string RuleAlreadyInUse { get; }
string RuleDoesNotExist { get; }
string RuleInvalid { get; }
string RuleMaxLength { get; }
string RuleRequired { get; }
}
public class CommonResource : ICommonResource
{
private readonly IStringLocalizer<CommonResource> _localizer;
public CommonResource(IStringLocalizer<CommonResource> localizer) =>
_localizer = localizer;
public string ErrorUnexpectedNumberOfRowsSaved => GetString(nameof(ErrorUnexpectedNumberOfRowsSaved));
public string ErrorNoRecordsSaved => GetString(nameof(ErrorNoRecordsSaved));
public string ErrorConcurrency => GetString(nameof(ErrorConcurrency));
public string ErrorGeneric => GetString(nameof(ErrorGeneric));
public string RuleAlreadyInUse => GetString(nameof(RuleAlreadyInUse));
public string RuleDoesNotExist => GetString(nameof(RuleDoesNotExist));
public string RuleInvalid => GetString(nameof(RuleInvalid));
public string RuleMaxLength => GetString(nameof(RuleMaxLength));
public string RuleRequired => GetString(nameof(RuleRequired));
private string GetString(string name) =>
_localizer[name];
}