Since the release of Umbraco 8, building and maintaining multi-language websites has become
a lot easier. In contrast to Umbraco v7, where for each single language version a seperate
content tree had to be created, Language Variants were introduced. Now multilingual content is managed in one node only so no more need for workarounds or perhaps the need to work with external packages to fulfill this need.

In this post you'll be presented with a way to navigate throughout variants easily by building
a variants toggle. The objective is to not create a redirect to the root of that specific language but
directly to the translated page and only if it's published content.

We'll assume that, for the sake of convenience, you've already got your document types and
desired cultures in place.

As Umbraco 8 now works perfectly with a built-in dependecy injection model the following snippet
can be injected anywhere. Presumably in a kind of navigation controller or anywhere you want
the language toggle to appear.

First up the UmbracoContext needs to be accesed to give access to all registered domains and
the current page that is requested (PublishedRequest).

public class LanguageVariantService {
    private readonly IUmbracoContextFactory _context;

    public LanguageVariantService (IUmbracoContextFactory context) {
        _context = context;
    }

    public Dictionary<string, string> GetVariants() {

    }
}

The method GetVariants() will do all the hard work for us. It will return a dictionary
where 'Key' presents the variant's culture key and 'Value' the absolute path.

public Dictionary<string, string> GetVariants() {
    Dictionary<string, string> paths = new Dictionary<string, string>();
    using (var cref = _context.EnsureUmbracoContext()) {
        IPublishedContent currentPage = cref.UmbracoContext.PublishedRequest.PublishedContent;

        IEnumerable domains = cref.UmbracoContext.Domains.GetAll(false);
        IEnumerable cultures = domains.Select(x => x.Culture.Name.ToLower());
        IReadOnlyDictionary<string, PublishedCultureInfo> variants = currentPage.Cultures;

        foreach (var currentCulture in variants) {
            if (cultures.Contains(currentCulture.Value.Culture)) {
                paths.Add(currentCulture.Key, cref.UmbracoContext.Url(currentPage.Id, currentCulture.Value.Culture));
            } else {
                paths.Add(currentCulture.Key, cref.UmbracoContext.Url(domains.FirstOrDefault(d => d.Culture.TwoLetterISOLanguageName == currentCulture.Value.Culture).ContentId));
            }
        }
    }
return paths; }

In this method, for every present variant of the current node, a link to that specific translation will be added to the lists of toggles. Otherwise, if there is no translation available, a fallback will be added to the homepage of that specific culture. 

Whether or not you choose to use dependecy injection (DI) is up to you. You could also make a static class with static methods to call from the controller.

When using DI you'll need to add the service to the pool. The following snippet will register the LanguageVariantService as part of the dependecy injection model.

[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class MyComposer : IUserComposer {
	public void Compose(Composition composition) {
		composition.Components().Append(MyComponent);
		composition.Register(LanguageVariantService);
	}
}

public class MyComponent : IComponent {
	public MyComponent() {}
	public void Initialize() {}
	public void Terminate() {}
}

If you have any questions or remarks please feel free to contact FungyBytes via contact@fungybytes.com or give us a tweet @fungybytes

An alternative to Google Site Search 2

Why giving good development time estimates is hard

For proper functioning and anonymous analysis of our website, we place functional and analytical cookies that have no or minor consequences for your privacy. These cookies may collect data outside of our website. By using this website you agree to the placement of these cookies.