From f52cd5263edbd25978fea293de617c04ee5ab816 Mon Sep 17 00:00:00 2001 From: vahidrezvani <47754185+vr120678@users.noreply.github.com> Date: Thu, 21 Aug 2025 19:22:09 +0330 Subject: [PATCH] set up language detect for translation --- .../src/app/catalog/catalog.controller.ts | 6 +- catalog-service/project.json | 34 ++++++++++-- .../src/app/i18next/i18next.module.ts | 21 ++++--- .../src/app/language/language.controller.ts | 7 ++- .../src/app/language/language.module.ts | 2 +- .../src/app/language/language.service.ts | 7 ++- .../app/shop-category/shop-category.module.ts | 2 +- .../src/app/upload/upload.module.ts | 2 +- .../src/app/upload/upload.service.ts | 2 +- .../en/{translation.json => language.json} | 0 .../fa/{translation.json => language.json} | 0 .../src/schemas/language.schema.ts | 32 +++++++++++ nx.json | 10 +++- package-lock.json | 2 +- tsconfig.base.json | 5 +- user-service/src/app/app.module.ts | 4 +- .../src/app/language/dto/language.dto.ts | 55 ------------------- .../app/language/language.controller.spec.ts | 18 ------ .../src/app/language/language.controller.ts | 36 ------------ .../src/app/language/language.module.ts | 14 ----- .../src/app/language/language.service.spec.ts | 18 ------ .../src/app/language/language.service.ts | 55 ------------------- 22 files changed, 103 insertions(+), 229 deletions(-) rename catalog-service/src/locales/en/{translation.json => language.json} (100%) rename catalog-service/src/locales/fa/{translation.json => language.json} (100%) create mode 100644 catalog-service/src/schemas/language.schema.ts delete mode 100644 user-service/src/app/language/dto/language.dto.ts delete mode 100644 user-service/src/app/language/language.controller.spec.ts delete mode 100644 user-service/src/app/language/language.controller.ts delete mode 100644 user-service/src/app/language/language.module.ts delete mode 100644 user-service/src/app/language/language.service.spec.ts delete mode 100644 user-service/src/app/language/language.service.ts diff --git a/api-gateway/src/app/catalog/catalog.controller.ts b/api-gateway/src/app/catalog/catalog.controller.ts index f1921fd..54640af 100644 --- a/api-gateway/src/app/catalog/catalog.controller.ts +++ b/api-gateway/src/app/catalog/catalog.controller.ts @@ -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 diff --git a/catalog-service/project.json b/catalog-service/project.json index efb91d4..eb11696 100644 --- a/catalog-service/project.json +++ b/catalog-service/project.json @@ -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 @@ } } } - } -} \ No newline at end of file +} diff --git a/catalog-service/src/app/i18next/i18next.module.ts b/catalog-service/src/app/i18next/i18next.module.ts index b252c3e..457d0d0 100644 --- a/catalog-service/src/app/i18next/i18next.module.ts +++ b/catalog-service/src/app/i18next/i18next.module.ts @@ -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 {} \ No newline at end of file +export class I18nextModule {} diff --git a/catalog-service/src/app/language/language.controller.ts b/catalog-service/src/app/language/language.controller.ts index 506f98d..7c8dc68 100644 --- a/catalog-service/src/app/language/language.controller.ts +++ b/catalog-service/src/app/language/language.controller.ts @@ -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 { 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); } diff --git a/catalog-service/src/app/language/language.module.ts b/catalog-service/src/app/language/language.module.ts index 0e4947b..0d5dd31 100644 --- a/catalog-service/src/app/language/language.module.ts +++ b/catalog-service/src/app/language/language.module.ts @@ -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'; diff --git a/catalog-service/src/app/language/language.service.ts b/catalog-service/src/app/language/language.service.ts index 1d98b0b..3116884 100644 --- a/catalog-service/src/app/language/language.service.ts +++ b/catalog-service/src/app/language/language.service.ts @@ -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, }; } diff --git a/catalog-service/src/app/shop-category/shop-category.module.ts b/catalog-service/src/app/shop-category/shop-category.module.ts index 7fdad37..3e6d1ab 100644 --- a/catalog-service/src/app/shop-category/shop-category.module.ts +++ b/catalog-service/src/app/shop-category/shop-category.module.ts @@ -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: [ diff --git a/catalog-service/src/app/upload/upload.module.ts b/catalog-service/src/app/upload/upload.module.ts index 992bdd0..ea08a44 100644 --- a/catalog-service/src/app/upload/upload.module.ts +++ b/catalog-service/src/app/upload/upload.module.ts @@ -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'; diff --git a/catalog-service/src/app/upload/upload.service.ts b/catalog-service/src/app/upload/upload.service.ts index 8b12ae4..026542a 100644 --- a/catalog-service/src/app/upload/upload.service.ts +++ b/catalog-service/src/app/upload/upload.service.ts @@ -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'; diff --git a/catalog-service/src/locales/en/translation.json b/catalog-service/src/locales/en/language.json similarity index 100% rename from catalog-service/src/locales/en/translation.json rename to catalog-service/src/locales/en/language.json diff --git a/catalog-service/src/locales/fa/translation.json b/catalog-service/src/locales/fa/language.json similarity index 100% rename from catalog-service/src/locales/fa/translation.json rename to catalog-service/src/locales/fa/language.json diff --git a/catalog-service/src/schemas/language.schema.ts b/catalog-service/src/schemas/language.schema.ts new file mode 100644 index 0000000..f89b2c5 --- /dev/null +++ b/catalog-service/src/schemas/language.schema.ts @@ -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 }); \ No newline at end of file diff --git a/nx.json b/nx.json index eec72a0..db81bfa 100644 --- a/nx.json +++ b/nx.json @@ -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"] + } + } } diff --git a/package-lock.json b/package-lock.json index c159957..de61a5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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" }, diff --git a/tsconfig.base.json b/tsconfig.base.json index b73cce6..1ef0c27 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -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"] } diff --git a/user-service/src/app/app.module.ts b/user-service/src/app/app.module.ts index ff040ec..12a5c14 100644 --- a/user-service/src/app/app.module.ts +++ b/user-service/src/app/app.module.ts @@ -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], }) diff --git a/user-service/src/app/language/dto/language.dto.ts b/user-service/src/app/language/dto/language.dto.ts deleted file mode 100644 index 65e640d..0000000 --- a/user-service/src/app/language/dto/language.dto.ts +++ /dev/null @@ -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; -} \ No newline at end of file diff --git a/user-service/src/app/language/language.controller.spec.ts b/user-service/src/app/language/language.controller.spec.ts deleted file mode 100644 index c2774f5..0000000 --- a/user-service/src/app/language/language.controller.spec.ts +++ /dev/null @@ -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); - }); - - it('should be defined', () => { - expect(controller).toBeDefined(); - }); -}); diff --git a/user-service/src/app/language/language.controller.ts b/user-service/src/app/language/language.controller.ts deleted file mode 100644 index 91baa9c..0000000 --- a/user-service/src/app/language/language.controller.ts +++ /dev/null @@ -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 { - return this.languageService.create(createLanguageDto); - } - - @Get() - async findAll(): Promise { - return this.languageService.findAll(); - } - - @Get(':id') - async findOne(@Param('id') id: string): Promise { - return this.languageService.findOne(id); - } - - @Put(':id') - async update(@Param('id') id: string, @Body() updateLanguageDto: UpdateLanguageDto): Promise { - return this.languageService.update(id, updateLanguageDto); - } - - @Delete(':id') - async remove(@Param('id') id: string): Promise { - return this.languageService.remove(id); - } -} \ No newline at end of file diff --git a/user-service/src/app/language/language.module.ts b/user-service/src/app/language/language.module.ts deleted file mode 100644 index 5f4b1dc..0000000 --- a/user-service/src/app/language/language.module.ts +++ /dev/null @@ -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 {} diff --git a/user-service/src/app/language/language.service.spec.ts b/user-service/src/app/language/language.service.spec.ts deleted file mode 100644 index b91e0ea..0000000 --- a/user-service/src/app/language/language.service.spec.ts +++ /dev/null @@ -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); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/user-service/src/app/language/language.service.ts b/user-service/src/app/language/language.service.ts deleted file mode 100644 index 0f346ed..0000000 --- a/user-service/src/app/language/language.service.ts +++ /dev/null @@ -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) {} - - async create(createLanguageDto: CreateLanguageDto): Promise { - 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 { - return this.languageModel.find().exec(); - } - - async findOne(id: string): Promise { - 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 { - 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 { - const result = await this.languageModel.deleteOne({ ID: id }).exec(); - if (result.deletedCount === 0) { - throw new NotFoundException(`Language with ID ${id} not found`); - } - } -} \ No newline at end of file