Интернационализация контента в Entity Framework

Я постоянно сталкиваюсь с требованием i18n, когда мои данные (не мой пользовательский интерфейс) должны быть интернационализированы.

public class FooEntity
{
  public long Id { get; set; }
  public string Code { get; set; } // Some values might not need i18n
  public string Name { get; set } // but e.g. this needs internationalized
  public string Description { get; set; } // and this too
}

Какие подходы я мог бы использовать?

Некоторые вещи, которые я пробовал: -

1) Хранить ключ ресурса в базе данных

public class FooEntity
{
  ...
  public string NameKey { get; set; }
  public string DescriptionKey { get; set; }
}
  • Плюсы: Нет необходимости в сложных запросах для получения переведенного объекта. System.Globalizationобрабатывает резервные копии за вас.
  • Минусы: пользователям с правами администратора нелегко управлять переводами (приходится развертывать файлы ресурсов всякий раз, когда мои Fooменяются).

2) Используйте тип сущности LocalizableString

public class FooEntity
{
  ...

  public int NameId { get; set; }
  public virtual LocalizableString Name { get; set; }

  public int NameId { get; set; }
  public virtual LocalizableString Description { get; set; }
}

public class LocalizableString
{
  public int Id { get; set; }

  public ICollection<LocalizedString> LocalizedStrings { get; set; }
}

public class LocalizedString
{
  public int Id { get; set; }

  public int ParentId { get; set; }
  public virtual LocalizableString Parent { get; set; }

  public int LanguageId { get; set; }
  public virtual Language Language { get; set; }

  public string Value { get; set; }
}

public class Language
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string CultureCode { get; set; }
}
  • Плюсы: все локализованные строки в одной таблице. Проверка может выполняться для каждой строки.
  • Минусы: ужасные запросы. Необходимо .Include таблицу LocalizedStrings один раз для каждой локализуемой строки в родительском объекте. Отказы сложны и включают в себя обширное присоединение. Не нашел способа избежать N+1 при извлечении, например. данные для таблицы.

3) Использовать родительский объект со всеми инвариантными свойствами и дочерние объекты, содержащие все локализованные свойства.

public class FooEntity
{
  ...
  public ICollection<FooTranslation> Translations { get; set; }
}

public class FooTranslation
{
  public long Id { get; set; }

  public int ParentId { get; set; }
  public virtual FooEntity Parent { get; set; }

  public int LanguageId { get; set; }
  public virtual Language Language { get; set; }

  public string Name { get; set }
  public string Description { get; set; }
}

public class Language
{
  public int Id { get; set; }
  public string Name { get; set; }
  public string CultureCode { get; set; }
}
  • Плюсы: не так сложно (но все же слишком сложно!) получить полный перевод объекта в память.
  • Минусы: вдвое больше объектов. Невозможно обработать частичные переводы объекта, особенно в случае, когда, скажем, Имя происходит от es, а Описание исходит от es-AR.

У меня есть три требования к решению.

  • Пользователи могут редактировать объекты, языки и переводы во время выполнения.

  • Пользователи могут предоставлять частичные переводы с отсутствующими строками, полученными из резервного варианта в соответствии с System.Globalization

  • Объекты могут быть внесены в память, не наткнувшись, например, на Проблемы N+1

18
задан Iain Galloway 10 June 2013 в 08:11
поделиться