Files
wwjcloud-nest-v1/wwjcloud-nest/src/common/language/language.service.ts
wanwujie c4e588a2fe feat: 完成PHP到NestJS迁移工具和代码生成
-  成功运行迁移工具,生成28个模块的完整NestJS代码
-  生成所有实体、服务、控制器、验证器等组件
-  修复npm依赖冲突,更新package-lock.json
-  添加Docker测试脚本和配置文件
-  完善迁移工具的调试日志和错误处理
- 🔧 包含增量更新工具和质量检查工具
- 📊 迁移统计:28个模块,数千个文件,耗时26.47秒

主要变更:
- wwjcloud-nest/src/core/* - 生成的业务模块代码
- tools/* - 迁移工具和辅助脚本
- wwjcloud-nest/package.json - 依赖更新
- docker/* - 容器化配置和测试脚本
2025-10-20 18:43:52 +08:00

459 lines
12 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { promises as fs } from 'fs';
import * as path from 'path';
import { ILanguageService } from './language.interface';
/**
* 语言服务
* 基于 NestJS 实现模块化多语言支持
* 符合NestJS规范的服务层实现
* 对应PHP: think\Lang 类
* 对应Java: MessageSource 实现
*/
@Injectable()
export class LanguageService implements ILanguageService {
private readonly logger = new Logger(LanguageService.name);
private readonly languageCache = new Map<string, Map<string, any>>();
private readonly moduleCache = new Map<string, Set<string>>(); // 记录已加载的模块
constructor(private readonly configService: ConfigService) {
this.initializeLanguagePacks();
}
/**
* 获取消息
* @param key 消息键
* @param args 参数
* @param module 模块名
* @param type 类型 (api|dict|validate)
* @param language 语言
* @returns 消息内容
*/
async getMessage(
key: string,
args?: any,
module: string = 'common',
type: string = 'api',
language?: string,
): Promise<string> {
try {
const currentLanguage = language || this.getCurrentLanguage();
const cacheKey = `${type}.${module}.${key}`;
// 确保模块已加载
await this.ensureModuleLoaded(module, type, currentLanguage);
const message = this.getMessageFromCache(cacheKey, currentLanguage);
if (message && message !== key) {
// 支持参数替换
if (args && typeof args === 'object') {
return this.replaceMessageParams(message, args);
}
return message;
}
this.logger.warn(
`未找到消息: ${key} (模块: ${module}, 类型: ${type}, 语言: ${currentLanguage})`,
);
return key;
} catch (error) {
this.logger.warn(`获取消息失败: ${key}`, error);
return key;
}
}
/**
* 获取消息(实例方法)
* @param key 消息键
* @param args 参数
* @param module 模块名
* @param type 类型
* @param language 语言
* @returns 消息内容
*/
async get(
key: string,
args?: any,
module: string = 'common',
type: string = 'api',
language?: string,
): Promise<string> {
return await this.getMessage(key, args, module, type, language);
}
/**
* 初始化语言包
* 只加载通用语言包,其他模块按需加载
*/
private async initializeLanguagePacks(): Promise<void> {
try {
const supportedLanguages = this.getSupportedLanguages();
for (const language of supportedLanguages) {
// 只加载通用模块
await this.loadModuleLanguagePack('common', 'api', language);
await this.loadModuleLanguagePack('common', 'dict', language);
await this.loadModuleLanguagePack('common', 'validate', language);
}
this.logger.log('通用语言包初始化完成');
} catch (error) {
this.logger.error('语言包初始化失败', error);
}
}
/**
* 确保模块已加载
* @param module 模块名
* @param type 类型
* @param language 语言
*/
private async ensureModuleLoaded(
module: string,
type: string,
language: string,
): Promise<void> {
const moduleKey = `${module}.${type}`;
const languageKey = `${language}.${moduleKey}`;
if (
!this.moduleCache.has(language) ||
!this.moduleCache.get(language)!.has(moduleKey)
) {
await this.loadModuleLanguagePack(module, type, language);
}
}
/**
* 加载模块语言包
* @param module 模块名
* @param type 类型 (api|dict|validate)
* @param language 语言
*/
private async loadModuleLanguagePack(
module: string,
type: string,
language: string,
): Promise<void> {
try {
const langDir = path.join(process.cwd(), 'src', 'lang', language);
const languagePack = new Map<string, any>();
// 1. 加载通用语言包
if (module !== 'common') {
await this.loadCommonLanguagePack(langDir, type, languagePack);
}
// 2. 加载模块语言包
await this.loadModuleSpecificPack(langDir, module, type, languagePack);
// 3. 加载插件语言包
await this.loadAddonLanguagePacks(langDir, type, languagePack);
// 4. 缓存语言包
if (!this.languageCache.has(language)) {
this.languageCache.set(language, new Map());
}
const languageCache = this.languageCache.get(language)!;
for (const [key, value] of languagePack) {
languageCache.set(key, value);
}
// 5. 记录已加载的模块
if (!this.moduleCache.has(language)) {
this.moduleCache.set(language, new Set());
}
this.moduleCache.get(language)!.add(`${module}.${type}`);
this.logger.log(`模块语言包加载完成: ${module}.${type} (${language})`);
} catch (error) {
this.logger.error(
`加载模块语言包失败: ${module}.${type} (${language})`,
error,
);
}
}
/**
* 加载通用语言包
*/
private async loadCommonLanguagePack(
langDir: string,
type: string,
languagePack: Map<string, any>,
): Promise<void> {
const commonDir = path.join(langDir, 'common');
const filePath = path.join(commonDir, `${type}.json`);
try {
const content = await fs.readFile(filePath, 'utf8');
const data = JSON.parse(content);
// 合并到语言包,添加前缀
for (const [key, value] of Object.entries(data)) {
languagePack.set(`${type}.common.${key}`, value);
}
} catch (error) {
this.logger.warn(`加载通用语言包失败: ${type}`, error);
}
}
/**
* 加载模块特定语言包
*/
private async loadModuleSpecificPack(
langDir: string,
module: string,
type: string,
languagePack: Map<string, any>,
): Promise<void> {
const moduleDir = path.join(langDir, module);
const filePath = path.join(moduleDir, `${type}.json`);
try {
const content = await fs.readFile(filePath, 'utf8');
const data = JSON.parse(content);
// 合并到语言包,添加前缀
for (const [key, value] of Object.entries(data)) {
languagePack.set(`${type}.${module}.${key}`, value);
}
} catch (error) {
this.logger.warn(`加载模块语言包失败: ${module}.${type}`, error);
}
}
/**
* 加载插件语言包
*/
private async loadAddonLanguagePacks(
langDir: string,
type: string,
languagePack: Map<string, any>,
): Promise<void> {
const addonsDir = path.join(langDir, 'addons');
try {
const addonDirs = await fs.readdir(addonsDir);
for (const addonDir of addonDirs) {
const addonPath = path.join(addonsDir, addonDir);
const stat = await fs.stat(addonPath);
if (stat.isDirectory()) {
const filePath = path.join(addonPath, `${type}.json`);
try {
const content = await fs.readFile(filePath, 'utf8');
const data = JSON.parse(content);
// 合并到语言包,添加前缀
for (const [key, value] of Object.entries(data)) {
languagePack.set(`${type}.addon.${addonDir}.${key}`, value);
}
} catch (error) {
this.logger.warn(`加载插件语言包失败: ${addonDir}.${type}`, error);
}
}
}
} catch (error) {
this.logger.warn(`扫描插件语言包失败: ${type}`, error);
}
}
/**
* 合并语言数据
*/
private mergeLanguageData(
target: Map<string, any>,
source: Record<string, any>,
): void {
for (const [key, value] of Object.entries(source)) {
target.set(key, value);
}
}
/**
* 从缓存获取消息
*/
private getMessageFromCache(key: string, language: string): string {
const languagePack = this.languageCache.get(language);
if (languagePack && languagePack.has(key)) {
return languagePack.get(key);
}
return key; // 未找到返回key作为fallback
}
/**
* 替换消息参数
* 对应 Java: MessageFormat.format()
*/
private replaceMessageParams(
message: string,
args: Record<string, any>,
): string {
let result = message;
for (const [key, value] of Object.entries(args)) {
const placeholder = `{${key}}`;
result = result.replace(new RegExp(placeholder, 'g'), String(value));
}
return result;
}
/**
* 获取当前语言
* @returns 当前语言
*/
getCurrentLanguage(): string {
return this.getDefaultLanguage();
}
/**
* 设置语言
* @param language 语言代码
*/
setLanguage(language: string): void {
this.logger.log(`设置语言: ${language}`);
}
/**
* 获取支持的语言列表
* @returns 支持的语言列表
*/
getSupportedLanguages(): string[] {
return this.configService.get('app.supportedLocales', ['zh_CN', 'en_US']);
}
/**
* 获取默认语言
* @returns 默认语言
*/
getDefaultLanguage(): string {
return this.configService.get('app.defaultLanguage', 'zh_CN');
}
/**
* 检查语言是否支持
* @param language 语言代码
* @returns 是否支持
*/
isLanguageSupported(language: string): boolean {
const supportedLanguages = this.getSupportedLanguages();
return supportedLanguages.includes(language);
}
/**
* 重新加载语言包
*/
async reloadLanguagePack(language: string): Promise<void> {
try {
// 清除该语言的所有缓存
this.languageCache.delete(language);
this.moduleCache.delete(language);
// 重新加载通用语言包
await this.loadModuleLanguagePack('common', 'api', language);
await this.loadModuleLanguagePack('common', 'dict', language);
await this.loadModuleLanguagePack('common', 'validate', language);
this.logger.log(`重新加载语言包完成: ${language}`);
} catch (error) {
this.logger.error(`重新加载语言包失败: ${language}`, error);
}
}
/**
* 重新加载所有语言包
*/
async reloadAllLanguagePacks(): Promise<void> {
try {
this.languageCache.clear();
this.moduleCache.clear();
await this.initializeLanguagePacks();
this.logger.log('所有语言包重新加载完成');
} catch (error) {
this.logger.error('重新加载所有语言包失败', error);
}
}
/**
* 获取API消息
* @param key 消息键
* @param args 参数
* @param module 模块名
* @param language 语言
*/
async getApiMessage(
key: string,
args?: any,
module: string = 'common',
language?: string,
): Promise<string> {
const currentLanguage = language || this.getCurrentLanguage();
return this.getMessage(key, args, module, 'api', currentLanguage);
}
/**
* 获取字典数据
* @param key 字典键
* @param args 参数
* @param module 模块名
* @param language 语言
*/
async getDictData(
key: string,
args?: any,
module: string = 'common',
language?: string,
): Promise<string> {
const currentLanguage = language || this.getCurrentLanguage();
return this.getMessage(key, args, module, 'dict', currentLanguage);
}
/**
* 获取验证器消息
* @param key 验证器键
* @param args 参数
* @param module 模块名
* @param language 语言
*/
async getValidateMessage(
key: string,
args?: any,
module: string = 'common',
language?: string,
): Promise<string> {
const currentLanguage = language || this.getCurrentLanguage();
return this.getMessage(key, args, module, 'validate', currentLanguage);
}
/**
* 批量获取消息
* @param keys 消息键数组
* @param module 模块名
* @param type 类型
* @param language 语言
*/
async getBatchMessages(
keys: string[],
module: string = 'common',
type: string = 'api',
language?: string,
): Promise<Record<string, string>> {
const results: Record<string, string> = {};
const currentLanguage = language || this.getCurrentLanguage();
for (const key of keys) {
results[key] = await this.getMessage(
key,
undefined,
module,
type,
currentLanguage,
);
}
return results;
}
}