[translens] add test project

This commit is contained in:
Yangshun 2025-03-17 18:24:06 +08:00
parent 68b70ca57d
commit 2867e83cd0
11 changed files with 206 additions and 76 deletions

3
.gitignore vendored
View File

@ -45,3 +45,6 @@ crowdin.yml
# angular
.angular
# env
.env

View File

@ -0,0 +1,14 @@
{
"name": "i18n-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"translens": "translens"
},
"keywords": [],
"devDependencies": {
"translens": "workspace:0.0.0"
}
}

View File

@ -0,0 +1,5 @@
{
"hello": "Hello world!",
"bye": "Goodbye earth...",
"smart": "You're so smart, what a pancake!"
}

View File

@ -0,0 +1,12 @@
{
"hashes": {
"hello": "627b0c2c",
"bye": "48112765",
"smart": "553ab50e"
},
"hash": "c206299b",
"translatedLocales": [
"zh-CN",
"ja-JP"
]
}

View File

@ -0,0 +1,5 @@
{
"hello": "Hello world!",
"bye": "Goodbye earth...",
"smart": "あなたはとても賢いね、なんてパンケーキなんだ!"
}

View File

@ -0,0 +1,5 @@
{
"hello": "Hello world!",
"bye": "Goodbye earth...",
"smart": "你真聪明,真是个天才!"
}

View File

@ -0,0 +1,18 @@
{
"localeConfig": {
"source": "en-US",
"target": ["zh-CN", "ja-JP"]
},
"groups": [
{
"name": "App JSON",
"handler": "json",
"files": [
{
"source": "./src/locales/en-US.json",
"target": "./src/locales/{locale}.json"
}
]
}
]
}

View File

@ -38,7 +38,6 @@
"@codesandbox/sandpack-react": "2.13.8",
"@formatjs/intl": "^2.9.9",
"@formatjs/intl-localematcher": "^0.2.32",
"@gfe/translens": "workspace:0.0.0",
"@hookform/resolvers": "^3.3.2",
"@lexical/code": "^0.13.1",
"@lexical/headless": "^0.13.1",
@ -191,6 +190,7 @@
"strip-comments": "^2.0.1",
"supabase": "^1.115.5",
"tailwindcss": "^3.4.13",
"translens": "workspace:0.0.0",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.2",
"tsx": "^4.7.1",

View File

