19

データ (UI ではない) を国際化する必要がある 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; }
}
  • 長所: 同じテーブル内のすべてのローカライズされた文字列。検証は文字列ごとに実行できます。
  • 短所: クエリは恐ろしいものです。親エンティティのローカライズ可能な文字列ごとに、LocalizedStrings テーブルを 1 回含める必要があります。フォールバックは難しく、大規模な参加が必要です。テーブルのデータなどを取得するときに 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; }
}
  • 長所: エンティティをメモリに完全に変換することはそれほど難しくありません (それでも難しすぎます!)。
  • 短所: エンティティの数が 2 倍になります。エンティティの部分的な翻訳を処理できません。特に、 Name は fromesですが、 Description は fromの場合es-ARです。

ソリューションには 3 つの要件があります

  • ユーザーは実行時にエンティティ、言語、および翻訳を編集できます

  • ユーザーは、System.Globalization に従って、フォールバックからの文字列が欠落している部分的な翻訳を提供できます。

  • N+1 の問題などに遭遇することなく、エンティティをメモリに取り込むことができます。

4

2 に答える 2

1

データベースに静的コンテンツがある場合、最初のものは価値があります。たとえば、ユーザーによって変更される可能性が比較的低いカテゴリがある場合などです。次回のデプロイ時に変更できます。私は個人的にこの解決策が好きではありません。私はこれを良い解決策とは考えていません。これは問題の単なる回避です。

2 番目の方法が最適ですが、1 つのエンティティに 2 つ以上のローカライズ可能なフィールドがある場合に問題が発生する可能性があります。あなたはそれを少し単純化し、このように言語をハードコードすることができます

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

  public string EnglishText { get; set; }
  public string ItalianText { get; set; }
  public string ArmenianText { get; set; }
}

3番目のものも良いものではありません。この構造から、すべてのノード (リテラル、行、文字列など) が特定のカルチャで翻訳されているかどうかはわかりません。

あまり一般化しないでください。それぞれの問題は一種の専門的なものであり、専門的な解決策も必要です。一般化しすぎると、不当な問題が生じます。

于 2013-06-10T03:22:53.333 に答える