set up language detect for translation

This commit is contained in:
vahidrezvani 2025-08-21 19:22:09 +03:30
parent d2b6c0bb2b
commit f52cd5263e
22 changed files with 103 additions and 229 deletions

View File

@ -13,11 +13,11 @@ export class CatalogController {
@Post('/language/create') @Post('/language/create')
async getCatalog( async getCatalog(
@Body() body: CreateLanguageDto, @Body() body: CreateLanguageDto,
@Query('lang') queryLang: string,
@Headers('accept-language') acceptLanguage: string, @Headers('accept-language') acceptLanguage: string,
) { ) {
// اولویت‌بندی: body > query > header > پیش‌فرض const lang = acceptLanguage?.split(',')[0] || 'en';
const lang = body.lang || queryLang || acceptLanguage?.split(',')[0] || 'en';
console.log("---kii",lang)
// ارسال پیام به catalog-service // ارسال پیام به catalog-service
return this.catalogService return this.catalogService

View File

@ -5,12 +5,37 @@
"projectType": "application", "projectType": "application",
"tags": [], "tags": [],
"targets": { "targets": {
"build": {
"executor": "@nx/js:tsc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/catalog-service",
"main": "catalog-service/src/main.ts",
"tsConfig": "catalog-service/tsconfig.app.json",
"assets": [
{
"input": "catalog-service/src/assets",
"glob": "**/*",
"output": "assets"
},
{
"input": "catalog-service/src/locales",
"glob": "**/*",
"output": "locales"
}
]
},
"configurations": {
"production": {
"optimization": true,
"sourceMap": false
}
}
},
"serve": { "serve": {
"executor": "@nx/js:node", "executor": "@nx/js:node",
"defaultConfiguration": "development", "defaultConfiguration": "development",
"dependsOn": [ "dependsOn": ["build"],
"build"
],
"options": { "options": {
"buildTarget": "catalog-service:build", "buildTarget": "catalog-service:build",
"runBuildTargetDependencies": false "runBuildTargetDependencies": false
@ -24,6 +49,5 @@
} }
} }
} }
} }
} }

View File

