Angular国际化与本地化

国际化(i18n)和本地化(l10n)是构建全球可用应用的关键技术,让应用能够适应不同语言、地区和文化习惯。

概念区分:
  • 国际化(i18n):设计应用以支持多语言和区域格式
  • 本地化(l10n):为特定语言和地区适配内容
  • 全球化(g11n):国际化 + 本地化的完整过程

多语言演示

点击切换语言查看实时翻译效果

欢迎词: 欢迎来到我们的应用!
日期: 2024年1月15日 星期一
货币: ¥1,234.56
数字: 1,234,567.89
复数: 您有3条新消息
性别: 他分享了照片

1. Angular内置i18n

1.1 基本配置

// angular.json - 配置多语言构建
{
  "projects": {
    "my-app": {
      "i18n": {
        "sourceLocale": "zh-Hans",  // 源语言
        "locales": {
          "en": "src/locale/messages.en.xlf",      // 英语翻译
          "es": "src/locale/messages.es.xlf",      // 西班牙语
          "ja": "src/locale/messages.ja.xlf",      // 日语
          "fr": "src/locale/messages.fr.xlf"       // 法语
        }
      },
      "architect": {
        "build": {
          "configurations": {
            "en": {
              "localize": ["en"],    // 构建英语版本
              "outputPath": "dist/my-app/en/"
            },
            "es": {
              "localize": ["es"],    // 构建西班牙语版本
              "outputPath": "dist/my-app/es/"
            }
          }
        },
        "serve": {
          "configurations": {
            "en": {
              "browserTarget": "my-app:build:en"  // 服务英语版本
            }
          }
        }
      }
    }
  }
}
// package.json - 添加构建脚本
{
  "scripts": {
    "build:zh": "ng build --localize",  // 构建所有语言
    "build:en": "ng build --configuration=en",
    "build:es": "ng build --configuration=es",
    "serve:en": "ng serve --configuration=en",
    "extract-i18n": "ng extract-i18n --output-path src/locale"
  }
}

// 提取翻译字符串
ng extract-i18n --output-path src/locale

// 构建特定语言版本
ng build --configuration=ja

// 构建所有语言版本
ng build --localize

1.2 标记可翻译文本

<!-- 基本翻译标记 -->
<h1 i18n>欢迎来到我的应用</h1>
<p i18n>这是一个多语言演示应用</p>

<!-- 带有描述的翻译 -->
<button i18n="按钮描述|提交按钮@@submitButton">
  提交
</button>

<!-- 带有上下文的翻译 -->
<span i18n="用户菜单|欢迎词">欢迎,{{user.name}}</span>

<!-- 复数形式 -->
<span i18n>
  {count, plural,
  =0 {没有消息}
  =1 {有一条消息}
  other {有{{count}}条消息}}
</span>

<!-- 选择形式(性别) -->
<span i18n>
  {gender, select,
  male {他}
  female {她}
  other {他们}}
  分享了照片
</span>

<!-- 嵌套翻译 -->
<div i18n>
  价格: <strong>{{price | currency}}</strong>
  数量: <strong>{{quantity}}</strong>
</div>

<!-- 属性翻译 -->
<input
  [placeholder]="'搜索...'"
  i18n-placeholder
  i18n-title="输入框标题|搜索输入@@searchTitle"
  title="输入关键字搜索">

<img
  [src]="logoUrl"
  i18n-alt
  alt="应用Logo">

1.3 XLIFF翻译文件

翻译工作流程:
1. 提取: ng extract-i18n → messages.xlf
2. 翻译: 编辑XLIFF文件
3. 构建: ng build --localize
4. 部署: 不同语言的构建版本

XLIFF文件结构:
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="zh-Hans" datatype="plaintext">
    <body>
      <trans-unit id="welcomeHeader">
        <source>欢迎来到我的应用</source>
        <target>Welcome to My App</target>
        <note>首页标题</note>
      </trans-unit>
      <trans-unit id="submitButton">
        <source>提交</source>
        <target>Submit</target>
      </trans-unit>
    </body>
  </file>
