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

View File

@ -5,12 +5,37 @@
"projectType": "application",
"tags": [],
"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": {
"executor": "@nx/js:node",
"defaultConfiguration": "development",
"dependsOn": [
"build"
],
"dependsOn": ["build"],
"options": {
"buildTarget": "catalog-service:build",
"runBuildTargetDependencies": false
@ -24,6 +49,5 @@
}
}
}
}
}
}

View File

@ -1,22 +1,25 @@
import { Module } from '@nestjs/common';
import * as i18next from 'i18next';
import Backend from 'i18next-fs-backend';
import { join } from 'path';
import { Module } from '@nestjs/common';
import * as i18nextMiddleware from 'i18next-http-middleware';
@Module({
providers: [
{
provide: 'I18NEXT',
useFactory: async () => {
await i18next.use(Backend).init({
lng: 'en', // زبان پیش‌فرض
fallbackLng: 'en', // زبان جایگزین
// Type assertion برای رفع مشکل TypeScript
await (i18next as any).use(Backend)
.use(i18nextMiddleware.LanguageDetector)
.init({
fallbackLng: ['en','fa'],
backend: {
loadPath: join(__dirname, './locales/{{lng}}/{{ns}}.json'), // مسیر فایل‌های ترجمه
loadPath: join(__dirname, '../../../locales/{{lng}}/{{ns}}.json'),
},
ns: ['language', 'validation','translation'], // فضاهای نام
defaultNS: 'translation', // فضای نام پیش‌فرض
debug: true, // برای دیباگ
ns: ['language', 'validation'],
defaultNS: 'language',
debug: true,
});
return i18next;
},
@ -24,4 +27,4 @@ import { join } from 'path';
],
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 { 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';
import { CreateLanguageDto, UpdateLanguageDto } from './dto/language.dto';
import { Language } from '../../schemas/language.schema';
import { I18n, I18nContext, I18nService } from 'nestjs-i18n';
import { MessagePattern, Payload } from '@nestjs/microservices';
@ -12,11 +12,12 @@ export class LanguageController {
) { }
@MessagePattern({cmd:'POST-language/create'})
async create(payload: any): Promise<any> {
console.log("---------------------",payload)
const createLanguageDto: CreateLanguageDto = payload.body;
const lang = payload.body.lang || 'en'
const lang = payload.lang || 'en'
return this.languageService.create(createLanguageDto,lang);
}

View File

@ -2,7 +2,7 @@ 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';
import { Language,LanguageSchema } from '../../schemas/language.schema';
import { I18nModule } from 'nestjs-i18n';
import { I18nextModule } from '../i18next/i18next.module';

View File

@ -1,8 +1,8 @@
import { Inject, 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 { Language } from '../../schemas/language.schema';
import { CreateLanguageDto, UpdateLanguageDto } from './dto/language.dto';
import { v4 as uuidv4 } from 'uuid';
import { I18nContext, I18nService } from 'nestjs-i18n';
import i18next from 'i18next';
@ -23,9 +23,10 @@ async create(
});
const result = await createdLanguage.save();
console.log("language -----------------", await this.i18n.t('created', { lng: lang ,ns: 'language' }))
console.log("language -------sdadasd----------", lang)
return {
success: true,
message: await this.i18n.t('created', { lng:'fa' }),
message: await this.i18n.t('created', { lng:lang }),
data: result,
};
}

View File

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

View File

@ -1,7 +1,7 @@
import { Module } from '@nestjs/common';
import { UploadService } from './upload.service';
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 { ConfigModule } 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 { v4 as uuidv4 } from 'uuid';
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 { Model } from 'mongoose'
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": []
},
"nxCloudId": "68a41cfe0d57f61c2f4a9625",
"plugins": [
{
"plugin": "@nx/webpack/plugin",
@ -46,5 +45,12 @@
"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": {
"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==",
"license": "MIT"
},

View File

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

View File

@ -2,10 +2,10 @@ import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LanguageModule } from './language/language.module';
@Module({
imports: [LanguageModule],
imports: [],
controllers: [AppController],
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`);
}
}
}