@ -1,22 +1,25 @@
import { Module } from '@nestjs/common';
import * as i18next from 'i18next'; import * as i18next from 'i18next';
import Backend from 'i18next-fs-backend'; import Backend from 'i18next-fs-backend';
import { join } from 'path'; import { join } from 'path';
import { Module } from '@nestjs/common';
import * as i18nextMiddleware from 'i18next-http-middleware';
@Module({ @Module({
providers: [ providers: [
{ {
provide: 'I18NEXT', provide: 'I18NEXT',
useFactory: async () => { useFactory: async () => {
await i18next.use(Backend).init({ // Type assertion برای رفع مشکل TypeScript
lng: 'en', // زبان پیش‌فرض await (i18next as any).use(Backend)
fallbackLng: 'en', // زبان جایگزین .use(i18nextMiddleware.LanguageDetector)
.init({
fallbackLng: ['en','fa'],
backend: { backend: {
loadPath: join(__dirname, './locales/{{lng}}/{{ns}}.json'), // مسیر فایل‌های ترجمه loadPath: join(__dirname, '../../../locales/{{lng}}/{{ns}}.json'),
}, },
ns: ['language', 'validation','translation'], // فضاهای نام ns: ['language', 'validation'],
defaultNS: 'translation', // فضای نام پیش‌فرض defaultNS: 'language',
debug: true, // برای دیباگ debug: true,
}); });
return i18next; return i18next;
}, },
@ -24,4 +27,4 @@ import { join } from 'path';
], ],
exports: ['I18NEXT'], exports: ['I18NEXT'],
}) })
export class I18nextModule {} export class I18nextModule {}

View File

@ -1,7 +1,7 @@
import { Controller, Get, Post, Put, Delete, Body, Param, HttpStatus } from '@nestjs/common'; import { Controller, Get, Post, Put, Delete, Body, Param, HttpStatus } from '@nestjs/common';
import { LanguageService } from './language.service'; import { LanguageService } from './language.service';
import { CreateLanguageDto, UpdateLanguageDto } from 'user-service/src/app/language/dto/language.dto'; import { CreateLanguageDto, UpdateLanguageDto } from './dto/language.dto';
import { Language } from 'user-service/src/schemas/language.schema'; import { Language } from '../../schemas/language.schema';
import { I18n, I18nContext, I18nService } from 'nestjs-i18n'; import { I18n, I18nContext, I18nService } from 'nestjs-i18n';
import { MessagePattern, Payload } from '@nestjs/microservices'; import { MessagePattern, Payload } from '@nestjs/microservices';
@ -12,11 +12,12 @@ export class LanguageController {
) { } ) { }
@MessagePattern({cmd:'POST-language/create'}) @MessagePattern({cmd:'POST-language/create'})
async create(payload: any): Promise<any> { async create(payload: any): Promise<any> {
console.log("---------------------",payload) console.log("---------------------",payload)
const createLanguageDto: CreateLanguageDto = payload.body; const createLanguageDto: CreateLanguageDto = payload.body;
const lang = payload.body.lang || 'en' const lang = payload.lang || 'en'
return this.languageService.create(createLanguageDto,lang); return this.languageService.create(createLanguageDto,lang);
} }

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { LanguageController } from './language.controller'; import { LanguageController } from './language.controller';
import { LanguageService } from './language.service'; import { LanguageService } from './language.service';
import { MongooseModule } from '@nestjs/mongoose'; import { MongooseModule } from '@nestjs/mongoose';
import { Language,LanguageSchema } from 'user-service/src/schemas/language.schema'; import { Language,LanguageSchema } from '../../schemas/language.schema';
import { I18nModule } from 'nestjs-i18n'; import { I18nModule } from 'nestjs-i18n';
import { I18nextModule } from '../i18next/i18next.module'; import { I18nextModule } from '../i18next/i18next.module';

View File

@ -1,8 +1,8 @@
import { Inject, Injectable, NotFoundException } from '@nestjs/common'; import { Inject, Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose'; import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose'; import { Model } from 'mongoose';
import { Language } from 'user-service/src/schemas/language.schema'; import { Language } from '../../schemas/language.schema';
import { CreateLanguageDto, UpdateLanguageDto } from 'user-service/src/app/language/dto/language.dto'; import { CreateLanguageDto, UpdateLanguageDto } from './dto/language.dto';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { I18nContext, I18nService } from 'nestjs-i18n'; import { I18nContext, I18nService } from 'nestjs-i18n';
import i18next from 'i18next'; import i18next from 'i18next';
@ -23,9 +23,10 @@ async create(
}); });
const result = await createdLanguage.save(); const result = await createdLanguage.save();
console.log("language -----------------", await this.i18n.t('created', { lng: lang ,ns: 'language' })) console.log("language -----------------", await this.i18n.t('created', { lng: lang ,ns: 'language' }))
console.log("language -------sdadasd----------", lang)
return { return {
success: true, success: true,
message: await this.i18n.t('created', { lng:'fa' }), message: await this.i18n.t('created', { lng:lang }),
data: result, data: result,
}; };
} }

View File