</xliff>
<!-- messages.en.xlf -->
<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
  <file source-language="zh-Hans" target-language="en" datatype="plaintext">
    <body>
      <!-- 简单文本翻译 -->
      <trans-unit id="welcomeHeader" datatype="html">
        <source>欢迎来到我的应用</source>
        <target>Welcome to My Application</target>
        <context-group purpose="location">
          <context context-type="sourcefile">src/app/app.component.html</context>
          <context context-type="linenumber">1</context>
        </context-group>
      </trans-unit>

      <!-- 带插值的翻译 -->
      <trans-unit id="userGreeting" datatype="html">
        <source>欢迎,<x id="INTERPOLATION" equiv-text="{{user.name}}"/></source>
        <target>Welcome, <x id="INTERPOLATION" equiv-text="{{user.name}}"/></target>
      </trans-unit>

      <!-- 复数形式 -->
      <trans-unit id="messageCount" datatype="html">
        <source>{VAR_PLURAL, plural, =0 {没有消息} =1 {有一条消息} other {有<x id="INTERPOLATION" equiv-text="{{count}}"/>条消息}}</source>
        <target>{VAR_PLURAL, plural, =0 {No messages} =1 {One message} other {<x id="INTERPOLATION" equiv-text="{{count}}"/> messages}}</target>
      </trans-unit>

      <!-- 选择形式 -->
      <trans-unit id="genderMessage" datatype="html">
        <source>{VAR_SELECT, select, male {他} female {她} other {他们}}分享了照片</source>
        <target>{VAR_SELECT, select, male {He} female {She} other {They}} shared a photo</target>
      </trans-unit>
    </body>
  </file>
</xliff>

2. ngx-translate库

对于需要运行时语言切换的应用,推荐使用ngx-translate库。

# 安装ngx-translate
npm install @ngx-translate/core @ngx-translate/http-loader
// app.module.ts - 配置ngx-translate
import { NgModule } from '@angular/core';
import { HttpClientModule, HttpClient } from '@angular/common/http';
import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';

// 创建翻译加载器
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

@NgModule({
  imports: [
    HttpClientModule,
    TranslateModule.forRoot({
      defaultLanguage: 'zh',
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    })
  ],
  exports: [TranslateModule]
})
export class AppModule { }
// app.component.ts - 初始化翻译
import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html'
})
export class AppComponent {
  constructor(private translate: TranslateService) {
    // 设置支持的语言
    translate.addLangs(['zh', 'en', 'es', 'ja', 'fr']);

    // 设置默认语言
    translate.setDefaultLang('zh');

    // 获取浏览器语言
    const browserLang = translate.getBrowserLang();

    // 使用浏览器语言或默认语言
    const useLang = translate.getLangs().includes(browserLang)
      ? browserLang
      : 'zh';

    translate.use(useLang);
  }

  // 切换语言
  switchLanguage(lang: string): void {
    this.translate.use(lang);
    localStorage.setItem('userLang', lang);
  }
}

2.1 翻译文件结构

