public class Item{
public string Id { get; set;}
public string Name { get; set; }
public string Description { get; set;}
}
Approach 1 - use dictionary
public class Item{
public string Id { get; set;}
public string Name { get; set; }
public Dictionary<string,string> Description { get; set;} // language is key
}
Approach 2 - use explicit property
public class Item{
public string Id { get; set;}
public string Name { get; set; }
public string Description_DE { get; set;}
public string Description_RU { get; set;}
public string Description_EN { get; set;}
}
Approach 3 - one document per language
public class Item{
public string Id { get; set;}
public string Language { get; set;}
public string Name { get; set; }
public string Description { get; set;}
}
Approach 4 - language sub properties
public class Item{
public string Id { get; set;}
public string Name { get; set; }
public ItemLanguage[] LanguageProperties { get; set; }
}
public class ItemLanguage{
public string Language { get; set;}
public string Description { get; set;}
}
Approach 5 - Id hacking
"/Item/123/en";
"/Item/123/de";
"/Item/123/ru";
Any other suggestions? I was thinking that maybe some DB specific
feature like Document Versioning can be used to handle this kind of
stuff.
my opinion off the bat is for approach #1
--
Cheers,
w://
woudl you do the same there?
--
Cheers,
w://
Name : Ferrari Testarossa
General Description : The Ferrari Testarossa is a 12-cylinder
mid-engine sports car manufactured by Ferrari, which went into
production in 1984 as the successor to the Ferrari Berlinetta Boxer. T
Engine : The Testarossa sports a 4.9 litre (4,943 cubic centimetres /
302 cubic inches) Ferrari Colombo flat-12 engine mid mounted.[4][9]
Each cylinder has four valves, with forty-eight valves total,
lubricated via a dry sump system, and a compression ratio of
9.20:1.[4][9] These combine to provide a maximum torque of 490 newton
metres (361 ft·lbf) at 4500 rpm and a maximum power of 291 kilowatts
(396 PS; 390 hp) at 6300 rpm.[1][4][10] Early U.S. versions of the car
had the same engine, but slightly less power with only 283 kW (385 PS;
380 hp).[2][7][10]
Price : $181,000
Code: FT-001
The general description and engine section need to be translated to
multiple languages (Arabic, Italian, Inuit).
As the sales person, I know I only have one car that I have to
describe in multiple languages. Approach #3 will result in 3
documents. When I pull up a list of cars I have in my garage, I have
to filter by language so only one version of the car shows up.
public class TranslatedString : ListDictionary
{
public const string INVARIANT = "_";
public const string INVARIANT_LABEL = "Neutral";
string _lang;
/// <summary>
/// Initializes a new instance of the <see
cref="T:TranslatedString"/> class.
/// </summary>
public TranslatedString()
{
}
[JsonIgnore]
public string CurrentLanguage
{
get
{
return _lang as string;
}
set
{
_lang = value;
}
}
[JsonIgnore]
public string Value
{
get
{
_lang = _lang ?? Env.GetCurrentCultureCode();
var text = this[_lang] as string;
//If a language specific content is not found, try the
invariant version
if (text.IsNullOrWhiteSpace())
return this[INVARIANT] as string;
else
return text;
}
set
{
_lang = _lang ?? Env.GetCurrentCultureCode();
if (this.Contains(_lang))
this[_lang] = value;
else
Add(_lang, value);
}
}
/// <summary>
/// Only works if there's only one entry in the translated
string. Applicable mainly to be used in model binding.
/// </summary>
/// <param name="lang"></param>
public void ForceLanguage(string lang)
{
if (!this.Contains(lang) && this.Keys.Count == 1)
{
object oldValue = null;
object oldKey = null;
foreach (var k in this.Keys)
{
oldValue = this[k];
oldKey = k;
}
this.Remove(oldKey);
this[lang] = oldValue;
}
}
public void Merge(TranslatedString source)
{
foreach (var v in source.Keys)
this[v] = source[v];
}
/// <summary>
/// Set invariant value
/// </summary>
/// <param name="text"></param>
public void SetInvariant(string text)
{
this[INVARIANT] = text;
}
public static void SetLanguageOnStrings(string lang, bool
isForce, params TranslatedString[] strings)
{
if (isForce)
{
foreach (var s in strings)
s.ForceLanguage(lang);
}
else
{
foreach (var s in strings)
s.CurrentLanguage = lang;
}
}
/// <summary>
/// Mark all the languages with the given text in a target
translated string
/// </summary>
/// <param name="languages"></param>
/// <param name="text"></param>
/// <param name="targetString"></param>
public static void Reset(string[] languages, string text,
TranslatedString targetString)
{
foreach (var l in languages)
{
targetString[l] = text;
}
}
}
Use TranslatedString in properties you want to support
public class Fragment {
public string Id { get ; set; }
public TranslatedString Content { get; set; }
public string Name { get; set;}
}
This will be stored in RavenDB in this form
{
"Name": "screen-1",
"Content": {
"_": "<img src=\"/file/templates/screen1.png\" />",
"ar": "<img src=\"/file/templates/screen1.png\" /> ",
"en": "<img src=\"/file/templates/screen1.png\" />",
"fr": "<img src=\"/file/templates/screen1.png\" /> ",
"es": "<img src=\"/file/templates/screen1.png\" />"
}
}
In your HTML form, you use
Model.Name.Value e.g. @Html.EditorFor(model => model.Content.Value)
instead of model.Content
[HttpPost]
Create (Fragment f, string lang = "_")
{
//"_" signify invariant
f.SetLanguage(lang, force: true);
Save(f);
}
Note:
You have to use SetLanguage with force to ensure that the data from
the form is set according to the lang parameter you set otherwise it
will default to your current culture. If you don't do this, you will
end up saving "Poyo" in "en" culture instead of "se".
[HttpGet]
Edit(string id, string lang = "_")
{
var fragment = Load(id);
fragment.SetLanguage(lang);
return View(fragment)
}
Note:
You have to use SetLanguage so your Content property display the data
per lang parameter. Remember you have multiple language version for
the Content property but you can only display one in your form. So you
must pick which version of the language you display on your form.
Otherwise it will default to your current environment. This way, you
simply pass /edit/xxx?lang=en or /edit/xx?lang=ar to get English or
Arabic data.
For edit post, it's a bit trickier
[HttpPost]
Edit(string id, Fragment f, string lang = "_")
{
var existingFragment = Load(Id);
//Force form fragment to specific language
f.SetLanguage(lang, force: true);
//Start copy stuff from the form to the existing fragment
existingFragment.Name = f.Name
existingFragment.Content.Merge(f.Content);
//As you can see above, we have to use merge instead of direct
assignment. Remember your form Fragment only contains one language
version. Your existing data might already contains multiple version.
Direct assignment would erase old values
Save(existingFragment)
}
I hope this helps.
On Thu, May 26, 2011 at 4:09 PM, jalchr <jal...@gmail.com> wrote:
> Dody, that's interesting ...
> Can you post how you use the above class, just to be complete ?
public class Fragment {
public string Id { get ; set; }
public TranslatedString Content { get; set; }
public string Name { get; set;}
public void SetLanguage(string lang, bool force = false)
{
TranslatedString.SetLanguageOnStrings(lang, force, Content);
}
}