@ -2,7 +2,7 @@ import { Module } from '@nestjs/common';
import { ShopCategoryController } from './shop-category.controller'; import { ShopCategoryController } from './shop-category.controller';
import { ShopCategoryService } from './shop-category.service'; import { ShopCategoryService } from './shop-category.service';
import { MongooseModule } from '@nestjs/mongoose'; import { MongooseModule } from '@nestjs/mongoose';
import { ShopCategory, ShopCategorySchema } from 'catalog-service/src/schemas/shopCategory.schema'; import { ShopCategory, ShopCategorySchema } from '../../schemas/shopCategory.schema';
@Module({ @Module({
imports: [ imports: [

View File

@ -1,7 +1,7 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { UploadService } from './upload.service'; import { UploadService } from './upload.service';
import { UploadController } from './upload.controller'; import { UploadController } from './upload.controller';
import { FileSchema } from 'catalog-service/src/schemas/file.schema'; import { FileSchema } from '../../schemas/file.schema';
import { MongooseModule } from '@nestjs/mongoose'; import { MongooseModule } from '@nestjs/mongoose';
import { ConfigModule } from '@nestjs/config'; import { ConfigModule } from '@nestjs/config';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';

View File

@ -4,7 +4,7 @@ import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { extname } from 'path'; import { extname } from 'path';
import { File, FileDocument } from 'catalog-service/src/schemas/file.schema' import { File, FileDocument } from '../../schemas/file.schema'
import { InjectModel } from '@nestjs/mongoose'; import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose' import { Model } from 'mongoose'
import { Express } from 'express'; import { Express } from 'express';

View File

@ -0,0 +1,32 @@
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Types } from 'mongoose';
@Schema()
export class Language {
@Prop({ required: true, unique: true })
ID: string;
@Prop({ required: true })
Name: string;
@Prop()
Symbol: string;
@Prop()
Icon: string;
@Prop()
Direction: string;
@Prop()
Status: Boolean;
@Prop({ type: Date, default: Date.now })
createdAt: Date;
@Prop({ type: Date, default: Date.now })
updatedAt: Date;
}
export const LanguageSchema = SchemaFactory.createForClass(Language);
LanguageSchema.index({ ID: 1 });

10
nx.json
View File

@ -15,7 +15,6 @@
], ],
"sharedGlobals": [] "sharedGlobals": []
}, },
"nxCloudId": "68a41cfe0d57f61c2f4a9625",
"plugins": [ "plugins": [
{ {
"plugin": "@nx/webpack/plugin", "plugin": "@nx/webpack/plugin",
@ -46,5 +45,12 @@
"advertisement-service-e2e/**/*" "advertisement-service-e2e/**/*"
] ]
} }
] ],
"targetDefaults": {
"@nx/js:tsc": {
"cache": true,
"dependsOn": ["^build"],
"inputs": ["production", "^production"]
}
}
} }

2
package-lock.json generated
View File

@ -17133,7 +17133,7 @@
}, },
"node_modules/i18next-http-middleware": { "node_modules/i18next-http-middleware": {
"version": "3.8.0", "version": "3.8.0",
"resolved": "https://registry.npmjs.org/i18next-http-middleware/-/i18next-http-middleware-3.8.0.tgz", "resolved": "https://registry.npmmirror.com/i18next-http-middleware/-/i18next-http-middleware-3.8.0.tgz",
"integrity": "sha512-G3DpT/ibwOx6BCI5A2xUmZ2ybUDUrI6emCdEE7AX9TKvz+WzA6peuyv0BxC8kIrJHtrdnmUWwk4rDN9nxWvsFg==", "integrity": "sha512-G3DpT/ibwOx6BCI5A2xUmZ2ybUDUrI6emCdEE7AX9TKvz+WzA6peuyv0BxC8kIrJHtrdnmUWwk4rDN9nxWvsFg==",
"license": "MIT" "license": "MIT"
}, },

View File

@ -14,7 +14,10 @@
"skipLibCheck": true, "skipLibCheck": true,
"skipDefaultLibCheck": true, "skipDefaultLibCheck": true,
"baseUrl": ".", "baseUrl": ".",
"paths": {} "paths": {
"@ecommerce-microservices/i18next": ["i18next/src/index.ts"],
"@ecommerce-microservices/language": ["language/src/index.ts"]
}
}, },
"exclude": ["node_modules", "tmp"] "exclude": ["node_modules", "tmp"]
} }

View File

@ -2,10 +2,10 @@ import { Module } from '@nestjs/common';
import { AppController } from './app.controller'; import { AppController } from './app.controller';
import { AppService } from './app.service'; import { AppService } from './app.service';
import { LanguageModule } from './language/language.module';
@Module({ @Module({
imports: [LanguageModule], imports: [],
controllers: [AppController], controllers: [AppController],
providers: [AppService], providers: [AppService],
}) })

View File

