基于 Angular 的国际化文件模块化拆分方案与配置指南

需求背景

随着项目的不断迭代和功能的持续扩展,国际化文件的体积显著增加,不仅影响了加载性能,还加大了后期维护的复杂性。为了提升系统的性能与可维护性,建议采用模块化拆分的方式,将国际化文件按功能模块独立管理。这样做不仅可以有效减少每次加载的文件体积,提升系统响应速度,还能使得各个模块的国际化维护更加独立,降低跨模块修改带来的影响,提升开发效率。接下来,我们将详细介绍这种拆分方案的具体实现方法。

配置流程

  1. HttpLoaderFactory:为 AoT 编译提供工厂函数,生成 TranslateHttpLoader 用于加载国际化文件
/**
 * AoT(Ahead-of-Time 编译)需要导出一个工厂函数来生成 TranslateHttpLoader 实例。
 * 该函数会在应用启动时由 Angular 调用。
 * 
 * @param http HttpClient实例,用于发起HTTP请求
 * @returns TranslateHttpLoader实例
 */
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
  // 创建并返回 TranslateHttpLoader,用于加载国际化文件
  return new TranslateHttpLoader(http, '../assets/i18n/', '');
}
@NgModule({
  declarations: [AppComponent],
  imports: [
    // 国际化配置
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    })
  ]
})
  1. initLoadTranslations:在应用初始化时调用,返回一个 Promise,确保在所有翻译文件加载完
/**
 * initLoadTranslations 函数用于在应用初始化时加载指定语言的全部国际化文件。
 * 
 * @param translate TranslateService实例,用于操作翻译内容
 * @param http HttpClient实例,用于发起HTTP请求
 * @returns 一个函数,该函数返回Promise,当所有语言文件加载完成后,Promise resolve
 */
export function initLoadTranslations(translate: TranslateService, http: HttpClient): () => Promise<void> {
  return (): Promise<void> => {
    // 返回一个 Promise,确保在所有语言文件加载完成后再继续应用初始化
    return new Promise<void>((resolve, reject) => {
      // 当前语言,这里默认设为中文(可以根据实际需求修改)
      const language: string = LanguageEnum.ZH_CN;
      // 调用 loadTranslations 函数加载国际化文件
      loadTranslations(language, translate, http, resolve);
    });
  };
}
@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initLoadTranslations,
      deps: [TranslateService, HttpClient],
      multi: true
    }
  ]
})
  1. getTranslateUrls:生成当前语言的所有国际化文件的 URL,并带有时间戳以避免缓存
/**
 * 获取国际化文件的 URL 地址,避免缓存。
 * 
 * @param language 语言代码,例如 'zh_CN' 或 'en_US'
 * @returns 包含当前语言的多个国际化文件的URL数组
 */
export function getTranslateUrls(language: string): Array<string> {
  // 当前时间戳,作为 URL 参数,避免浏览器缓存
  const timestamp: number = new Date().getTime();
  // 返回包含所有需要加载的国际化文件URL
  return [
    `./assets/i18n/${language}/main.json?t=${timestamp}`
    // 其余文件
  ];
}
  1. getTranslatePromises:遍历 URL 列表,发起 HTTP 请求获取翻译文件,使用 TranslateService 将内容添加至应用中
/**
 * 获取请求每个国际化文件的Promise实例,加载后会将其添加到TranslateService中。
 * 
 * @param language 语言代码
 * @param translationUrls 语言文件的 URL 数组
 * @param translate TranslateService实例
 * @param http HttpClient实例
 * @returns Promise数组,每个Promise代表一个文件加载完成
 */
export function getTranslatePromises(language: string, translationUrls: Array<string>, translate: TranslateService, http: HttpClient): Array<Promise<void>> {
  // 遍历每个URL并发起HTTP请求,加载后将翻译内容设置到TranslateService中
  const loadLangs: Promise<void>[] = translationUrls.map((url: string) => 
    // 发起HTTP请求获取JSON格式的翻译数据
    http.get(url).toPromise().then((translations: any) => {
      // 加载完成后将翻译数据加入TranslateService,第三个参数为true表示追加而不是覆盖
      translate.setTranslation(language, translations, true);
    })
  );
  // 返回每个请求对应的Promise
  return loadLangs;
}
  1. loadTranslations:实际处理加载过程,等待所有文件加载完成后设置应用语言
/**
 * 加载语言文件,并在加载完成后调用resolve函数。
 * 
 * @param language 语言代码,例如 'zh_CN' 或 'en_US'
 * @param translate TranslateService实例,用于设置和切换语言
 * @param http HttpClient实例,用于发起HTTP请求
 * @param resolve 可选的回调函数,当所有语言文件加载完成后调用
 */
export function loadTranslations(language: string, translate: TranslateService, http: HttpClient, resolve?: any): void {
  // 获取当前语言的所有国际化文件的 URL 列表
  const translationUrls: string[] = getTranslateUrls(language);

  // 为每个 URL 创建 Promise,用于处理文件的加载
  const loadPromises: Promise<void>[] = getTranslatePromises(language, translationUrls, translate, http);

  // 使用 Promise.all 等待所有文件加载完成
  Promise.all(loadPromises).then(() => {
    // 当所有文件加载完成后,设置应用当前语言
    translate.use(language);
    // 调用传入的 resolve 函数(如果存在)
    resolve && resolve();
  }).catch((err: any) => {
    // 如果加载过程中出现错误,输出错误信息
    console.error('Error loading translations', err);
    // 此处可以进一步添加错误处理逻辑
  });
}

方案总结