// assets/i18n/zh.json - 中文翻译
{
  "HEADER": {
    "TITLE": "我的应用",
    "WELCOME": "欢迎,{{name}}",
    "LOGIN": "登录",
    "LOGOUT": "退出"
  },
  "HOME": {
    "TITLE": "首页",
    "DESCRIPTION": "这是一个多语言演示应用",
    "FEATURES": "主要特性",
    "FEATURES_LIST": [
      "多语言支持",
      "响应式设计",
      "高性能",
      "易于使用"
    ]
  },
  "USER": {
    "PROFILE": "用户资料",
    "SETTINGS": "设置",
    "MESSAGES": {
      "ZERO": "没有消息",
      "ONE": "有一条新消息",
      "OTHER": "有{{count}}条新消息",
      "GENDER": {
        "MALE": "他有{{count}}条消息",
        "FEMALE": "她有{{count}}条消息",
        "OTHER": "他们有{{count}}条消息"
      }
    }
  },
  "BUTTONS": {
    "SAVE": "保存",
    "CANCEL": "取消",
    "DELETE": "删除",
    "CONFIRM": "确认"
  },
  "VALIDATION": {
    "REQUIRED": "此字段为必填项",
    "EMAIL": "请输入有效的邮箱地址",
    "MIN_LENGTH": "最少需要{{min}}个字符",
    "MAX_LENGTH": "最多允许{{max}}个字符"
  }
}
// assets/i18n/en.json - 英文翻译
{
  "HEADER": {
    "TITLE": "My Application",
    "WELCOME": "Welcome, {{name}}",
    "LOGIN": "Login",
    "LOGOUT": "Logout"
  },
  "HOME": {
    "TITLE": "Home",
    "DESCRIPTION": "This is a multilingual demo application",
    "FEATURES": "Main Features",
    "FEATURES_LIST": [
      "Multilingual support",
      "Responsive design",
      "High performance",
      "Easy to use"
    ]
  },
  "USER": {
    "PROFILE": "User Profile",
    "SETTINGS": "Settings",
    "MESSAGES": {
      "ZERO": "No messages",
      "ONE": "One new message",
      "OTHER": "{{count}} new messages",
      "GENDER": {
        "MALE": "He has {{count}} messages",
        "FEMALE": "She has {{count}} messages",
        "OTHER": "They have {{count}} messages"
      }
    }
  },
  "BUTTONS": {
    "SAVE": "Save",
    "CANCEL": "Cancel",
    "DELETE": "Delete",
    "CONFIRM": "Confirm"
  },
  "VALIDATION": {
    "REQUIRED": "This field is required",
    "EMAIL": "Please enter a valid email address",
    "MIN_LENGTH": "Minimum {{min}} characters required",
    "MAX_LENGTH": "Maximum {{max}} characters allowed"
  }
}

2.2 在模板中使用翻译

<!-- 使用translate管道 -->
<h1>{{ 'HEADER.TITLE' | translate }}</h1>
<p>{{ 'HOME.DESCRIPTION' | translate }}</p>

<!-- 带参数的翻译 -->
<span>{{ 'HEADER.WELCOME' | translate:{name: userName} }}</span>

<!-- 复数形式 -->
<span>
  {{ 'USER.MESSAGES.ZERO' | translate }}
  {{ 'USER.MESSAGES.ONE' | translate }}
  {{ 'USER.MESSAGES.OTHER' | translate:{count: messageCount} }}
</span>

<!-- 使用translate指令 -->
<button translate>BUTTONS.SAVE</button>
<h2 translate>HOME.TITLE</h2>

<!-- 属性翻译 -->
<input
  [placeholder]="'VALIDATION.EMAIL' | translate"
  [title]="'VALIDATION.REQUIRED' | translate">

<!-- 复数指令 -->
<span
  [translate]="'USER.MESSAGES.ZERO'"
  [translateParams]="{count: messageCount}">
</span>

<!-- 复杂结构翻译 -->
<ul>
  <li *ngFor="let feature of 'HOME.FEATURES_LIST' | translate">
    {{feature}}
  </li>
</ul>

<!-- 动态键名 -->
<span>{{ translationKey | translate }}</span>

2.3 在组件类中使用翻译

// translation.service.ts - 翻译服务
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class TranslationService {
  constructor(private translate: TranslateService) {}

  // 获取当前语言
  getCurrentLanguage(): string {
    return this.translate.currentLang;
  }

  // 获取支持的语言列表
  getSupportedLanguages(): string[] {
    return this.translate.getLangs();
  }

  // 设置语言
  setLanguage(lang: string): Observable<any> {
    return this.translate.use(lang);
  }

  // 获取翻译(同步)
  getTranslation(key: string, params?: any): string {
    return this.translate.instant(key, params);
  }

  // 获取翻译(异步)
  getTranslationAsync(key: string, params?: any): Observable<string> {
    return this.translate.get(key, params);
  }

  // 获取JSON文件的所有翻译
  getTranslationFile(lang: string): Observable<any> {
    return this.translate.getTranslation(lang);
  }

  // 重新加载翻译
  reloadTranslations(): void {
    this.translate.reloadLang(this.translate.currentLang);
  }

  // 监听语言变化
  onLanguageChange(): Observable<string> {
    return this.translate.onLangChange;
  }
}

