You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何创建基于Rest Call的Angular 5 i18n自定义指令

Building a Custom i18n Directive with REST-backed Translation Service

Let's walk through creating a custom i18n directive that fetches translation JSON via a REST call and stores the data in a dedicated service. I'll use Angular for this example (since directives are a core feature there), but the core concepts can adapt to other frameworks like Vue or React with minor tweaks.


1. First: Create the Translation Service

This service will be our single source of truth for translation data—handling API calls, storing translations, and providing methods to retrieve strings.

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class TranslationService {
  // Holds the current translations (key-value pairs)
  private translations: Record<string, string> = {};
  // Subject to notify when language/translations change
  private languageChanged = new BehaviorSubject<string>('en');

  constructor(private http: HttpClient) {}

  // Fetch translations from REST API and store them
  fetchTranslations(language: string = 'en'): Observable<Record<string, string>> {
    // Replace with your actual API endpoint
    return this.http.get<Record<string, string>>(`/api/translations/${language}`).pipe(
      (response) => {
        this.translations = response;
        this.languageChanged.next(language);
        return response;
      }
    );
  }

  // Get a translation by key, fall back to key if not found
  getTranslation(key: string): string {
    return this.translations[key] || `[${key}]`;
  }

  // Subscribe to language change events
  onLanguageChange(): Observable<string> {
    return this.languageChanged.asObservable();
  }
}

Key points here:

  • We use a BehaviorSubject to broadcast language changes, so our directive can react dynamically.
  • The fetchTranslations method caches the response directly in the service—no need to refetch unless the language changes.
  • A fallback ([${key}]) ensures we don't show empty content if a translation is missing.

2. Build the Custom i18n Directive

This directive will attach to DOM elements, pull the translation key from an attribute, and replace the element's content with the translated string. It'll also listen for language changes to update content automatically.

import { Directive, ElementRef, Input, OnInit, OnDestroy } from '@angular/core';
import { TranslationService } from './translation.service';
import { Subscription } from 'rxjs';

@Directive({
  selector: '[appI18n]' // Use this attribute in your templates
})
export class I18nDirective implements OnInit, OnDestroy {
  @Input('appI18n') translationKey!: string;
  private languageSub?: Subscription;

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

  ngOnInit(): void {
    // Set initial translation
    this.updateTranslation();
    // Subscribe to language changes to update content
    this.languageSub = this.translationService.onLanguageChange().subscribe(() => {
      this.updateTranslation();
    });
  }

  private updateTranslation(): void {
    const translatedText = this.translationService.getTranslation(this.translationKey);
    this.el.nativeElement.textContent = translatedText;
  }

  ngOnDestroy(): void {
    // Clean up subscription to avoid memory leaks
    this.languageSub?.unsubscribe();
  }
}

Key details:

  • The @Input grabs the translation key from the template attribute (e.g., [appI18n]="'welcome.greeting'").
  • updateTranslation handles replacing the element's text content—you could extend this to handle attributes like placeholder or title too.
  • We clean up the subscription in ngOnDestroy to prevent memory leaks, which is crucial for long-lived apps.

3. Initialize and Use the Directive

Step 3.1: Load Initial Translations

In your root component (e.g., AppComponent), call the fetchTranslations method to load the default language's data when the app starts:

import { Component, OnInit } from '@angular/core';
import { TranslationService } from './translation.service';

@Component({
  selector: 'app-root',
  template: `
    <h1 [appI18n]="'home.title'"></h1>
    <p [appI18n]="'home.description'"></p>
    <button (click)="switchToSpanish()">Switch to Spanish</button>
  `
})
export class AppComponent implements OnInit {
  constructor(private translationService: TranslationService) {}

  ngOnInit(): void {
    // Load English translations on app start
    this.translationService.fetchTranslations('en').subscribe();
  }

  switchToSpanish(): void {
    // Switch to Spanish and fetch new translations
    this.translationService.fetchTranslations('es').subscribe();
  }
}

Step 3.2: Use the Directive in Templates

Just add the [appI18n] attribute to any element, passing the translation key as the value:

<h2 [appI18n]="'dashboard.welcome'"></h2>
<button [appI18n]="'actions.save'"></button>

Bonus Enhancements

  • Add Loading States: Modify the service to track loading status, then update the directive to show a spinner or placeholder while translations are fetching.
  • Support Attribute Translations: Extend the directive to handle attributes like placeholder or title (e.g., [appI18nPlaceholder]="'form.email.placeholder'").
  • Cache Translations: Store fetched translations in localStorage so users don't re-download them on subsequent visits.

内容的提问来源于stack exchange,提问作者Vijayabaskaran M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:32:06