通过本文的介绍,我们详细探讨了如何基于 Angular 进行国际化文件的模块化拆分。随着项目规模的扩大,合理地将国际化文件按功能模块进行拆分,不仅可以提升应用的加载性能,还能有效降低后期的维护成本,确保各个模块的国际化工作更加清晰、独立。同时,这种方案为项目的可扩展性和灵活性提供了更大的支持。在实际应用中,开发者可以根据项目的需求,灵活调整拆分方案,进一步提升项目的开发效率与用户体验。

完整配置代码

  1. 国际化公共方法文件,集成了在app.module.ts里面需要使用的useFactory。
import { HttpClient } from '@angular/common/http';
import { TranslateService } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';

// 支持的语言枚举,定义了中文和英文
export enum LanguageEnum {
  ZH_CN = 'zh_CN',
  EN_US = 'en_US'
}

/**
 * AoT(Ahead-of-Time 编译)需要导出一个工厂函数来生成 TranslateHttpLoader 实例。
 * 该函数会在应用启动时由 Angular 调用。
 * 
 * @param http HttpClient实例,用于发起HTTP请求
 * @returns TranslateHttpLoader实例
 */
export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader {
  // 创建并返回 TranslateHttpLoader,用于加载国际化文件
  return new TranslateHttpLoader(http, '../assets/i18n/', '');
}

/**
 * initLoadTranslations 函数用于在应用初始化时加载指定语言的全部国际化文件。
 * 
 * @param translate TranslateService实例,用于操作翻译内容
 * @param http HttpClient实例,用于发起HTTP请求
 * @returns 一个函数,该函数返回Promise,当所有语言文件加载完成后,Promise resolve
 */
export function initLoadTranslations(translate: TranslateService, http: HttpClient): () => Promise<void> {
  return (): Promise<void> => {
    // 返回一个 Promise,确保在所有语言文件加载完成后再继续应用初始化
    return new Promise<void>((resolve, reject) => {
      // 当前语言,这里默认设为中文(可以根据实际需求修改)
      const language: string = LanguageEnum.ZH_CN;
      // 调用 loadTranslations 函数加载国际化文件
      loadTranslations(language, translate, http, resolve);
    });
  };
}

/**
 * 获取国际化文件的 URL 地址,避免缓存。
 * 
 * @param language 语言代码,例如 'zh_CN' 或 'en_US'
 * @returns 包含当前语言的多个国际化文件的URL数组
 */
export function getTranslateUrls(language: string): Array<string> {
  // 当前时间戳,作为 URL 参数,避免浏览器缓存
  const timestamp: number = new Date().getTime();
  // 返回包含所有需要加载的国际化文件URL
  return [
    `./assets/i18n/${language}/main.json?t=${timestamp}`
  ];
}

/**
 * 获取请求每个国际化文件的Promise实例,加载后会将其添加到TranslateService中。
 * 
 * @param language 语言代码
 * @param translationUrls 语言文件的 URL 数组
 * @param translate TranslateService实例
 * @param http HttpClient实例
 * @returns Promise数组,每个Promise代表一个文件加载完成
 */
export function getTranslatePromises(language: string, translationUrls: Array<string>, translate: TranslateService, http: HttpClient): Array<Promise<void>> {
  // 遍历每个URL并发起HTTP请求,加载后将翻译内容设置到TranslateService中
  const loadLangs: Promise<void>[] = translationUrls.map((url: string) => 
    // 发起HTTP请求获取JSON格式的翻译数据
    http.get(url).toPromise().then((translations: any) => {
      // 加载完成后将翻译数据加入TranslateService,第三个参数为true表示追加而不是覆盖
      translate.setTranslation(language, translations, true);
    })
  );
  // 返回每个请求对应的Promise
  return loadLangs;
}

/**
 * 加载语言文件,并在加载完成后调用resolve函数。
 * 
 * @param language 语言代码,例如 'zh_CN' 或 'en_US'
 * @param translate TranslateService实例,用于设置和切换语言
 * @param http HttpClient实例,用于发起HTTP请求
 * @param resolve 可选的回调函数,当所有语言文件加载完成后调用
 */
export function loadTranslations(language: string, translate: TranslateService, http: HttpClient, resolve?: any): void {
  // 获取当前语言的所有国际化文件的 URL 列表
  const translationUrls: string[] = getTranslateUrls(language);

  // 为每个 URL 创建 Promise,用于处理文件的加载
  const loadPromises: Promise<void>[] = getTranslatePromises(language, translationUrls, translate, http);

  // 使用 Promise.all 等待所有文件加载完成
  Promise.all(loadPromises).then(() => {
    // 当所有文件加载完成后,设置应用当前语言
    translate.use(language);
    // 调用传入的 resolve 函数(如果存在)
    resolve && resolve();
  }).catch((err: any) => {
    // 如果加载过程中出现错误,输出错误信息
    console.error('Error loading translations', err);
    // 此处可以进一步添加错误处理逻辑
  });
}
  1. app.module.ts文件。
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { HttpLoaderFactory, initLoadTranslations } from './utils/translate/use-factory';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    AppRoutingModule,
    BrowserAnimationsModule,
    FormsModule,
    HttpClientModule,
    // 国际化配置
    TranslateModule.forRoot({
      loader: {
        provide: TranslateLoader,
        useFactory: HttpLoaderFactory,
        deps: [HttpClient]
      }
    })
  ],
  providers: [
    {
      // 由于请求国际化文件是异步的,有时系统初始化时会出现国际化文件未加载,渲染时找不到翻译文件,故在初始化时先加载国际化文件
      provide: APP_INITIALIZER,
      useFactory: initLoadTranslations,
      deps: [TranslateService, HttpClient],
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}
  1. 国际化文件目录结构,目录名必须与使用语言的key对应,不然会加载不到翻译文件。
src
└── assets
    └── i18n
        ├── en_US
        │   └── main.json
        └── zh_CN
            └── main.json

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值