Связь между директивой и обслуживанием - PullRequest
1 голос
/ 12 марта 2020

Я пытаюсь развивать интернационализацию в своем проекте без использования сторонних модулей и столкнулся с проблемой. Вот моя служба перевода:

export class TranslationService {
    private translations: any;

    // load translations for the certain language
    loadTranslations(lang: string) { ... }

    // get translation by key
    get(key: string) {
        return this.translations[key];
    }

}

Вот моя директива, которая заменит текст в теге:

export class I18nDirective implements OnInit {
    @Input() i18n: string;

    constructor(private el: ElementRef,
                private translationService: TranslationService) {}

    ngOnInit() {
        this.el.nativeElement.textContent = this.translationService.get(this.i18n);
    }

}

Пример: <div i18n="global.welcome">This text will be replaced</div>

Проблема: В настоящее время изменение языка вызовет TranslationService для загрузки новых переводов, но директива об этом не знает. Что я должен сделать, чтобы «попросить» директиву использовать новый перевод и заменить его текстом?

Ответы [ 2 ]

1 голос
/ 12 марта 2020

Другим способом является использование декоратора, для ссылки две ссылки

Инжектор зависимости с использованием декораторов

Пример декоратора для отказа от подписки

Ну, декоратор похож на

export function Translation(name:string) {
  return function(constructor) {
    const original = constructor.prototype.ngOnInit;
    const originalDestroy = constructor.prototype.ngOnDestroy;
    const injector = ReflectiveInjector.resolveAndCreate([TranslationService]);
    constructor.prototype.ngOnInit = function() {
      this.translationService = injector.get(TranslationService);
      this.obs$ = this.translationService.observable.subscribe(() => {
        this[name] &&
          this[name].forEach(x => {
            x.el.nativeElement.textContent = this.translationService.get(
              x.i18n
            );
          });
      });
      original &&
        typeof original === "function" &&
        original.apply(this, arguments);
    };
    constructor.prototype.ngOnDestroy = function() {
      this.obs$.unsubscribe();
      originalDestroy &&
        typeof originalDestroy === "function" &&
        originalDestroy.apply(this, arguments);
    };
  };
}

Так что нам нужен только наш компонент, имеющий ViewChildren меток

@ViewChildren(I18nDirective) labels: QueryList<I18nDirective>;

И декорирующий наш компонент:

@Component({
  selector: "my-app",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"]
})
@Translation('labels') //<--this line before declare the class
                       //labels is the name of the variable of ViewChildren
export class AppComponent implements OnInit { ...}

Вы можете увидеть в stackblitz

1 голос
/ 12 марта 2020

Полагаю, вы можете создать Subject в TranslationService и подписаться в директиве, например,

export class TranslationService {
    private subject = new Subject<any>();
    public observable=this.subject.asObservable();

    loadTranslations(lang: string) { 
      ... 
   this.subject.next(true)
    }
   ...
}

export class I18nDirective implements OnInit {
    @Input() i18n: string;

    constructor(private el: ElementRef,
                private translationService: TranslationService) {}

    ngOnInit() {
        this.translationService.observable.pipe(
           startWith(null)
        ).subscribe(()=>{
           this.el.nativeElement.textContent = this.translationService.get(this.i18n);
        })
    }

}

Другой вариант - создать метод setValue в вашей директиве

setValue()
    {
        this.el.nativeElement.textContent = this.translationService.get(this.i18n);
    }

И в вашем компоненте получите директиву, используя ViewChildren

@ViewChildren(I18nDirective) labels: QueryList<I18nDirective>;

при изменении идиомы

changeIdioma() {
    this.translationService.loadTranslations(this.idioma).subscribe(()=>{
      this.labels && this.labels.forEach(x => x.setValue());
    })
  }

Вы можете увидеть в stackblitz (*)

( *) Я поставил два пути, просто разомкнуть строки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...