@ -1,8 +1,7 @@
{
"name": "@gfe/translens",
"name": "translens",
"version": "0.0.0",
"description": "Modern translation toolchain",
"author": "Nitesh Seram <niteshseram@gmail.com>",
"license": "MIT",
"type": "module",
"main": "dist/index.js",
@ -23,9 +22,9 @@
"prepublishOnly": "npm run verify"
},
"dependencies": {
"@ai-sdk/openai": "^0.0.33",
"@ai-sdk/deepseek": "^0.1.15",
"@clack/prompts": "^0.9.1",
"ai": "^3.2.8",
"ai": "^4.1.61",
"chalk": "^5.2.0",
"dotenv": "^16.3.1",
"glob": "^11.0.1",

View File

@ -1,25 +1,15 @@
import { ITranslationService } from '../interfaces';
import { generateText } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';
import { deepseek } from '@ai-sdk/deepseek';
export default class DeepSeekTranslationService implements ITranslationService {
private openai;
constructor() {
const apiKey = process.env.DEEPSEEK_API_KEY;
if (!apiKey) {
throw new Error('DEEPSEEK_API_KEY is not added.');
}
this.openai = createOpenAI({
apiKey,
});
}
private async translateAPI(prompt: string): Promise<any> {
const result = await generateText({
model: this.openai('gpt-4o-mini'),
prompt: prompt,
const { text } = await generateText({
model: deepseek('deepseek-chat'),
prompt,
});
return JSON.parse(result.text);
return JSON.parse(text);
}
private constructPrompt(
@ -28,9 +18,9 @@ export default class DeepSeekTranslationService implements ITranslationService {
): string {
return `You are a professional translator. Translate the following text to ${targetLocale}.
Maintain the original meaning, tone, and formatting. Only return the translated text, no explanations or additional content.
It is a JSON object, translate it values and return the translated content in the same format with its key and value.
It is a JSON object, translate its values and return the translated content in the same format with its key and value.
Text to translate:
JSON to translate:
${JSON.stringify(content)}`;
}
@ -39,7 +29,7 @@ ${JSON.stringify(content)}`;
targetLocale: string,
): Promise<Record<string, string>> {
const prompt = this.constructPrompt(items, targetLocale);
const translation = await this.translateAPI(prompt);
return translation;
return await this.translateAPI(prompt);
}
}

View File

@ -76,6 +76,12 @@ importers:
specifier: ^5.3.3
version: 5.3.3
apps/i18n-test:
devDependencies:
translens:
specifier: workspace:0.0.0
version: link:../../packages/translens
apps/socialmon:
dependencies:
'@ai-sdk/openai':
@ -262,9 +268,6 @@ importers:
'@formatjs/intl-localematcher':
specifier: ^0.2.32
version: 0.2.32
'@gfe/translens':
specifier: workspace:0.0.0
version: link:../../packages/translens
'@hookform/resolvers':
specifier: ^3.3.2
version: 3.3.2(react-hook-form@7.48.2)
@ -716,6 +719,9 @@ importers:
tailwindcss:
specifier: ^3.4.13
version: 3.4.13(ts-node@10.9.2)
translens:
specifier: workspace:0.0.0
version: link:../../packages/translens
ts-jest:
specifier: ^29.1.1
version: 29.1.1(@babel/core@7.24.7)(esbuild@0.17.19)(jest@29.7.0)(typescript@5.7.2)
@ -809,15 +815,15 @@ importers:
packages/translens:
dependencies:
'@ai-sdk/openai':
specifier: ^0.0.33
version: 0.0.33(zod@3.22.4)
'@ai-sdk/deepseek':
specifier: ^0.1.15
version: 0.1.15(zod@3.24.2)
'@clack/prompts':
specifier: ^0.9.1
version: 0.9.1
ai:
specifier: ^3.2.8
version: 3.2.8(react@18.3.1)(solid-js@1.8.17)(svelte@4.2.18)(vue@3.4.31)(zod@3.22.4)
specifier: ^4.1.61
version: 4.1.61(react@18.3.1)(zod@3.24.2)
chalk:
specifier: ^5.2.0
version: 5.3.0
@ -858,6 +864,29 @@ packages:
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
engines: {node: '>=0.10.0'}
/@ai-sdk/deepseek@0.1.15(zod@3.24.2):
resolution: {integrity: sha512-0sB3G71eXI7ND4fa9MwBIyN+tTwnH0MQs2Sc+8gGluMy6FtlQi1x49j0yWp1jWSp8E0T31zU7Po7U77NEM0Wxw==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/openai-compatible': 0.1.15(zod@3.24.2)
'@ai-sdk/provider': 1.0.11
'@ai-sdk/provider-utils': 2.1.13(zod@3.24.2)
zod: 3.24.2
dev: false
/@ai-sdk/openai-compatible@0.1.15(zod@3.24.2):
resolution: {integrity: sha512-iuylARLylTkaVYXKdgA1GeGU2TwANaJ3RlhJqmN0cVO5uEt3qVKvedrzR3jrQIyy9hu3gngsiXfFBMW2UQ7Ntg==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
dependencies:
'@ai-sdk/provider': 1.0.11
'@ai-sdk/provider-utils': 2.1.13(zod@3.24.2)
zod: 3.24.2
dev: false
/@ai-sdk/openai@0.0.33(zod@3.22.4):
resolution: {integrity: sha512-siVeHnagh08UFgdwflPdUKTdrVvfU/JWqSa8nCsMy6DvSri8T7zTzPZoCxXiMKPXkhQDd/KsaXhweOShGLQ1uQ==}
engines: {node: '>=18'}
@ -885,6 +914,22 @@ packages:
zod: 3.22.4
dev: false
/@ai-sdk/provider-utils@2.1.13(zod@3.24.2):
resolution: {integrity: sha512-kLjqsfOdONr6DGcGEntFYM1niXz1H05vyZNf9OAzK+KKKc64izyP4/q/9HX7W4+6g8hm6BnmKxu8vkr6FSOqDg==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
peerDependenciesMeta:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 1.0.11
eventsource-parser: 3.0.0
nanoid: 3.3.8
secure-json-parse: 2.7.0
zod: 3.24.2
dev: false
/@ai-sdk/provider@0.0.10:
resolution: {integrity: sha512-NzkrtREQpHID1cTqY/C4CI30PVOaXWKYytDR2EcytmFgnP7Z6+CrGIA/YCnNhYAuUm6Nx+nGpRL/Hmyrv7NYzg==}
engines: {node: '>=18'}
@ -892,6 +937,13 @@ packages:
json-schema: 0.4.0
dev: false
/@ai-sdk/provider@1.0.11:
resolution: {integrity: sha512-CPyImHGiT3svyfmvPvAFTianZzWFtm0qK82XjwlQIA1C3IQ2iku/PMQXi7aFyrX0TyMh3VTkJPB03tjU2VXVrw==}
engines: {node: '>=18'}
dependencies:
json-schema: 0.4.0
dev: false
/@ai-sdk/react@0.0.8(react@18.2.0)(zod@3.22.4):
resolution: {integrity: sha512-YASx575akiHuH8izwojwpA4NH7PqsezmRnz/Kmc/4dS4JN38uu4domd8y4fzOT/oO1nfdJ5xB+8aRa4NaQdu2Q==}
engines: {node: '>=18'}
@ -911,11 +963,11 @@ packages:
zod: 3.22.4
dev: false
/@ai-sdk/react@0.0.8(react@18.3.1)(zod@3.22.4):
resolution: {integrity: sha512-YASx575akiHuH8izwojwpA4NH7PqsezmRnz/Kmc/4dS4JN38uu4domd8y4fzOT/oO1nfdJ5xB+8aRa4NaQdu2Q==}
/@ai-sdk/react@1.1.23(react@18.3.1)(zod@3.24.2):
resolution: {integrity: sha512-R+PG9ya0GLs6orzt+1MxmjrWFuZM0gVs+l8ihBr1u+42wwkVeojY4CAtQjW4nrfGTVbdJYkl5y+r/VKfjr42aQ==}
engines: {node: '>=18'}
peerDependencies:
react: ^18 || ^19
react: ^18 || ^19 || ^19.0.0-rc
zod: ^3.0.0
peerDependenciesMeta:
react:
@ -923,11 +975,12 @@ packages:
zod:
optional: true
dependencies:
'@ai-sdk/provider-utils': 0.0.16(zod@3.22.4)
'@ai-sdk/ui-utils': 0.0.6(zod@3.22.4)
'@ai-sdk/provider-utils': 2.1.13(zod@3.24.2)
'@ai-sdk/ui-utils': 1.1.19(zod@3.24.2)
react: 18.3.1
swr: 2.2.0(react@18.3.1)
zod: 3.22.4
swr: 2.3.3(react@18.3.1)
throttleit: 2.1.0
zod: 3.24.2
dev: false
/@ai-sdk/solid@0.0.7(solid-js@1.8.17)(zod@3.22.4):
@ -978,6 +1031,21 @@ packages:
zod: 3.22.4
dev: false
/@ai-sdk/ui-utils@1.1.19(zod@3.24.2):
resolution: {integrity: sha512-rDHy2uxlPMt3jjS9L6mBrsfhEInZ5BVoWevmD13fsAt2s/XWy2OwwKmgmUQkdLlY4mn/eyeYAfDGK8+5CbOAgg==}
engines: {node: '>=18'}
peerDependencies:
zod: ^3.0.0
peerDependenciesMeta:
zod:
optional: true
dependencies:
'@ai-sdk/provider': 1.0.11
'@ai-sdk/provider-utils': 2.1.13(zod@3.24.2)
zod: 3.24.2
zod-to-json-schema: 3.24.4(zod@3.24.2)
dev: false
/@ai-sdk/vue@0.0.7(vue@3.4.31)(zod@3.22.4):
resolution: {integrity: sha512-bGDkYHdSDrIxS1EhjzLrzQecnDvLRr6ksx7yPg+V28J4+PzU5gH23M3Z2g71KIhX5B80Jrv8CsOFYDAKm3at5Q==}
engines: {node: '>=18'}
@ -5123,6 +5191,11 @@ packages:
resolution: {integrity: sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==}
engines: {node: '>=8.0.0'}
/@opentelemetry/api@1.9.0:
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
dev: false
/@opentelemetry/context-async-hooks@1.18.1(@opentelemetry/api@1.7.0):
resolution: {integrity: sha512-HHfJR32NH2x0b69CACCwH8m1dpNALoCTtpgmIWMNkeMGNUeKT48d4AX4xsF4uIRuUoRTbTgtSBRvS+cF97qwCQ==}
engines: {node: '>=14'}
@ -8324,44 +8397,27 @@ packages:
- vue
dev: false
/ai@3.2.8(react@18.3.1)(solid-js@1.8.17)(svelte@4.2.18)(vue@3.4.31)(zod@3.22.4):
resolution: {integrity: sha512-lcWABN/pQ3crTKr9UvteKuWwTtvhZCGtP/lwo02cRyfCMuGaOxK/E/VXklo8WabuVLk9l1CRXCWdQcw6peg11g==}
/ai@4.1.61(react@18.3.1)(zod@3.24.2):
resolution: {integrity: sha512-Y9SAyGJEeW23F6C7PSHZXYNEvbH2cqJm0rVW2AoeFaXFT13ttx8rAqs8wz2w466C1UB329yl5PXayFcHqofSEA==}
engines: {node: '>=18'}
peerDependencies:
openai: ^4.42.0
react: ^18 || ^19
svelte: ^3.0.0 || ^4.0.0
react: ^18 || ^19 || ^19.0.0-rc
zod: ^3.0.0
peerDependenciesMeta:
openai:
optional: true
react:
optional: true
svelte:
optional: true
zod:
optional: true
dependencies:
'@ai-sdk/provider': 0.0.10
'@ai-sdk/provider-utils': 0.0.16(zod@3.22.4)
'@ai-sdk/react': 0.0.8(react@18.3.1)(zod@3.22.4)
'@ai-sdk/solid': 0.0.7(solid-js@1.8.17)(zod@3.22.4)
'@ai-sdk/svelte': 0.0.7(svelte@4.2.18)(zod@3.22.4)
'@ai-sdk/ui-utils': 0.0.6(zod@3.22.4)
'@ai-sdk/vue': 0.0.7(vue@3.4.31)(zod@3.22.4)
eventsource-parser: 1.1.2
json-schema: 0.4.0
'@ai-sdk/provider': 1.0.11
'@ai-sdk/provider-utils': 2.1.13(zod@3.24.2)
'@ai-sdk/react': 1.1.23(react@18.3.1)(zod@3.24.2)
'@ai-sdk/ui-utils': 1.1.19(zod@3.24.2)
'@opentelemetry/api': 1.9.0
eventsource-parser: 3.0.0
jsondiffpatch: 0.6.0
nanoid: 3.3.6
react: 18.3.1
secure-json-parse: 2.7.0
sswr: 2.1.0(svelte@4.2.18)
svelte: 4.2.18
zod: 3.22.4
zod-to-json-schema: 3.22.5(zod@3.22.4)
transitivePeerDependencies:
- solid-js
- vue
zod: 3.24.2
dev: false
/ajv-keywords@3.5.2(ajv@6.12.6):
@ -10445,7 +10501,7 @@ packages:
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 5.62.0(eslint@8.34.0)(typescript@5.7.2)
'@typescript-eslint/parser': 5.62.0(eslint@8.34.0)(typescript@5.3.3)
debug: 3.2.7
eslint: 8.34.0
eslint-import-resolver-node: 0.3.9
@ -10486,7 +10542,7 @@ packages:
'@typescript-eslint/parser':
optional: true
dependencies:
'@typescript-eslint/parser': 5.62.0(eslint@8.34.0)(typescript@5.7.2)
'@typescript-eslint/parser': 5.62.0(eslint@8.34.0)(typescript@5.3.3)
array-includes: 3.1.7
array.prototype.findlastindex: 1.2.3
array.prototype.flat: 1.3.2
@ -10812,6 +10868,11 @@ packages:
engines: {node: '>=14.18'}
dev: false
/eventsource-parser@3.0.0:
resolution: {integrity: sha512-T1C0XCUimhxVQzW4zFipdx0SficT651NnkR0ZSH3yQwh+mFMdLfgjABVi4YtMTtaL4s168593DaoaRLMqryavA==}
engines: {node: '>=18.0.0'}
dev: false
/execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'}
@ -16897,13 +16958,14 @@ packages:
use-sync-external-store: 1.2.0(react@18.2.0)
dev: false
/swr@2.2.0(react@18.3.1):
resolution: {integrity: sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==}
/swr@2.3.3(react@18.3.1):
resolution: {integrity: sha512-dshNvs3ExOqtZ6kJBaAsabhPdHyeY4P2cKwRCniDVifBMoG/SVI7tfLWqPXriVspf2Rg4tPzXJTnwaihIeFw2A==}
peerDependencies:
react: ^16.11.0 || ^17.0.0 || ^18.0.0
react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
dependencies:
dequal: 2.0.3
react: 18.3.1
use-sync-external-store: 1.2.0(react@18.3.1)
use-sync-external-store: 1.4.0(react@18.3.1)
dev: false
/swrev@4.0.0:
@ -17158,6 +17220,11 @@ packages:
engines: {node: '>=10'}
dev: false
/throttleit@2.1.0:
resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
engines: {node: '>=18'}
dev: false
/through@2.3.8:
resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==}
dev: false
@ -17433,7 +17500,7 @@ packages:
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.4
'@types/node': 18.19.2
acorn: 8.12.0
acorn: 8.11.2
acorn-walk: 8.3.1
arg: 4.1.3
create-require: 1.1.1
@ -18029,10 +18096,10 @@ packages:
react: 18.2.0
dev: false
/use-sync-external-store@1.2.0(react@18.3.1):
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
/use-sync-external-store@1.4.0(react@18.3.1):
resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
dependencies:
react: 18.3.1
dev: false
@ -18604,9 +18671,21 @@ packages:
zod: 3.22.4
dev: false
/zod-to-json-schema@3.24.4(zod@3.24.2):
resolution: {integrity: sha512-0uNlcvgabyrni9Ag8Vghj21drk7+7tp7VTwwR7KxxXXc/3pbXz2PHlDgj3cICahgF1kHm4dExBFj7BXrZJXzig==}
peerDependencies:
zod: ^3.24.1
dependencies:
zod: 3.24.2
dev: false
/zod@3.22.4:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
dev: false
/zod@3.24.2:
resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==}
dev: false
/zwitch@2.0.4:
resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==}