// 在组件中使用
@Component({
  selector: 'app-example',
  templateUrl: './example.component.html'
})
export class ExampleComponent implements OnInit {
  translatedText: string = '';

  constructor(
    private translate: TranslateService,
    private translationService: TranslationService
  ) {}

  ngOnInit(): void {
    // 方式1:使用translate服务
    this.translate.get('HOME.TITLE').subscribe((translation: string) => {
      this.translatedText = translation;
    });

    // 带参数的翻译
    this.translate.get('HEADER.WELCOME', {name: '张三'})
      .subscribe((text: string) => {
        console.log(text); // "欢迎,张三"
      });

    // 监听语言变化
    this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
      console.log('语言已切换:', event.lang);
      this.updateTranslations();
    });
  }

  // 获取多个翻译
  getMultipleTranslations(): void {
    this.translate.get(['BUTTONS.SAVE', 'BUTTONS.CANCEL'])
      .subscribe((translations: any) => {
        console.log('保存:', translations['BUTTONS.SAVE']);
        console.log('取消:', translations['BUTTONS.CANCEL']);
      });
  }

  // 使用服务方法
  updateTranslations(): void {
    this.translatedText = this.translationService.getTranslation('HOME.TITLE');
  }
}

3. 日期、时间、数字格式化

日期格式化
  • 短格式: {{ '2024-01-15' | date:'short' }}
  • 中格式: {{ '2024-01-15' | date:'medium' }}
  • 长格式: {{ '2024-01-15' | date:'long' }}
  • 完整格式: {{ '2024-01-15' | date:'full' }}
  • 自定义: {{ '2024-01-15' | date:'yyyy-MM-dd' }}
时间格式化
  • 短时间: {{ '14:30:00' | date:'shortTime' }}
  • 中时间: {{ '14:30:00' | date:'mediumTime' }}
  • 长时间: {{ '14:30:00' | date:'longTime' }}
  • 完整时间: {{ '14:30:00' | date:'fullTime' }}
货币格式化
  • 人民币: {{ 1234.56 | currency:'CNY':'symbol' }}
  • 美元: {{ 1234.56 | currency:'USD':'symbol' }}
  • 欧元: {{ 1234.56 | currency:'EUR':'symbol' }}
  • 日元: {{ 1234.56 | currency:'JPY':'symbol' }}
数字格式化
  • 小数: {{ 1234.567 | number:'1.2-2' }}
  • 百分比: {{ 0.1234 | percent:'1.2-2' }}
  • 科学计数: {{ 1234567 | number:'1.1-1' }}
// locale-aware.component.ts - 区域感知格式化
import { Component, Inject, LOCALE_ID } from '@angular/core';
import { formatDate, formatCurrency, formatNumber, formatPercent } from '@angular/common';

@Component({
  selector: 'app-locale-aware',
  template: `
    <div class="locale-demo">
      <h3>区域设置: {{currentLocale}}</h3>

      <div class="format-row">
        <strong>日期:</strong> {{formattedDate}}
      </div>

      <div class="format-row">
        <strong>货币:</strong> {{formattedCurrency}}
      </div>

      <div class="format-row">
        <strong>数字:</strong> {{formattedNumber}}
      </div>

      <div class="format-row">
        <strong>百分比:</strong> {{formattedPercent}}
      </div>
    </div>
  `
})
export class LocaleAwareComponent {
  currentLocale: string;
  formattedDate: string;
  formattedCurrency: string;
  formattedNumber: string;
  formattedPercent: string;

