Angular 2+ localization (i18n) rtl support

2019-03-30 04:11发布

问题:

What is the best practice for adding right to left (rtl) support into a localized Angular 2+ app (e.g. for Hebrew and Arabic languages)? I looked through several tutorials including Internationalization (i18n) but none seem to be covering that. I would expect, for example, the html direction property (e.g. <html dir="rtl">) to be added along with translations defined in 18n attributes at the build step of the app.

回答1:

It is possible to add i18n-dir as described in the docs. So, the best approach I found so far is to add i18n-dir dir="ltr" (where ltr is a default direction) to the root element in the the root component template (e.g. app.component.html) like so:

<div i18n-dir dir="ltr">
    <!-- The rest of the content --> 
</div>

Once you generate translation files a corresponding trans-unit will appear in each of them with source containing default direction, which is ltr in this case. So, you just need to set the target of the unit to rtl for corresponding languages.



回答2:

The problem is the main index.html (and some other files) isn't a template and you can't do some stuff with it (e. g. translation). See this issue.

But because it is an easy process, I tried to do it myself:

  1. Create a translated version of your main index.html and insert it in a folder that named the code of your rtl language (fa in my case):

    src/fa/index.html:

    <!doctype html>
    <html lang="fa" dir="rtl">
    <head>
        <meta charset="utf-8">
        <title>عنوان برنامه</title>
        <base href="/fa/">
    
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" type="image/x-icon" href="favicon.ico">
        <link rel="manifest" href="manifest.json">
        <meta name="theme-color" content="#1976d2">
    
        <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
     <link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet">
    </head>
    <body>
    <app-root></app-root>
    <noscript>برای ادامه استفاده از این برنامه لازم است JavaScript را فعال کنید.</noscript>
    </body>
    </html>
    

    Especially see lang="fa" and dir="rtl" and native texts.

  2. In the related build configurations (in my case: production-fa and fa) in your angular.json file put:

    "index": "src/fa/index.html"
    

Done.


You can do same with other languages (Even ltrs! Because of other changes that we made in index.html).

To better understanding I also insert related build scripts in my package.json file:

    "start-fa": "ng serve --configuration=fa",
    "build-fa": "ng build --configuration=fa",
    "build-prod-fa": "ng build --prod --configuration=production-fa",

Bonus: What about manifest.json file (in case you want an installable PWA)?

The first step like above. Create a translated version in src/fa/manifest.json:

{
    "dir": "rtl",
    "lang": "fa",
    "name": "نام بلند برنامه",
    "short_name": "نام کوتاه",
    "theme_color": ...
    ...

But the second step is a little more difficult. I couldn't find a way to define its path. You can replace the original (src/manifest.json) with this one. You must do it BEFORE the build process starts (not after it by replacing dist/.../manifest.json; because @angular/service-worker needs to know its final state during the build process). So in your package.json:

"build-prod-fa": "cp src/fa/manifest.json src/manifest.json && ng build --prod --configuration=production-fa",

And revert it to its default version (in my case the default language is en) before the default production build:

"build-prod": "cp src/en/manifest.json src/manifest.json && ng build --prod",

Note that about manifest.json just production builds are important. Because serviceWorker is enabled only in these configurations by default (see your angular.json file).


I know this is not an ideal solution. Because you will need to edit your sources (in these two files) in multiple places.



回答3:

As of 2017, it appears that the Angular team is too busy and too few to add right-to-left (rtl) support to the angular-translate module (https://github.com/angular-translate/angular-translate/issues/260).

Not a big deal though, because it's pretty easy to do this with just native JS...

document.body.setAttribute("dir", "rtl");

In my experience, HTML5 does a pretty good job of getting rtl support done correctly.