Modeling localizable entities

128 views
Skip to first unread message

Jesús López

unread,
Oct 8, 2012, 5:04:44 AM10/8/12
to rav...@googlegroups.com
If i need to search and order by localizable properties. Which would be a good model for localizable entities? Which options should I consider?
 
 
Here is a proposed model that seems to work https://gist.github.com/3851523
 
Localizable entities would look like this:
 
"Products/1"
{
  "UnitPrice": 10.0,
  "LocalizedProperties": {
    "en": {
      "Name": "Cheese",
      "Description": null
    },
    "es": {
      "Name": "Queso",
      "Description": null
    }
  }
}

Oren Eini (Ayende Rahien)

unread,
Oct 8, 2012, 5:22:42 AM10/8/12
to rav...@googlegroups.com
That would work, sure. 

Jesús López

unread,
Oct 8, 2012, 7:04:43 AM10/8/12
to rav...@googlegroups.com
Thank you
 
Another option is this: https://gist.github.com/3851961 but I like more the first one.

Oren Eini (Ayende Rahien)

unread,
Oct 8, 2012, 7:10:44 PM10/8/12
to rav...@googlegroups.com
No, don't go that way. My eyes started to cross before I even got even half way

Paul Hinett

unread,
Oct 8, 2012, 7:38:50 PM10/8/12
to rav...@googlegroups.com
Ok that fix got my database up and running, so i'll leave it until you
have some spare time to have a deeper look.

By the way, my destinations document looked like this to cause the
failure:

{
"Destinations": [
{
"ConnectionStringName": "slave",
"Url": null,
"UseConnectionString": true,
"Username": null,
"Password": null,
"Domain": null,
"ApiKey": null,
"Database": "house-mixes2",
"TransitiveReplicationBehavior": "Replicate"
}
]
}



Paul Hinett

unread,
Oct 8, 2012, 7:44:01 PM10/8/12
to rav...@googlegroups.com
sorry, replied to wrong email.

Paul Hinett

unread,
Oct 8, 2012, 7:44:08 PM10/8/12
to rav...@googlegroups.com

mare

unread,
Oct 8, 2012, 8:07:59 PM10/8/12
to rav...@googlegroups.com
Jesus,
 
I happen to have a proprietary CMS that supports multiple locales and I did it the way that I separated content by language. For me, it's never really very logical that you have ONE instance of product or text or article (or anything else) in multiple languages. If it's an article, then different language means another article. Different article, with its own ID etc. That allows for more flexibility - you might have hundreds of articles in English but only a dozen in Spanish for instance. If you implemented it the way you described above, it would look to the end user or someone who doesn't know the system well that there are hundreds of articles in each and every language. It also makes it harder to pull out only the ones that are in Spanish. You inevitably end up with a lot of "if" checks..
 
to sum it up, I like to branch it by culture into a tree like structure, which work especially well within web apps.
 
HTH

Jesús López

unread,
Oct 9, 2012, 2:54:32 AM10/9/12
to rav...@googlegroups.com
Mare,
 
Thank you for sharing your approach. I agree that, in a CMS, having a sepparate document per language or culture makes sense. However I think there are many entities that are localizable. Perhaps the product example was not the best one. But products are break down into categories and subcategories, and it seems very clear to me that "Beverages" are the same category as "Bebidas" and they have to share the same document id.

Jesús López

unread,
Oct 9, 2012, 2:56:26 AM10/9/12
to rav...@googlegroups.com
Thank you,
 
Just exploring and experimenting other options. I agree this one is very awfull.

Troy

unread,
Oct 9, 2012, 3:03:37 AM10/9/12
to rav...@googlegroups.com
What would happen if you have a product or article or what have you... that did not have a translation? How would you be able to at least serve up a default language? I may be getting a project where I have to support multiple languages, so this is a very interesting conversation to me.

Jesús López

unread,
Oct 9, 2012, 3:36:42 AM10/9/12
to rav...@googlegroups.com
Yes,
 
This is something that we need to deal with.
 
First I would create a well known document with language settings:
 
 public class LanguageSettings
 {
  public string Id { get { return "WellknownDocuments/LanguageSettings"; } }
  public string DefaultLanguage { get; set; }
  public List<string> SupportedLanguages { get; set; }
  public static LanguageSettings Instance { get; set; }
 }
 
To show products to the user you can use a view model that projects localized properties in the current language.
 
It would be great to have a mapper or something that simplifies things like this:
 
 
 public class ProductViewModel
 {
  public string Id { get; set; }
  public decimal UnitPrice { get; set; }
  public string Name { get; set; }
  public string Description { get; set; }
  public ProductViewModel(){}
  public ProductViewModel(Product product, string languageCode)
  {
   this.Id = product.Id;
   this.UnitPrice = product.UnitPrice;
   Product.Localized lp = null;
   if (product.LocalizedProperties != null)
   {
    if (!product.LocalizedProperties.TryGetValue(languageCode, out lp))
    {
     if (!product.LocalizedProperties.TryGetValue(LanguageSettings.Instance.DefaultLanguage, out lp))
     {
      lp = product.LocalizedProperties.Select(kv => kv.Value).FirstOrDefault();
     }
    }
   }
   if (lp != null)
   {
    this.Name = lp.Name;
    this.Description = lp.Description;
   }
  }
 }
 
