根据用户的语言

时间:2017-01-11 23:16:02

标签: angular angular2-services

我有一个Angular2应用程序,它需要支持多种语言。其中一些语言可能是RTL(即波斯语),有些语言可能是LTR(即英语)。除了本地化字符串之外,我还需要根据语言的方向设置组件的样式。

现在using this helper,我可以有两个单独的文件(即app-rtl.scss& app-ltr.scss),它们都导入一个单独的scss文件(即app.scss),它允许我写我的scss代码在一个地方,并自动输出两个文件;每个方向一个。

问题是现在我需要以某种方式根据用户的语言引用合适的css文件。因此,如果用户的语言是英语,那么我应该 标头中有<link href="app-ltr.css" rel="stylesheet">,如果是RTL,则为<link href="app-rtl.css" rel="stylesheet">。此外,我想为我的项目添加bootstrap,并且还有两个不同的LTR和RTL输出文件。

有没有干净的方法来实现这个功能?

我尝试了什么:

我创建了两个虚拟组件(一个用于LTR,一个用于RTL),没有任何模板,然后使用styleUrls分配相应的scss文件并设置encapsulation: ViewEncapsulation.None,使其成为全局样式。然后我使用* ngIf在我的根组件模板中初始化它们,并检查语言是否为LTR。

这适用于第一页加载,因为只有一个组件(比如组件LTR)处于活动状态,但只要你更改语言(即第二个组件(RTL)变为活动状态,因此LTR被删除),那么与LTR关联的样式保留在页面上,不会被删除。那么你的页面上既有RTL又有LTR样式,这是不可取的。

4 个答案:

答案 0 :(得分:3)

您需要从浏览器中有条件地添加或删除样式:

添加

convert main.png mask.png -background none -gravity center -geometry +0-17 -compose dstin -composite -trim +repage result2.png

并删除

loadIfNot(url,cssId){

     if (!document.getElementById(cssId)){
        var head  = document.getElementsByTagName('head')[0];
        var link  = document.createElement('link');
        link.id   = cssId;
        link.rel  = 'stylesheet';
        link.type = 'text/css';
        link.href = url;
        link.media = 'all';
        head.appendChild(link);
    }else{
        document.getElementById(cssId).disabled = false;///i fit's already there, enable it
    }

  }

disable(cssId){ document.getElementById(cssId).disabled = true } Disable是因为浏览器倾向于缓存您的样式,为了使它们启用或禁用,您需要更改该属性

答案 1 :(得分:2)

根据@marbug的回答,我会尝试使用服务并动态加载和卸载“语言”组件。

将如下工作

import { Injectable, ViewChild, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { LanguageAComponent } from "./language-a.component";
import { LanguageBComponent } from "./language-b.component";
import { Router } from '@angular/router';

@Injectable()
export class LanguageComponentService {
    componentRef: any;

    constructor(private componentFactoryResolver: ComponentFactoryResolver, private router: Router
    ) { }

    loadLanguageA(viewContainerRef: ViewContainerRef) {
        let componentFactory = this.componentFactoryResolver.resolveComponentFactory(LanguageAComponent);
        this.componentRef = viewContainerRef.createComponent(componentFactory);

    }

   loadLanguageB(viewContainerRef: ViewContainerRef) {
        let componentFactory = this.componentFactoryResolver.resolveComponentFactory(LanguageBComponent);
        this.componentRef = viewContainerRef.createComponent(componentFactory);

    }


    unloadComponent() {
        this.componentRef.destroy();
    }

}

答案 2 :(得分:1)

也许您可以根据用户语言的方向有条件地将课程添加到<body>?例如,<body ng-class="{'dir-ltr': ltr, 'dir-rtl': !ltr}">。当然,您必须分别在.dir-ltr.dir-rtl中包装所有sass样式,以便DOM的其余部分使用正确的样式集。这假定在加载状态时解析语言方向,并且<body>也在角度应用程序的范围内。

答案 3 :(得分:1)

1)我建议您使用延迟加载的模块而不是动态css文件(请查看official Angular docs以获取更多信息)

2)我还建议将当前语言放到某个服务中,将服务注入适当的组件并使用所需的css类。优点:

2.1)组件样式不依赖于body元素 - 只是服务中的值 - 这对于单元测试来说更好/更正

2.2)当它不足以使用LTR与RTL类时,可能会有用例,但是对于特定语言使用一些额外的类(例如,表列可能具有不同的英语,德语等语言宽度)

3)动态加载css可能会导致UI问题:首先应用初始样式然后他们跳转&#39;到&#34;其他&#34;样式(加载适当的css文件时)。所以1)&amp; 2)好多了(恕我直言)

更新2017-06-07 (只是为了更清楚)

app-routing.module 可能就像:

import { NgModule }             from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

export const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full'},
    { 
        path: 'home', 
        loadChildren: 'app/my-home-page/my-home-page.module#MyHomePageModule' 
    },
    ...
];

@NgModule({
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
})
export class AppRoutingModule {}

my-global.service 可能就像:

@Injectable()
export class MyGlobalService {
    currentLanguageDirection: string; // i.e. 'ltr' or 'rtl'
    currentLanguage: string;          // i.e. 'en', 'de', 'ru', etc
}

my-home-page.component.ts 可以是:

export class MyHomePageComponent {
    ...

    constructor(
        private myGlobalService: MyGlobalService, // inject global service
        ...
    ) {
    }

    ...
}

my-home-page.component.html 可以是:

<div [ngSwitch]="myGlobalService.currentLanguageDirection">
    <my-home-page-rtl *ngSwitchCase="'rtl'"></my-home-page-rtl>
    <my-home-page-ltr *ngSwitchDefault></my-home-page-ltr>
</div>

即。可以使用两个附加组件: my-home-page-ltr my-home-page-rtl 。他们将有单独的scss | css文件。

如果你需要德语的独特实现,那么 my-home-page-ltr.component.html 可以是:

<div [ngSwitch]="myGlobalService.currentLanguage">
    <my-home-page-ltr-de *ngSwitchCase="'de'"></my-home-page-ltr-de>
    <div *ngSwitchDefault>
        ... (default html code)
    </div>
</div>

即。一个单独的 my-home-page-ltr-de 组件将为德语提供单独的scss | css。

P.S。请注意,您可以通过在@Component中设置html文件来重用它们:

@Component({
    selector: 'my-home-page...',
    templateUrl: './my-home-page....html', // <-------------- reuse here
    styleUrls: ['./my-home-page....scss']
})

P.P.S。我建议使用手动创建/删除组件。使用 ngSwitch ngIf 是一种更正确的方式(恕我直言)

P.P.P.S。优点如下。组件及其子组件应自动加载/释放角度。语言切换将以非常快的速度执行,因为当前组件已加载其子项 - 您无需在语言切换期间加载所有组件的样式。