cloudscribe/cloudscribe.Web.Navigation

Please implement Localization with IStringLocalizer

Closed this issue · 7 comments

It should be trivial:

https://github.com/joeaudette/cloudscribe.Web.Navigation/blob/2d51a710926b5dc58a58cc3f01e3bb7721b1c290/src/cloudscribe.Web.Navigation/TreeBuilders/XmlNavigationTreeBuilder.cs

Pass in constructor IStringLocalizer and here:

And in:

https://github.com/joeaudette/cloudscribe.Web.Navigation/blob/2d51a710926b5dc58a58cc3f01e3bb7721b1c290/src/cloudscribe.Web.Navigation/TreeBuilders/NavigationTreeXmlConverter.cs

Instead of:

writer.WriteAttributeString("text", node.Value.Text);

Use:

writer.WriteAttributeString("text", stringLocalizer[node.Value.Text]);

Or create another attribute so we don't reuse "text" attribute for that.

I can't use it if it doesn't integrate localization.

You could download the views and inject an IStringLocalizer into the views and use it to localize right in the view.

We should not localize it when building the tree of nodes, it can be potentially very large so we cache it, if we localized it there it would cache whatever langauge was for the first request. Also that is just the root level treebuilder, it may invoke child tree builders, ie in cloudscribe.SimpleContent we have PagesNavigationTreeBuilder which adds nodes from cms pages in the database. XmlNavigationTreeBuilder invokes PagesNavigationTreeBuilder to add its sub tree to an xml node. So there could be other treebuilders outside our control, treebuilder is not the right place to do the localization.

I looked into the possibility of passing

IStringLocalizer<NavigationString> 

into the NavigationViewModel, but the problem is IStringLocalizer has be of some T and if I make class like NavigationStrings and pass in IStringLocalizer of that you would not be able to override it locally in the web app because class library localization is different than main app localization unless you use something like https://github.com/joeaudette/cloudscribe.Web.Localization

if you make your own IStringLocalizer in your own web app and inject that into the navigation views it should work assuming you create the needed resx files.

So I think no changes are needed in the cloudscribe.Web.Navigation library, only custom views are needed for you to localize the menu.

Can you provide and example please?

https://github.com/joeaudette/cloudscribe.Web.Navigation/tree/master/src/cloudscribe.Web.Navigation/Views/Shared/Components/Navigation

https://github.com/joeaudette/cloudscribe.Web.Navigation/blob/master/src/cloudscribe.Web.Navigation/NavigationViewModel.cs

I have seen these files but I don't know what I should do.

I know how to inject my IStringLocalizer or IViewerLocalizer but what output should I replace?

I see in "BootstrapBreadcrumbs.cshtml" calls to:

@Model.AdjustText(node)
@n.Text

I'm saying download those views into your app and then it will use the local ones instead of embedded ones. Then inject your own IStringLocalizerlike this:

@using Microsoft.Extensions.Localization;
@using cloudscribe.Web.Navigation
@model NavigationViewModel
@inject<IStringLocalizer<yournamespace.yourclass> localizer
@if (Model.CurrentNode != null && Model.ParentChain.Count > 1)
{
    <ul class="breadcrumb">
    @foreach (var node in Model.ParentChain)
    {
        if (!Model.ShouldAllowView(node)) { continue; }
        if (node.EqualsNode(Model.CurrentNode))
        {
            if (Model.TailCrumbs != null)
            {
                <li><a href="@Url.Content(Model.AdjustUrl(node))">@localizer[Model.AdjustText(node)]</a><span class="divider"></span></li>
            }
            else
            {
                <li class="active">@Model.AdjustText(node)</li>
            }
          }
          else
          {
              <li><a href="@Url.Content(Model.AdjustUrl(node))">@localizer[Model.AdjustText(node)]</a><span class="divider"></span></li>
            }
        }
        @if (Model.TailCrumbs != null)
        {
             foreach (var n in Model.TailCrumbs)
              {
                  <li class="active">@localizer[n.Text]</li>
              }
         }
        </ul>
    }

Note that AdjustText only changes the text if you added a node adjuster for that node key inside a controller action, it is mainly a way of changing breadcrumb text from inside a controller action. either way you just localize the result and if you do adjust it need to have the adjusted text in your resx. But it is not adjusting anything unless you make it do so from your own code.

I don't have time to do it right now but tomorrow I will try to find time to update the demo app with an example of localization using the technique shown above.

I have implemented menu localization in the demo app. I only copied the views that are actually used in the demo into the demo app, so I didn't localize every view included in the embedded resources just the ones currently used in the demo app. I added a language switcher to make it easy to see that it works.

Thank you!

I'm going to learn how to use it and I'll get back to you in case if I face a problem.