3
votes

I have an angular application that was supporting only one locale (French). I then evolved the application to support another language where the same components are available under another root route /ar

My problem now is that the application uses a lot of [routerLink]="['some', 'thing'] and other router.navigate('...'). Instead of i18n all links, I'm thinking of a smart way to perform the url translation.

I have done the following :

this.translateService.onLangChange
.combineLatest(this.router.events)
.subscribe(([langEvent, event]) => {

    if (event instanceof NavigationStart) {
        let currentUrl = event.url;

        let locale = Locale.getLocaleByShortcut(langEvent.lang);

        if (locale) {
            if (locale.isArabic()) {
                if (!ContextUtils.isArabicUrl(currentUrl)) {
                    this.router.navigate(['/ar/' + currentUrl], {queryParams: this.route.snapshot.queryParams});
                }
            } else {
                if (ContextUtils.isArabicUrl(currentUrl)) {
                    let url = ContextUtils.frenchifyUrl(currentUrl);
                    this.router.navigate([url], {queryParams: this.route.snapshot.queryParams});
                }
            }
        }

    }

    if (event instanceof NavigationEnd) {

        if (Config.IS_WEB()) {
            $(document).ready(() =>
                setTimeout(() => {
                    Materialize.updateTextFields()
                }, 10)
            );
        }

        this.scrollToTop();
    }
});

The problem is that this solutions does not work perfectally especially with queryParams that are kept when navigating from an url having queryParams to another that does not have them.

Is there any way smart way to prefix the UrlSegments the router is navigating to ?

Example <a[routerLink]="['some', 'thing']></a> ----> redirect to : /ar/some/thing when AR locale is set. And to /some/thing when not.

Thank you.

1
If you change your routes so that all routes have a language parameter, then relative routes would work. When you make the prefix optional, then /some/thing can not relatively change to /ar/some/thing. If you have /en/some/thing you can relatively change to /ar/some/thing. The only other option is to make the language a query parameter so that the routing itself doesn't change. - Reactgular
How can I change /en/some/thing to /ar/some/thing - Radouane ROUFID
There isn't a feature in Angular to take a URL break it down into it's parts, change a particular parameter and generate the new URL. I really wish there was such a thing. You'll simply have to take the current URL, do a string replace and navigateByUrl. Handling the edge cases for query parameters and such. It's a pain, but I don't have a quick fix for you. - Reactgular
I already do this when the user changes the locale. But I wanted something more elegant. - Radouane ROUFID
What did you use for translating your application ? i18n from angular or other library ? - Nour

1 Answers

4
votes

Something is missing

As far as I know, Angular offers nothing that unites the locales into a single website. Angular demands you to make multiple builds each with a specified locale parameter. In essence they are different websites hosted on different addresses.

There are other open-source translation solutions that use pipes. But I personally am reluctant to use a 3rd party solution for something that affects every single page of your app.

I always had the feeling that a landing page would be an effective improvement. That would be a page which is an index.html that links these sites together. e.g. you would then have a setup like this:

index.html --> root landing page
en/
   index.html --> your angular site in English
   ...
fr/
   index.html --> your angular site in French.
   ...

The main improvement would be, that you can welcome all visitors on the same address and seamlessly forward them from there.

Open source solution

I created a gist, which you can find here, which does exactly this. It's a configurable landing page. It is intentionally written in just plain html and js. The aim is to make this your root index.html.

So, you can easily host everything under 1 root domain name. But if the user decides to switch from one locale to another, that still means a full reload of memory though. But under normal circumstances a user only changes language once.

Basic working

So, if somebody just navigates to http://example.com, it will try to determine the language of that user in several ways (e.g. browser language, ...), and once it knows the language, it will use a predefined routing configuration to redirect the user to the right URL. And while forwarding the request, it will also forward subpaths. (little more about that in the last part of my answer).

But it also caches languages in the local storage, for your next visit.

Now, if you want your user to select a language, then (e.g. on your page navbar or in a settings pane) you can add a link to e.g. http://example.com/?locale=en. A language specified in this fashion (i.e. using a query parameter), will have a higher priority than browser languages or previously stored languages.

To configure the routing mechanism, you should set a default locale which will act as a fallback, and provide a route mapping.

var defaultLocale = 'en';
var routing = {
  "en": 'https://example.com/en',
  "fr": 'https://example.com/fr'
  "en-uk": 'https://example.com/uk',
};

The script will prefer a perfect locale hit. But if that does not produce a match, it will try to use just the language. (always define them in lowercase though).

How are subpaths handled

Specific for your question, how does the forwarding work.

No matter which webserver you use, with angular a webserver should always be configured so that all subpath requests are also forwarded to your index.html. (That should already be the case with your current setup.)

Our landing page html file works in that same way, it also receives the full path. So, when it wants to extract subpaths, it actually has access to the full path. And it will extract a subpath by cutting out everything behind the third /.

So, if you host this landing page on http://example.com and you have the above routing config. Then if somebody navigates to http://example.com/foo, and that user has an English locale, then he will be redirected to http://example.com/en/foo.