EF Code First поддержка нескольких языков - PullRequest
2 голосов
/ 03 декабря 2011

Предполагая, что вам нужно разработать веб-сайт, поддерживающий несколько языков, с классами EF Code First и POCO, как бы вы смоделировали свои классы POCO для поддержки этого сценария?

Под многоязыковой поддержкой я подразумевал не только, например, ярлыкиперевод в некоторые файлы ресурсов для вашего пользовательского интерфейса, но вам также необходимо сохранить имя, описание и т. д. для данного доменного объекта в вашей базе данных.

Например: допустим, в вашей доменной модели есть продукт сущности.В вашей базе данных вам нужно сохранить Название продукта и описание (2 поля для простоты) для 2 языков (но в будущем может быть добавлено больше языков).Исходя из текущей культуры, пользовательскому интерфейсу необходимо выбрать текст меток из файлов ресурсов (это легко реализовать), но вам также необходимо отобразить «Название и описание продукта», которое поступает из базы данных.

1 Ответ

7 голосов
/ 16 марта 2012

Наконец, я создал свои собственные классы для поддержки многоязычия в моих данных базы данных.

Я испанский, и я перевел свой код для поста здесь. Возможно, в нем есть простые синтаксические ошибки,

  1. У вас есть класс Product, у которого свойство ProductName имеет тип MultilingualString
  2. Класс MultilingualString имеет текст по умолчанию для каждого неизвестного языка и имеет список переводов этого текста. У него есть методы для установки различных переводов (SetTranslation) и методы для перевода на определенный язык. К концу этого класса есть свойство tu переводить в текущий поток культуры (перевод)
  3. У вас есть класс Translation, в котором есть язык и переведенный текст

Вот код:

public class Product
{
    public int Id { get; set; }
    public MultilingualString ProductName { get; set; }
}

public class MultilingualString
{
    // You need it only to make the class persistent
    public int Id { get; set; }

    public string Text { get; set; }
    public virtual ICollection<Translation> Translations { get; set; }

    public string Translation { get { return Translate(); } }

    public void SetTranslation(string language, string text)
    {
        if (Translations == null)
            Translations = new List<Translation>();

        var found = Translations.Where(t => t.Language.ToUpper() == language.ToUpper()).FirstOrDefault();
        if (found == null)
            Translations.Add(new Translation() { Language = language, Text = text });
        else
            found.Text = text;
    }

    public string Translate(string cultureName)
    {
        return Translate(new CultureInfo(cultureName));
    }


    public string Translate(CultureInfo culture = null)
    {
        if (culture == null)
            culture = Thread.CurrentThread.CurrentCulture;

        var translation = Translations == null
                             ? null
                             : Translations.Where(
                                 t =>
                                 culture.Name.ToUpper(CultureInfo.InvariantCulture).StartsWith(
                                     t.Language.ToUpper(CultureInfo.InvariantCulture))).FirstOrDefault();

        return translation == null ? Text : translation.Text;
    }
}

public class Translation
{
    // You need it only to make the class persistent
    public int Id { get; set; }
    public string Language { get; set; }
    public string Text { get; set; }
}

Вы можете создать класс DbContext и выполнить такой тест:

public class MultilingualContext : DbContext
{
    public DbSet<Product> Products { get; set; }
}

[TestClass]
public class Tests
{
    [TestMethod]
    public void ThisWorksFine()
    {
        using (var context = new MultilingualContext())
        {
            var product = new Product();
            context.Products.Add(product);

            product.ProductName = new MultilingualString() { Text = "Beer (default language)" };
            product.ProductName.SetTranslation("en", "Beer");
            product.ProductName.SetTranslation("es", "Cerveza");
            product.ProductName.SetTranslation("fr", "Bière");
            product.ProductName.SetTranslation("de", "Bier");

            var spanishProductName = product.ProductName.Translate(new CultureInfo("es"));
            Assert.AreEqual(spanishProductName, "Cerveza");

            var culture = Thread.CurrentThread.CurrentCulture;

            Thread.CurrentThread.CurrentCulture = new CultureInfo("en");
            Assert.AreEqual(product.ProductName.Translation, "Beer");
            Thread.CurrentThread.CurrentCulture = new CultureInfo("es");
            Assert.AreEqual(product.ProductName.Translation, "Cerveza");
            Thread.CurrentThread.CurrentCulture = new CultureInfo("fr");
            Assert.AreEqual(product.ProductName.Translation, "Bière");
            Thread.CurrentThread.CurrentCulture = new CultureInfo("de");
            Assert.AreEqual(product.ProductName.Translation, "Bier");
            Thread.CurrentThread.CurrentCulture = new CultureInfo("it");
            Assert.AreEqual(product.ProductName.Translation, "Beer (default language)");

            Thread.CurrentThread.CurrentCulture = culture;

            context.SaveChanges();


        }
    }
}

Я просто хочу покончить с этим, надеюсь, это нормально работает;)

С наилучшими пожеланиями!

UPDATE

Еще одна вещь, при удалении продукта не удаляйте многоязычную строковую запись. Вы можете добавить бизнес логический к вашим услугам и удалить многоязычную запись при удалении продукта.

Или нет! если вы не удалите многоязычную запись, у вас будет все больше и больше записей MultilingualStrings, и вы можете воспользоваться этим репозиторием, чтобы предлагать переведенные названия продуктов для будущих продуктов.

Вы можете добавить набор MultilingualStrings в контекст:

public class MultilingualContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<MultilingualString> MultilingualStrings { get; set; }
}

Затем вы можете искать MultilingualStrings в событии ProductNameTextBoxOnChange, например:

context.MultilingualStrings.Where(s => s.Translation.StartsWith(ProductNameTextBox.Text));

И вы можете использовать этот репозиторий для других свойств других объектов, которые имеют многоязычные строки.

...