@ -1,55 +0,0 @@
import { IsString, IsNotEmpty, IsOptional, IsEnum, IsUUID } from 'class-validator';
export enum LanguageDirection {
LTR = 'ltr',
RTL = 'rtl',
}
export enum LanguageStatus {
ACTIVE = 'active',
INACTIVE = 'inactive',
}
export class CreateLanguageDto {
@IsString()
@IsNotEmpty()
Name: string;
@IsString()
@IsOptional()
Symbol?: string;
@IsString()
@IsOptional()
Icon?: string;
@IsEnum(LanguageDirection)
@IsOptional()
Direction?: LanguageDirection;
@IsEnum(LanguageStatus)
@IsOptional()
Status?: LanguageStatus;
}
export class UpdateLanguageDto {
@IsString()
@IsOptional()
Name?: string;
@IsString()
@IsOptional()
Symbol?: string;
@IsString()
@IsOptional()
Icon?: string;
@IsEnum(LanguageDirection)
@IsOptional()
Direction?: LanguageDirection;
@IsEnum(LanguageStatus)
@IsOptional()
Status?: LanguageStatus;
}

View File

@ -1,18 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { LanguageController } from './language.controller';
describe('LanguageController', () => {
let controller: LanguageController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [LanguageController],
}).compile();
controller = module.get<LanguageController>(LanguageController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@ -1,36 +0,0 @@
import { Controller, Get, Post, Put, Delete, Body, Param, HttpStatus } from '@nestjs/common';
import { LanguageService } from './language.service';
import { CreateLanguageDto, UpdateLanguageDto } from 'user-service/src/app/language/dto/language.dto';
import { Language } from 'user-service/src/schemas/language.schema';
@Controller('languages')
export class LanguageController {
constructor(private readonly languageService: LanguageService) {}
@Post()
async create(@Body() createLanguageDto: CreateLanguageDto): Promise<Language> {
return this.languageService.create(createLanguageDto);
}
@Get()
async findAll(): Promise<Language[]> {
return this.languageService.findAll();
}
@Get(':id')
async findOne(@Param('id') id: string): Promise<Language> {
return this.languageService.findOne(id);
}
@Put(':id')
async update(@Param('id') id: string, @Body() updateLanguageDto: UpdateLanguageDto): Promise<Language> {
return this.languageService.update(id, updateLanguageDto);
}
@Delete(':id')
async remove(@Param('id') id: string): Promise<void> {
return this.languageService.remove(id);
}
}

View File

@ -1,14 +0,0 @@
import { Module } from '@nestjs/common';
import { LanguageController } from './language.controller';
import { LanguageService } from './language.service';
import { MongooseModule } from '@nestjs/mongoose';
import { Language,LanguageSchema } from 'user-service/src/schemas/language.schema';
@Module({
imports: [
MongooseModule.forFeature([{ name: Language.name, schema: LanguageSchema }]),
],
controllers: [LanguageController],
providers: [LanguageService],
})
export class LanguageModule {}

View File

@ -1,18 +0,0 @@
import { Test, TestingModule } from '@nestjs/testing';
import { LanguageService } from './language.service';
describe('LanguageService', () => {
let service: LanguageService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [LanguageService],
}).compile();
service = module.get<LanguageService>(LanguageService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -1,55 +0,0 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { Language } from 'user-service/src/schemas/language.schema';
import { CreateLanguageDto, UpdateLanguageDto } from 'user-service/src/app/language/dto/language.dto';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
export class LanguageService {
constructor(@InjectModel(Language.name) private languageModel: Model<Language>) {}
async create(createLanguageDto: CreateLanguageDto): Promise<Language> {
const createdLanguage = new this.languageModel({
...createLanguageDto,
ID: uuidv4(), // Generate UUID for new language
createdAt: new Date(),
updatedAt: new Date(),
});
return createdLanguage.save();
}
async findAll(): Promise<Language[]> {
return this.languageModel.find().exec();
}
async findOne(id: string): Promise<Language> {
const language = await this.languageModel.findOne({ ID: id }).exec();
if (!language) {
throw new NotFoundException(`Language with ID ${id} not found`);
}
return language;
}
async update(id: string, updateLanguageDto: UpdateLanguageDto): Promise<Language> {
const language = await this.languageModel
.findOneAndUpdate(
{ ID: id },
{ ...updateLanguageDto, updatedAt: new Date() },
{ new: true },
)
.exec();
if (!language) {
throw new NotFoundException(`Language with ID ${id} not found`);
}
return language;
}
async remove(id: string): Promise<void> {
const result = await this.languageModel.deleteOne({ ID: id }).exec();
if (result.deletedCount === 0) {
throw new NotFoundException(`Language with ID ${id} not found`);
}
}
}