  constructor(@Inject(LOCALE_ID) private locale: string) {
    this.currentLocale = locale;

    const now = new Date();
    const amount = 1234.5678;

    // 使用formatXXX函数进行格式化
    this.formattedDate = formatDate(now, 'fullDate', this.locale);
    this.formattedCurrency = formatCurrency(amount, this.locale, '¥');
    this.formattedNumber = formatNumber(amount, this.locale, '1.2-2');
    this.formattedPercent = formatPercent(0.1234, this.locale, '1.2-2');
  }
}

// 动态切换区域设置
@Component({
  selector: 'app-dynamic-locale',
  template: `
    <div class="dynamic-locale">
      <select [(ngModel)]="selectedLocale" (change)="changeLocale()">
        <option value="zh-Hans">简体中文</option>
        <option value="en-US">English (US)</option>
        <option value="es-ES">Español</option>
        <option value="ja-JP">日本語</option>
        <option value="fr-FR">Français</option>
        <option value="de-DE">Deutsch</option>
      </select>

      <div class="demo-output">
        <p>日期: {{currentDate | date:'fullDate'}}</p>
        <p>货币: {{price | currency}}</p>
        <p>数字: {{numberValue | number}}</p>
        <p>百分比: {{percentage | percent}}</p>
      </div>
    </div>
  `
})
export class DynamicLocaleComponent {
  selectedLocale = 'zh-Hans';
  currentDate = new Date();
  price = 1234.56;
  numberValue = 1234567.89;
  percentage = 0.75;

  constructor() {
    // 从本地存储或用户设置获取区域
    const savedLocale = localStorage.getItem('userLocale');
    if (savedLocale) {
      this.selectedLocale = savedLocale;
      this.changeLocale();
    }
  }

  changeLocale(): void {
    // 注意:需要重新加载应用才能更改区域设置
    localStorage.setItem('userLocale', this.selectedLocale);

    // 在实际应用中,可能需要重新加载页面或使用服务动态更新
    console.log('区域设置已更改为:', this.selectedLocale);

    // 这里可以触发事件通知其他组件
  }
}

4. 右到左(RTL)语言支持

// rtl-support.component.ts - RTL语言支持
import { Component, HostBinding, Renderer2 } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Component({
  selector: 'app-rtl-support',
  template: `
    <div class="rtl-demo">
      <div class="language-selector">
        <button (click)="setLanguage('en')">English (LTR)</button>
        <button (click)="setLanguage('ar')">العربية (RTL)</button>
        <button (click)="setLanguage('he')">עברית (RTL)</button>
      </div>

      <div class="content">
        <h3>{{ 'TITLE' | translate }}</h3>
        <p>{{ 'DESCRIPTION' | translate }}</p>
        <div class="text-example">
          {{ 'SAMPLE_TEXT' | translate }}
        </div>
      </div>
    </div>
  `,
  styles: [`
    .rtl-demo {
      padding: 20px;
      border: 1px solid #dee2e6;
      border-radius: 8px;
      margin: 20px 0;
    }

    .language-selector {
      margin-bottom: 20px;
    }

    .language-selector button {
      margin-right: 10px;
      padding: 8px 16px;
    }

    .content {
      text-align: inherit; /* 根据方向继承 */
    }

    .text-example {
      padding: 15px;
      background: #f8f9fa;
      border-radius: 4px;
      margin-top: 15px;
    }
  `]
})
export class RtlSupportComponent {
  @HostBinding('attr.dir') direction = 'ltr';

  constructor(
    private translate: TranslateService,
    private renderer: Renderer2
  ) {
    // 监听语言变化
    this.translate.onLangChange.subscribe((event: LangChangeEvent) => {
      this.updateDirection(event.lang);
    });
  }

  setLanguage(lang: string): void {
    this.translate.use(lang);
  }