There is a problem with searching, though. If there is no translation you will not find anything. But searching for the default language would probably return no results either.
 
Perhaps you could make sure that every localizable entity have a translation in every supported language.

mare

unread,
Oct 9, 2012, 5:47:06 AM10/9/12
to rav...@googlegroups.com
"Perhaps you could make sure that every localizable entity have a translation in every supported language."
 
This is probable a wrong assumption, not a very realistic one.
 
What you have to think about is how those entities will be used, what use cases/scenario you want to support? For instance, I agree that the Product example might be bad. It is unlikely that you would need all the localizations in one place for a webstore since it is very likely a webstore for different country will be based on a different domain, it will follow different business rules etc. so it makes sense to dedicate a website/web application to one country.
 
On the other hand, if building like a company presentation website where you want to display company information to global visitors and give them the ability to switch for instance between English, Spanish and Russian site, it might make sense to say that there will always have to be a default culture for which every entity has content - that makes sense otherwise you would be serving up nothing;)
 
Then when the default language content is finished you might want to have the ability to export those entities, hand them over to translators and import them back in. That's why I said I'd have them as separate entities. They represent 1:1 the content that's similar to the original language but it's a copy of it. You want to be able to simply add or remove it. What happens if you want to remove a supported culture?
 
It will be a pain to go through all the entities and remove/empty their culture strings. It is much easier to have a culture identifier on the entity and then store it as such
 
en/article/1/about-us
 
sl/article/2/o-nas
 
You end up branching the content. When you only have "en/..." and you want to localize it, you take everything and translate it. When you want to remove a localization you just get rid of the branch and remove that language as supported.
 
To sum it up, I like your LanguageSettings file but I don't like the approach you did in ProductViewModel.
 
What are you actually building?

Jesús López

unread,
Oct 9, 2012, 6:57:01 AM10/9/12
to rav...@googlegroups.com
Mare,
 
We build LOB enterprise applications.
 
We have entities such as PaymentMethod, ExpenseNoteStatus, ProcessTemplates (we use Workflow Foundation). One expense note needs to have a well defined payment method. I'm not going to put "en/PaymentMethods/1" as the PaymentMethodId in the expense note, I will put "PaymentMethods/1". ExpenseNotes have Expenses, and each Expense is of one ExpenseType. I'm not going to put "en/ExpenseTypes/1" into the ExpenseTypeId property of the expense, I will put "ExpenseTypes/1". The same ExpenseNote is viewed by several people from several countries. One sales person in Spain creates one document and one manager in UK might be required to approve the expense note. The sales person sees expense type name "Habitación de hotel" in spanish, and expense details such as the city "Londres" in spanish. The manager sees the expense type name in english "Hotel room", and the city "London" in english.
 
I agree the view model is awful, but with a good mapper I hope it become nicer.
 
Most localizable entities, are small collections, most are reference only collections. So I can ensure all supported languages have a value, may be the default value, but at least one value. That might be a bad idea, I'm experimenting with that. This is only for searching on localizable entities, another option is having one index per language per entity. The index would take the default language if not translated.
 
Your approach works for you, but I think it doesn't for me.

Kijana Woodard

unread,
Oct 9, 2012, 8:18:32 PM10/9/12
to rav...@googlegroups.com
I recently built an application that needed multi-language support. There are some tough debates to have. There's a very subtle difference between a "translation of" and a "localized substitute for". Then you have some real business decisions of "when there is no match for the requested culture, show - english? esparanto? nothing?" If "no match" means, "not suitable for that culture" you get a whole different solution than if the meaning is "haven't translated it yet, so show them something that they might be able to use".

Good discussion here. Thanks. 
Reminds me that the next time I build such an app I want to use Raven. Doing this in SQL Server was kind of a PITA.

Dody Gunawinata

unread,
Oct 10, 2012, 5:53:08 AM10/10/12
to rav...@googlegroups.com
The approach that I find working fine is "have a default value unless there's a specific locale for it" for translation scenario.

For example, I have Arabic, English and Indonesian as a target language. I usually build English content and then progressively translate them to other languages. When user is looking for Arabic for example (/ar/about-us) and the translation is not available, I show them by default the English language. 


Kijana Woodard

unread,
Oct 10, 2012, 9:33:28 AM10/10/12
to rav...@googlegroups.com

Yup. That was the route I went in the previous app as well. It's just not universally correct.

Reply all
Reply to author
Forward
0 new messages