UmbracoMapper
UmbracoMapper copied to clipboard
Umbraco Mapper honouring fallback?
Hi Andy
I am trying to extend my IPropertyValueGetter Method to support a language fallback but can’t figure out what’s not working.
Say for example that Umbraco has 2 languages, English and Spanish, and English is defined as the fallback language for Spanish. (English also being the default) Now, consider that I have page nodes in the both content trees that pick a “category” from a common area (just another set of nodes). What I was expecting is that if the Category node isn’t published in Spanish, then the Spanish pages would ‘fallback’ to the Category from the English language tree.
My viewmodel property is decorated with
[PropertyMapping(PropertyValueGetter = typeof(CategoriesGetter), FallbackMethods = new[] { Fallback.Language })]
And the method passes the fallback onto the Umbraco IPublishedElement Value() method.
Sorry I am not sure if this is a mapping issue or an Umbraco issue, or if I’m misunderstanding how fallbacks work. Does my scenario match your understanding?
Thanks Andrew
I'll have a look into this Andrew. Meantime, could you share the code of your CategoriesGetter
so I can see how you've implemented it please?
Hi Andy The method is like so (basically just attempting to get the Names of the picked content nodes i.e. “category”, there might be multiple picked)
public class CategoriesGetter : IPropertyValueGetter
{
public object GetPropertyValue(IPublishedElement content, string alias, string culture, string segment, Fallback fallback)
{
var categoryIpcs = content.Value<IEnumerable<IPublishedContent>>(alias, fallback: fallback);
return categoryIpcs?.Select(x=>x.Name).ToList();
}
}
When debugging my Spanish site, I can see both cultures on the IPublishedElement content, but after the Value() method is called the IPublishedContent has an object and the culture is English but the Name is null. I was expecting the English node name as there isn’t one published in Spanish.
I was trying to follow some documentation you linked to in an old forum post https://our.umbraco.com/Documentation/Getting-Started/Design/Rendering-Content/#using-fall-back-methods But that is more for the view helper methods. I’m not entirely sure if I need to be on-passing the culture and segment parameters in the Umbraco mapper signature?
Thanks Andrew
Also, not sure if this is relevant, but the property on the doctype has 'Allow varying by culture' enabled, and only the English site is content loaded. So the understanding would be that the Spanish site would 'fallback' to the English site property value?
I'm pretty sure you should be passing along the culture
parameter, yes. So: var categoryIpcs = content.Value<IEnumerable<IPublishedContent>>(alias, culture, fallback: fallback);
.
Otherwise I believe what will be happening is that you are getting the list of categories without specifying the culture, and it'll be using the default.
Thanks Andy - I’ve been trying all number of combinations with the culture and fallback parameters but no amount of trying seems to be getting it to work. I mentioned I wasn’t really sure if this was a core umbraco issue or umbraco mapper so I logged an issue here too https://github.com/umbraco/Umbraco-CMS/issues/7901
Btw do you have an example of how I extend my umbraco mapper property decorator to obtain the culture from the current request context and pass that into the IPropertyValueGetter method as the param?
Thanks for help so far 😊 Andrew
Hi Andrew
I've set up a simple example of the fallbacks, and think it working. Though I did note that both the node for the page AND the nodes for the picked categories need to be set to "allow varying by culture".
Here's the setup I've got:
One document type for a page, set to "allow varying by culture", with a single property called pickedCategories
, that's a multi-node picker that allows picking of nodes of the following type. The property is also set to "allow varying by culture".
The picked document type is set to "allow varying by culture" and it has a single property called categoryName
with the same setting.
I've then created a piece of content in en-US
(the default culture) and picked two categories that are also fully populated in that language. I've picked the same categories and published the same page in a second language (Italian).
For one of the categories I've translated it into Italian, and for the other I haven't.
Italian falls back to US English.
Then I've got this view model:
public class CategoryListViewModel
{
public List<CategoryDetail> PickedCategories { get; set; } = new List<CategoryDetail>();
public class CategoryDetail
{
public string Name { get; set; }
[PropertyMapping(FallbackMethods = new[] { Fallback.Language })]
public string CategoryName { get; set; }
}
}
And this controller:
public class CategoryListController : BaseController
{
public CategoryListController(IUmbracoMapper mapper)
: base(mapper)
{
}
public ActionResult CategoryList(string culture = "")
{
var model = new CategoryListViewModel();
Mapper.Map(CurrentPage, model, culture);
return CurrentTemplate(model);
}
}
And this view:
@inherits Umbraco.Web.Mvc.UmbracoViewPage<TestWebApp80.Models.CategoryListViewModel>
@foreach(var category in Model.PickedCategories)
{
<div>@category.Name - @category.CategoryName</div>
}
When requesting with /categories/?culture=en-US
I see:
Fruit - Fruit
Vegetables - Vegetables
And with /categories/?culture=it
:
Vegetables - Verdure
Fruit - Fruit
Note that "vegetables" is translated but "fruit" isn't, it's falling back.
Maybe you can use this to see why your version isn't working as you'd expect, or perhaps to see if there's a simpler way to do what you need.
It does seem that it's not ideal that I have to make the page "allow varying by culture" - as it means I've got to pick the categories in both languages, whereas ideally they'd be picked once, and the same categories would be displayed in both languages, just translated. But I couldn't get that to work - I think because the first mapping operation (for the pickedCategories
property) will fail if you pass a culture and it doesn't vary by culture.
Hi Andy
Many thanks for taking the time out to test that and verify its working as expected for you.
I have all doctypes set as "allow varying by culture" but yes that is a useful nugget of information 😊
Sebastiaan also set up a working example and explained in https://github.com/umbraco/Umbraco-CMS/issues/7901 that it all appears working for him too.
So at this point I need to work out what is different about my set up (screenshots also added to # 7901 now too) but it all looks the same as what you and Sebastiaan have set up.
Andrew
Also, to you point about “it's not ideal that I have to make the page "allow varying by culture" - as it means I've got to pick the categories in both languages, whereas ideally they'd be picked once, and the same categories would be displayed in both languages, just translated”
Yes, maybe my understanding of what "allow varying by culture" actually means isn’t 100% yet either. My expectation from the docs is that it would mean, assuming in this case that my ‘categories’ field didn’t have "allow varying by culture", is that the value method would return the IPC from the English site, or the Spanish variant of that node (if there was one published) but my site doesn’t seem to do either.
I've realised there's an improvement I could make to my example above, which avoids having the make the page and it's picker property varying by culture, which it so map the picked collection explicitly, only providing the culture there.
I.e. instead of:
public ActionResult CategoryList(string culture = "")
{
var model = new CategoryListViewModel();
Mapper.Map(CurrentPage, model, culture);
return CurrentTemplate(model);
}
This:
public ActionResult CategoryList(string culture = "")
{
var model = new CategoryListViewModel();
Mapper.Map(CurrentPage, model)
.MapCollection(CurrentPage.Value<IEnumerable<IPublishedContent>>("pickedCategories"), model.PickedCategories, culture);
return CurrentTemplate(model);
}
hi Andy - thanks for that extra suggestion. I feel like there's another issue with Umbraco going on where it returns an IPC when arguably it shouldn't be, and that could be contributing to this issue too. I described that here https://github.com/umbraco/Umbraco-CMS/issues/7979