  private updateDirection(lang: string): void {
    // 判断是否为RTL语言
    const rtlLanguages = ['ar', 'he', 'fa', 'ur'];
    const isRTL = rtlLanguages.includes(lang);

    // 更新方向
    this.direction = isRTL ? 'rtl' : 'ltr';

    // 更新HTML元素的dir属性
    this.renderer.setAttribute(document.documentElement, 'dir', this.direction);

    // 更新body类
    if (isRTL) {
      this.renderer.addClass(document.body, 'rtl');
      this.renderer.removeClass(document.body, 'ltr');
    } else {
      this.renderer.addClass(document.body, 'ltr');
      this.renderer.removeClass(document.body, 'rtl');
    }

    console.log(`语言方向已更新: ${this.direction}`);
  }
}

// RTL样式示例
/* rtl-styles.scss */
body.rtl {
  text-align: right;
  direction: rtl;

  .navbar-nav {
    padding-right: 0;
  }

  .float-left {
    float: right !important;
  }

  .float-right {
    float: left !important;
  }

  .text-left {
    text-align: right !important;
  }

  .text-right {
    text-align: left !important;
  }

  .ml-1 { margin-right: 0.25rem !important; margin-left: 0 !important; }
  .ml-2 { margin-right: 0.5rem !important; margin-left: 0 !important; }
  .ml-3 { margin-right: 1rem !important; margin-left: 0 !important; }

  .mr-1 { margin-left: 0.25rem !important; margin-right: 0 !important; }
  .mr-2 { margin-left: 0.5rem !important; margin-right: 0 !important; }
  .mr-3 { margin-left: 1rem !important; margin-right: 0 !important; }

  .pl-1 { padding-right: 0.25rem !important; padding-left: 0 !important; }
  .pl-2 { padding-right: 0.5rem !important; padding-left: 0 !important; }
  .pl-3 { padding-right: 1rem !important; padding-left: 0 !important; }

  .pr-1 { padding-left: 0.25rem !important; padding-right: 0 !important; }
  .pr-2 { padding-left: 0.5rem !important; padding-right: 0 !important; }
  .pr-3 { padding-left: 1rem !important; padding-right: 0 !important; }
}

5. 国际化最佳实践

国际化最佳实践:
  • 尽早规划国际化,而不是事后添加
  • 使用键值对而不是硬编码文本
  • 为翻译提供上下文和注释
  • 考虑文本扩展(不同语言长度不同)
  • 处理复数、性别、日期/时间格式化
  • 测试所有支持的语言
  • 考虑RTL语言支持
  • 使用专业的翻译服务
常见问题与解决方案:
  • 文本溢出:使用弹性布局和可扩展容器
  • 缺少翻译:提供备用语言和回退机制
  • 动态内容:确保API响应也支持多语言
  • SEO优化:为每种语言设置hreflang标签
  • 性能问题:懒加载翻译文件
  • 维护困难:使用翻译管理系统
  • 测试复杂:自动化国际化测试
// i18n-best-practices.service.ts
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';

@Injectable({
  providedIn: 'root'
})
export class I18nBestPracticesService {
  private supportedLangs = ['zh', 'en', 'es', 'ja', 'fr'];

  constructor(private translate: TranslateService) {}

  // 1. 语言检测和回退
  initializeLanguage(): void {
    // 优先级:用户选择 > 浏览器语言 > 默认语言
    const userLang = localStorage.getItem('userLang');
    const browserLang = this.translate.getBrowserLang();
    const defaultLang = 'zh';

    let langToUse = userLang || browserLang || defaultLang;

    // 确保语言在支持列表中
    if (!this.supportedLangs.includes(langToUse)) {
      langToUse = defaultLang;
    }

    this.translate.setDefaultLang(defaultLang);
    this.translate.use(langToUse);
  }

  // 2. 懒加载翻译
  async loadLanguage(lang: string): Promise {
    if (!this.supportedLangs.includes(lang)) {
      throw new Error(`语言 ${lang} 不受支持`);
    }

    try {
      // 动态导入翻译文件
      const translations = await import(`../assets/i18n/${lang}.json`);

      // 设置翻译
      this.translate.setTranslation(lang, translations, true);
      this.translate.use(lang);

      localStorage.setItem('userLang', lang);
    } catch (error) {
      console.error(`加载语言 ${lang} 失败:`, error);
      throw error;
    }
  }

  // 3. 翻译键名管理
  getTranslationKey(module: string, component: string, key: string): string {
    // 使用一致的命名约定
    return `${module.toUpperCase()}.${component.toUpperCase()}.${key.toUpperCase()}`;
  }

  // 4. 处理缺失翻译
  getSafeTranslation(key: string, params?: any): string {
    const translation = this.translate.instant(key, params);

    // 如果翻译不存在,返回键名作为后备
    if (translation === key) {
      console.warn(`缺少翻译: ${key}`);
      return this.getFallbackTranslation(key);
    }

    return translation;
  }

  private getFallbackTranslation(key: string): string {
    // 实现智能回退逻辑
    const fallbacks: { [key: string]: string } = {
      'COMMON.BUTTONS.SAVE': '保存',
      'COMMON.BUTTONS.CANCEL': '取消',
      'COMMON.BUTTONS.DELETE': '删除'
    };

    return fallbacks[key] || key;
  }

  // 5. 处理文本扩展
  getAdaptiveText(key: string, maxLength?: number): string {
    const text = this.translate.instant(key);

    if (maxLength && text.length > maxLength) {
      // 获取缩写版本
      const shortKey = `${key}_SHORT`;
      const shortText = this.translate.instant(shortKey);

      if (shortText !== shortKey) {
        return shortText;
      }

      // 如果缩写不存在,截断文本
      return text.substring(0, maxLength - 3) + '...';
    }

    return text;
  }

  // 6. 获取当前语言信息
  getLanguageInfo(lang: string): {
    code: string;
    name: string;
    nativeName: string;
    direction: 'ltr' | 'rtl';
  } {
    const languages: any = {
      'zh': { code: 'zh', name: 'Chinese', nativeName: '中文', direction: 'ltr' },
      'en': { code: 'en', name: 'English', nativeName: 'English', direction: 'ltr' },
      'es': { code: 'es', name: 'Spanish', nativeName: 'Español', direction: 'ltr' },
      'ja': { code: 'ja', name: 'Japanese', nativeName: '日本語', direction: 'ltr' },
      'fr': { code: 'fr', name: 'French', nativeName: 'Français', direction: 'ltr' },
      'ar': { code: 'ar', name: 'Arabic', nativeName: 'العربية', direction: 'rtl' },
      'he': { code: 'he', name: 'Hebrew', nativeName: 'עברית', direction: 'rtl' }
    };

    return languages[lang] || languages['zh'];
  }
}

6. SEO与多语言网站

<!-- index.html - 多语言SEO优化 -->
<!doctype html>
<html lang="zh-Hans">
<head>
  <meta charset="utf-8">
  <title>我的应用 - 多语言演示</title>

  <!-- 多语言SEO -->
  <link rel="alternate" hreflang="zh-Hans" href="https://example.com/zh/">
  <link rel="alternate" hreflang="en" href="https://example.com/en/">
  <link rel="alternate" hreflang="es" href="https://example.com/es/">
  <link rel="alternate" hreflang="ja" href="https://example.com/ja/">
  <link rel="alternate" hreflang="fr" href="https://example.com/fr/">
  <link rel="alternate" hreflang="x-default" href="https://example.com/">

  <meta name="description" content="多语言演示应用">
  <meta property="og:locale" content="zh_CN">
  <meta property="og:locale:alternate" content="en_US">
  <meta property="og:locale:alternate" content="es_ES">

  <!-- 语言切换元标签 -->
  <meta http-equiv="content-language" content="zh-CN">
</head>
<body>
  <app-root></app-root>
</body>
</html>
实施建议:
  • 新项目:使用Angular内置i18n,从开始就支持国际化
  • 现有项目:使用ngx-translate逐步添加多语言支持
  • 大型企业应用:考虑使用专业的翻译管理系统
  • 内容密集型:使用服务端渲染和内容交付网络
  • 实时应用:结合服务端和客户端国际化
  • 移动应用:使用平台特定的本地化功能