i18n-tools
Provides internationalization MCP tools enabling AI agents to perform translations, locale management, and i18n operations.
README
@yyc3/i18n-core
<div align="center"> <img src="Public/Family-001.png" alt="YYC³ Family" width="100%" style="max-width: 896px; border-radius: 12px;" /> </div>
<br/>
ð YYC³ Production-Ready Internationalization Framework
髿§èœãæä»¶åãé¶äŸèµç i18n è§£å³æ¹æ¡ïŒäžäžºç°ä»£ Web åºçšè®Ÿè®¡
<p align="center"> <a href="https://www.npmjs.com/package/@yyc3/i18n-core"><img src="https://img.shields.io/npm/v/@yyc3/i18n-core.svg?style=flat-square&color=blue" alt="npm version" /></a> <a href="https://github.com/YYC-Cube/YYC3-i18n-Core/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/@yyc3/i18n-core.svg?style=flat-square&color=brightgreen" alt="MIT License" /></a> <br/> <img src="https://img.shields.io/badge/TypeScript-5.3+-3178c6?style=flat-square&logo=typescript&logoColor=white" alt="TypeScript" /> <img src="https://img.shields.io/node/v/%3E%3D16.0.0.svg?style=flat-square&color=339933" alt="Node.js >=16" /> <img src="https://img.shields.io/badge/dependencies-0-success?style=flat-square" alt="Zero Dependencies" /> <br/> <img src="https://img.shields.io/badge/tests-621%20passed-brightgreen?style=flat-square" alt="621 Tests Passed" /> <img src="https://img.shields.io/badge/coverage-96.81%25-brightgreen?style=flat-square" alt="96.81% Coverage" /> <img src="https://img.shields.io/badge/security-OWASP%20L4-blue?style=flat-square" alt="OWASP Level 4" /> </p>
æŠè¿°
@yyc3/i18n-core æ¯ YYC³ïŒYanYuCloudCubeïŒæºèœåºçšéŸäžçåœé ååºç¡è®Ÿæœå±ïŒäžºæŽäžªçææäŸå€è¯èšãAIç¿»è¯ãMCPåè®®éæèœåãå®äžä» æ¯äžäžªç¬ç«ç i18n æ¡æ¶ïŒæŽæ¯ YYC³ çæãäºé«äºæ äºåäºç»Žãæ žå¿ç念åšåœé åé¢åçå ·äœèœå°ã
åš YYC³ çæäžçå®äœ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â YYC³ æºèœåºçšçæ â
â â
â âââââââââââââââ âââââââââââââââ âââââââââââââââ â
â â YYC³-CLI â â YYC³-ϳ â â Family-PAI â â
â â ææ¡£çæ â â 讟计工å
· â â AIåºçšéŸ â â
â â åŒæ â â ç»ä»¶æä»¶ â â â â
â ââââââââ¬âââââââ ââââââââ¬âââââââ ââââââââ¬âââââââ â
â â â â â
â ââââââââââââââââââŒâââââââââââââââââ â
â â â
â ââââââââŒâââââââ â
â â @yyc3/i18n â â åœåé¡¹ç® â
â â -core â â
â ââââââââ¬âââââââ â
â â â
â âââââââââââââââŒââââââââââââââ â
â ⌠⌠⌠â
â ââââââââââââââ ââââââââââââ âââââââââââââ â
â â AIç¿»è¯åŒæ â âMCP Serverâ âICUçŒè¯åš â â
â â(OpenAI+ â â(AI Agent â â(10è¯èš+ â â
â â Ollama) â â å·¥å
·éæ) â â RTLæ¯æ) â â
â ââââââââââââââ ââââââââââââ âââââââââââââ â
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
äž YYC³-CLI çè¡æ¥
YYC³-CLI æ¯ YYC³ çæçææ¡£å
šçåœåšæçæåŒæïŒv2.0.0ïŒïŒèŽèޣ项ç®åå§åãæ ååææ¡£çæãDevOpsè¿ç»Žã@yyc3/i18n-core äžå
¶åœ¢æä»¥äžååïŒ
| åååºæ¯ | CLI è莣 | i18n-core è莣 |
|---|---|---|
| 项ç®åå§å | yyc3 init çæé¡¹ç®éªšæ¶ |
èªåšæ³šå ¥ i18n é 眮ïŒlocales/ + åŒæå®äŸïŒ |
| å€è¯èšææ¡£ | çæç¬Šå YYC³ æ åçææ¡£æ¶æ | 䞺çæçææ¡£æäŸ 10 è¯èšç¿»è¯æ¯æ |
| AI èµèœ | AI 驱åšçææ¡£/代ç çæ | AI ç¿»è¯åŒæïŒOpenAI + OllamaïŒå€çšåäž AI åºç¡è®Ÿæœ |
| MCP åè®® | AI Agent å·¥å ·éŸçŒæ | æäŸ i18n MCP Server äœäžº Agent å¯è°çšå·¥å · |
| CI/CD éæ | DevOps æµæ°Žçº¿çŒæ | æäŸ i18n audit/translate åœä»€åµå
¥æµæ°Žçº¿ |
æ žå¿ä»·åŒäž»åŒ
| 绎床 | äŒ ç» i18n æ¹æ¡ | @yyc3/i18n-core |
|---|---|---|
| AI ç¿»è¯ | é倿¥ SaaS / æåšç¿»è¯ | åçéæ OpenAI + Ollama ååŒæ |
| AI åäœ | æ AI Agent æ¥å£ | è¡äžéŠäžª i18n MCP ServerïŒ7 äžªå·¥å ·ïŒ |
| äŸèµéŸ | 3-10 䞪è¿è¡æ¶äŸèµ | é¶äŸèµ â æ äŸåºéŸé£é© |
| å®å š | åºç¡æ£å | OWASP L4 å®å šç©éµïŒReDoS鲿€/å¯é¥çåŒ/éçéå¶ïŒ |
| çæ | ç¬ç«å·¥å · | YYC³ æºèœåºçšéŸåçç»ä»¶ |
æç¥æ¹å: è¯Šè§ è¡äžææ¯è¶å¿åæäžå šéŸè·¯èœå°æ¹æ¡ â MCPåè®®çæçåïŒ15,382+ Server / 9700äžSDKæäžèœœïŒïŒi18n MCP Server å æ¯<1%ïŒ@yyc3/i18n-core æ£å€äºè¿äžªèæµ·èµéçæ žå¿äœçœ®ã
ᅵᅵ ç®åœ
- æŠè¿°
- ç¹æ§æŠè§
- 䞺ä»ä¹éæ© @yyc3/i18n-core
- å®è£ æå
- å¿«éåŒå§
- æ¶æè®Ÿè®¡
- æ žå¿æš¡å诊解
- åè·¯åŸå¯Œå ¥ïŒTree ShakingïŒ
- API åè
- é«çº§åèœ
- æäœ³å®è·µ
- æµè¯èŠç
- æ§èœåºå
- å®å šç¹æ§
- åžžè§é®é¢
- è¿ç§»æå
- èŽ¡ç®æå
- License
âš ç¹æ§æŠè§
ð¯ æ žå¿äŒå¿
| ç¹æ§ | æè¿° | ç¶æ |
|---|---|---|
| é¶äŸèµè¿è¡æ¶ | æ ä»»äœç产äŸèµïŒçº¯ TypeScript å®ç° | â |
| 10 ç§è¯èšå 眮 | en/zh-CN/zh-TW/ja/ko/fr/de/es/pt-BR/ar(RTL) | â |
| AI ç¿»è¯éæ | OpenAI + Ollama æ¬å°æš¡åæ¯æ | â |
| MCP åè®®åç | AI Agent å·¥å ·éæïŒ7 䞪 i18n å·¥å · | â |
| ICU MessageFormat | 宿Žå®ç°ïŒ12 ç§è¯æ³ç±»å | â |
| RTL åçæ¯æ | é¿æäŒ¯è¯ç RTL è¯èšåžå±èªåšå€ç | â |
| LRU çŒåç³»ç» | <0.1ms çŒååœäžååºæ¶éŽ | â |
| æä»¶åæ¶æ | 坿©å±ççåœåšæé©åç³»ç» | â |
| äŒäžçº§å®å š | OWASP L4 å®å šæ å | â |
ð äžäž»æµæ¹æ¡å¯¹æ¯
| ç¹æ§ | @yyc3/i18n-core | react-i18next | vue-i18n | typesafe-i18n |
|---|---|---|---|---|
| äŸèµæ°é | 0 | 3+ | 2+ | 0 |
| æå å€§å° | ~15KB | ~33KB | ~1.5MB | ~1KB |
| AI ç¿»è¯ | â å 眮 | æä»¶ | æä»¶ | â |
| MCP åè®® | â å 眮 | â | â | â |
| ICU MessageFormat | â å®æŽ | æä»¶ | åºç¡ | åºç¡ |
| RTL æ¯æ | â åç | é 眮 | é 眮 | â |
| å®å šç级 | OWASP L4 | åºç¡ | åºç¡ | â |
| äžæäŒå | 10 è¯èš | é 眮 | é 眮 | é 眮 |
ð€ 䞺ä»ä¹éæ© @yyc3/i18n-core?
1ïžâ£ çæ£çé¶äŸèµ
npm install @yyc3/i18n-core
# ä»
æ€äžäžªå
ïŒæ å
¶ä»äŸèµ
2ïžâ£ åŒç®±å³çšçäžææ¯æ
import { i18n, t } from '@yyc3/i18n-core';
// 10 ç§è¯èšå³æ¶å¯çš
await i18n.setLocale('zh-CN'); // ç®äœäžæ
await i18n.setLocale('zh-TW'); // ç¹äœäžæ
await i18n.setLocale('ja'); // æ¥è¯
await i18n.setLocale('ko'); // é©è¯
// ... æŽå€
3ïžâ£ AI èµèœç¿»è¯
import { AIProviderManager, OpenAIProvider } from '@yyc3/i18n-core/ai';
const ai = new AIProviderManager();
ai.register(new OpenAIProvider({ apiKey: 'your-key' }));
const result = await ai.translate({
sourceText: 'Hello World',
sourceLocale: 'en',
targetLocale: 'zh-CN',
});
console.log(result.translatedText); // "äœ å¥œäžç"
4ïžâ£ MCP åè®®åçéæ
import { MCPServer, registerI18nTools, StdioTransport } from '@yyc3/i18n-core/mcp';
const server = new MCPServer({
name: 'i18n-tools',
version: '1.4.0',
transport: new StdioTransport(),
});
registerI18nTools(server);
await server.start();
// ç°åš Claude/Cursor ç AI å·¥å
·å¯ä»¥äœ¿çš i18n åèœäºïŒ
ðŠ å®è£ æå
åçœ®èŠæ±
- Node.js >= 16.0.0
- TypeScript >= 5.0 (æšèïŒäœä¹æ¯æ JavaScript)
å®è£ åœä»€
# äœ¿çš npm
npm install @yyc3/i18n-core
# äœ¿çš pnpm (æšè)
pnpm add @yyc3/i18n-core
# äœ¿çš yarn
yarn add @yyc3/i18n-core
éªè¯å®è£
import { i18n, t } from '@yyc3/i18n-core';
console.log(t('common.welcome')); // "Welcome"
console.log('â
@yyc3/i18n-core å®è£
æå');
ð å¿«éåŒå§
1. æç®äœ¿çš â é¶é 眮å¯åš
import { i18n, t } from '@yyc3/i18n-core';
// çŽæ¥äœ¿çšïŒæ éé
眮
t('common.welcome'); // "Welcome"
// 忢è¯èš
await i18n.setLocale('zh-CN');
t('common.welcome'); // "欢è¿"
2. 垊æä»¶ç宿Žé 眮
import { i18n, t, I18nEngine } from '@yyc3/i18n-core';
import {
createConsoleLogger,
MissingKeyReporter,
PerformanceTracker,
} from '@yyc3/i18n-core/plugins';
// åå»ºåŒæå®äŸ
const engine = new I18nEngine({
defaultLocale: 'en',
fallbackLocale: 'en',
cache: {
maxSize: 1000,
ttl: 3600000, // 1å°æ¶
},
});
// 泚åæä»¶
engine.plugins.register(createConsoleLogger());
engine.plugins.register(new MissingKeyReporter().createPlugin());
engine.plugins.register(
new PerformanceTracker({ slowThreshold: 10 }).createPlugin()
);
// åå§å
await engine.init();
// 䜿çš
engine.t('greeting', { name: 'World' }); // "Hello, World!"
3. React 项ç®éæ
// App.tsx
import { useEffect, useState } from 'react';
import { i18n, t } from '@yyc3/i18n-core';
function App() {
const [locale, setLocale] = useState('en');
useEffect(() => {
i18n.setLocale(locale);
}, [locale]);
return (
<div>
<h1>{t('app.title')}</h1>
<p>{t('greeting', { name: 'User' })}</p>
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
<option value="en">English</option>
<option value="zh-CN">äžæ</option>
<option value="ja">æ¥æ¬èª</option>
</select>
</div>
);
}
4. Vue 项ç®éæ
<template>
<div>
<h1>{{ $t('app.title') }}</h1>
<button @click="changeLocale('zh-CN')">äžæ</button>
<button @click="changeLocale('en')">English</button>
</div>
</template>
<script setup lang="ts">
import { i18n, t } from '@yyc3/i18n-core';
import { ref } from 'vue';
const changeLocale = async (locale: string) => {
await i18n.setLocale(locale);
};
</script>
5. Node.js / å端䜿çš
// server.ts
import { I18nEngine } from '@yyc3/i18n-core';
const i18n = new I18nEngine({
defaultLocale: 'zh-CN',
});
export function middleware(req, res, next) {
const locale = req.headers['accept-language']?.split(',')[0] || 'zh-CN';
i18n.setLocale(locale);
req.t = (key, params?) => i18n.t(key, params);
next();
}
// åšè·¯ç±äžäœ¿çš
app.get('/api/hello', (req, res) => {
res.json({ message: req.t('hello') });
});
ðïž æ¶æè®Ÿè®¡
å屿¶æ
âââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ
â Application Layer â
â (React / Vue / Angular / Node.js) â
âââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââââââââââ
â
âââââââââââââââââââââââââŒââââââââââââââââââââââââââââââââââââââ
â Public API Layer â
â i18n / t / I18nEngine / PluginManager â
âââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââââââââââ
â
âââââââââââââââââŒââââââââââââââââ¬ââââââââââââââââ
⌠⌠⌠âŒ
âââââââââââââ âââââââââââââ âââââââââââââ âââââââââââââ
â Core â â Cache â â Plugins â â Formats â
â Engine â â LRU â â System â â ICU/MF â
âââââââ¬ââââââ âââââââ¬ââââââ âââââââ¬ââââââ âââââââ¬ââââââ
â â â â
âââââââââââââââââŽââââââââââââââââŽââââââââââââââââ
â
âââââââââââââââââŒââââââââââââââââ¬ââââââââââââââââ
⌠⌠⌠âŒ
âââââââââââââ âââââââââââââ âââââââââââââ âââââââââââââ
â AI â â MCP â â Security â â RTL â
â Translationâ â Server â â OWASP L4 â â Utils â
âââââââââââââ âââââââââââââ âââââââââââââ âââââââââââââ
æš¡åè莣
| æš¡å | æä»¶è·¯åŸ | è莣 | å€æåºŠ |
|---|---|---|---|
| Core Engine | lib/engine.ts |
ç¿»è¯åŒæãè¯èšåæ¢ãåæ°æåŒ | âââ |
| Cache System | lib/cache.ts |
LRU çŒåãTTL è¿æãç»è®¡ | ââ |
| Plugin System | lib/plugins.ts |
çåœåšæé©åãäºä»¶è®¢é | ââ |
| ICU Engine | lib/icu/* |
MessageFormat è§£æäžçŒè¯ | âââ |
| AI Translation | lib/ai/* |
LLM ç¿»è¯ã莚éè¯äŒ° | âââ |
| MCP Server | lib/mcp/* |
åè®®å®ç°ãå·¥å ·æ³šå | âââ |
| Security | lib/security/* |
ReDoS鲿€ãæ³šå ¥æ£æµ | ââ |
| RTL Utils | lib/rtl-utils.ts |
åžå±éåãæ¹åæ£æµ | â |
æ°æ®æµ
çšæ·è°çš t(key, params)
â
Plugin.beforeTranslate()
â
Cache Lookup â Hit? â Return Cached Result
â Miss
ICU Parser â Parse Syntax Tree
â
Formatter â Interpolate Parameters
â
Plugin.afterTranslate()
â
Cache.Store(Result)
â
Return Translated String
ðŠ æ žå¿æš¡å诊解
1. Core Engine (@yyc3/i18n-core)
ç¿»è¯åŒæçæ žå¿ïŒæäŸå®æŽç i18n èœåã
import { I18nEngine, i18n, t } from '@yyc3/i18n-core';
// æ¹åŒ1: 䜿çšå
šå±åäŸ (æšèç®ååºæ¯)
t('welcome'); // "Welcome"
t('greeting', { name: 'World' }); // "Hello, World!"
// æ¹åŒ2: å建ç¬ç«å®äŸ (æšèå€æåºæ¯)
const engine = new I18nEngine({
defaultLocale: 'en',
fallbackLocale: 'en',
debug: false,
});
await engine.init();
// 忢è¯èš
await engine.setLocale('zh-CN');
// æ¹éç¿»è¯
const results = await engine.batchTranslate(['key1', 'key2', 'key3']);
// è·åç»è®¡ä¿¡æ¯
const stats = engine.getStats();
console.log(stats.cacheHits, stats.cacheMisses);
// 订é
è¯èšåæŽ
engine.onLocaleChange((from, to) => {
console.log(`Locale changed: ${from} -> ${to}`);
});
I18nEngineConfig æ¥å£
interface I18nEngineConfig {
defaultLocale?: string; // é»è®€è¯èš: 'en'
fallbackLocale?: string; // åéè¯èš: 'en'
debug?: boolean; // è°è¯æš¡åŒ: false
cache?: CacheConfig; // çŒåé
眮
plugins?: I18nPlugin[]; // åå§æä»¶å衚
onError?: (error: Error) => void; // é误å€ç
missingKeyHandler?: (key: string) => string; // 猺倱é®å€ç
}
2. Cache System (@yyc3/i18n-core/cache)
髿§èœ LRU çŒåïŒæŸèæåç¿»è¯æ§èœã
import { LRUCache } from '@yyc3/i18n-core/cache';
// å建çŒåå®äŸ
const cache = new LRUCache<string, string>({
maxSize: 1000, // æå€§çŒåæ¡ç®
ttl: 3600000, // è¿ææ¶éŽ (1å°æ¶)
});
// ååæ°æ®
cache.set('key', 'value');
const value = cache.get('key'); // "value"
// çŒåæªåœäž
cache.get('nonexistent'); // undefined
// è·åç»è®¡ä¿¡æ¯
const stats: CacheStats = cache.getStats();
console.log(stats.hits, stats.misses, stats.size);
// æåšæž
ç
cache.clear();
cache.delete('key');
æ§èœææ
| æäœ | æ¶éŽå€æåºŠ | å¹³åèæ¶ |
|---|---|---|
| get() | O(1) | <0.1ms |
| set() | O(1) | <0.1ms |
| æ¹éæ¥æŸ | O(n) | <1ms (100 keys) |
3. Plugin System (@yyc3/i18n-core/plugins)
坿©å±çæä»¶æ¶æïŒæ¯æçåœåšæé©åã
import {
PluginManager,
createConsoleLogger,
MissingKeyReporter,
PerformanceTracker,
} from '@yyc3/i18n-core/plugins';
// 泚åå
眮æä»¶
i18n.plugins.register(createConsoleLogger());
i18n.plugins.register(new MissingKeyReporter().createPlugin());
i18n.plugins.register(new PerformanceTracker({ slowThreshold: 10 }).createPlugin());
// èªå®ä¹æä»¶
i18n.plugins.register({
name: 'analytics-plugin',
beforeTranslate(key: string) {
console.log(`[Analytics] Translating: ${key}`);
// è¿å true ç»§ç»æ§è¡ïŒè¿å false äžæ
return true;
},
afterTranslate(result: string, key: string) {
console.log(`[Analytics] Result: ${result}`);
},
onLocaleChange(from: string, to: string) {
console.log(`[Analytics] Locale: ${from} -> ${to}`);
},
});
// ç§»é€æä»¶
i18n.plugins.unregister('analytics-plugin');
å 眮æä»¶å衚
| æä»¶å | çšé | é 眮项 |
|---|---|---|
| ConsoleLogger | åŒåè°è¯æ¥å¿ | æ |
| MissingKeyReporter | ç产ç¯å¢çŒºå€±é®çæ§ | reportUrl, threshold |
| PerformanceTracker | æ§èœææ æ¶é | slowThreshold, percentiles |
4. ICU MessageFormat (@yyc3/i18n-core/icu)
宿Žç ICU MessageFormat å®ç°ïŒæ¯æå€æ°ãéæ©çå€æè¯æ³ã
import { ICUParser, ICUCompiler } from '@yyc3/i18n-core/icu';
// è§£æ ICU è¯æ³
const parser = new ICUParser();
const ast = parser.parse('{count, plural, one {# item} other {# items}}');
// çŒè¯å¹¶æž²æ
const compiler = new ICUCompiler({ locale: 'en' });
const result = compiler.compile(ast, { count: 5 });
console.log(result); // "5 items"
// åšåŒæäžçŽæ¥äœ¿çš (èªå𿣿µ ICU è¯æ³)
t('items_count', { count: 5 }); // èªåšè·¯ç±å° ICU çŒè¯åš
æ¯æç ICU è¯æ³
| è¯æ³ç±»å | ç€ºäŸ | 诎æ |
|---|---|---|
| Plural | {count, plural, one {...} other {...}} |
倿°è§å |
| Select | {gender, select, male {...} female {...}} |
æ¡ä»¶éæ© |
| SelectOrdinal | {rank, selectOrdinal, one {...} two {...}} |
åºæ°è¯ |
| Number | {price, number, ::currency/USD} |
æ°åæ ŒåŒå |
| Date | {date, date, full} |
æ¥ææ ŒåŒå |
| Time | {time, time, short} |
æ¶éŽæ ŒåŒå |
| Offset | {offset, plural, offset:1 ...} |
åç§»é |
5. AI Translation (@yyc3/i18n-core/ai)
LLM 驱åšçæºèœç¿»è¯ïŒæ¯æ OpenAI åæ¬å° Ollamaã
import {
AIProviderManager,
OpenAIProvider,
OllamaProvider,
QualityEstimator,
} from '@yyc3/i18n-core/ai';
// å建 AI 管çåš
const ai = new AIProviderManager();
// 泚å OpenAI Provider
ai.register(new OpenAIProvider({
apiKey: process.env.OPENAI_API_KEY!,
model: 'gpt-4o-mini',
}));
// ææ³šå Ollama Provider (å
莹æ¬å°æš¡å)
ai.register(new OllamaProvider({
baseUrl: 'http://localhost:11434',
model: 'qwen2.5:3b',
}));
// æ§è¡ç¿»è¯
const result = await ai.translate({
sourceText: 'Hello World',
sourceLocale: 'en',
targetLocale: 'zh-CN',
context: 'UI label for welcome message',
});
console.log(result.translatedText); // "äœ å¥œäžç"
console.log(result.confidence); // 0.95
// 莚éè¯äŒ°
const qe = new QualityEstimator();
const quality = await qe.estimate({
sourceText: 'Hello World',
translatedText: 'äœ å¥œäžç',
sourceLocale: 'en',
targetLocale: 'zh-CN',
});
console.log(quality.score); // 0.98
console.log(quality.issues); // [] (æ é®é¢)
æ¯æç AI Provider
| Provider | ç±»å | ææ¬ | å»¶è¿ | éçšåºæ¯ |
|---|---|---|---|---|
| OpenAI | äºç«¯ API | ð°ð° | äœ (<2s) | ç产ç¯å¢ |
| Ollama | æ¬å°æš¡å | å 莹 | äž (~3s) | åŒå/犻线 |
6. MCP Server (@yyc3/i18n-core/mcp)
Model Context Protocol æå¡ç«¯ïŒè®© AI Agent çŽæ¥äœ¿çš i18n å·¥å ·ã
import {
MCPServer,
registerI18nTools,
StdioTransport,
} from '@yyc3/i18n-core/mcp';
// å建 MCP Server
const server = new MCPServer({
name: 'yyc3-i18n-tools',
version: '1.4.0',
transport: new StdioTransport(),
});
// 泚å 7 䞪 i18n å·¥å
·
registerI18nTools(server);
// å¯åšæå¡
await server.start();
console.log('MCP Server running...');
// å¯çšå·¥å
·:
// 1. search_translations - æçŽ¢ç¿»è¯
// 2. add_translation_key - æ·»å ç¿»è¯é®
// 3. translate_key - ç¿»è¯å䞪é®
// 4. check_missing_keys - æ£æ¥çŒºå€±é®
// 5. get_locale_stats - è·åè¯èšç»è®¡
// 6. set_locale - 讟眮åœåè¯èš
// 7. quality_report - ç¿»è¯èŽšéæ¥å
MCP å·¥å ·è¯Šæ
| å·¥å ·å | åèœ | åæ° |
|---|---|---|
search_translations |
æçŽ¢ç¿»è¯å 容 | query, locale, limit |
add_translation_key |
æ·»å æ°ç¿»è¯é® | key, translations |
translate_key |
ç¿»è¯æå®é® | key, targetLocale |
check_missing_keys |
æ£æ¥çŒºå€±çç¿»è¯é® | locale |
get_locale_stats |
è·åè¯èšç»è®¡ä¿¡æ¯ | - |
set_locale |
讟眮åœåè¯èš | locale |
quality_report |
çæèŽšéæ¥å | locale |
7. RTL Support (@yyc3/i18n-core â å
眮)
RTL (Right-to-Left) è¯èšçåçæ¯æã
import {
isRTL,
setupDocumentDirection,
flipSpacing,
getAlignment,
createMirroredLayout,
} from '@yyc3/i18n-core';
// æ£æµæ¯åŠäžº RTL è¯èš
isRTL('ar'); // true
isRTL('he'); // true
isRTL('en'); // false
// èªåšè®Ÿçœ®ææ¡£æ¹å
setupDocumentDirection('ar');
// <html dir="rtl" lang="ar">
// CSS 屿§ç¿»èœ¬
flipSpacing({ marginLeft: 10, marginRight: 20 }, 'rtl');
// â { marginLeft: 20, marginRight: 10 }
// è·åå¯¹éœæ¹åŒ
getAlignment('ltr'); // 'left'
getAlignment('rtl'); // 'right'
// å建éååžå±
const layout = createMirroredLayout('rtl');
layout.mainAxis; // 'right'
layout.crossAxis; // 'left'
æ¯æç RTL è¯èš
| è¯èš | 代ç | æ¹å |
|---|---|---|
| é¿æäŒ¯è¯ | ar | RTL |
| åžäŒ¯æ¥è¯ | he | RTL |
| æ³¢æ¯è¯ | fa | RTL |
| ä¹å°éœè¯ | ur | RTL |
ð³ åè·¯åŸå¯Œå ¥ïŒTree ShakingïŒ
æéåŒå ¥ïŒæèŽäŒåæå äœç§¯
// å
šéšåèœ (~15KB gzipped)
import { i18n, t, I18nEngine } from '@yyc3/i18n-core'
// ä»
çŒåç³»ç» (~3KB gzipped)
import { LRUCache } from '@yyc3/i18n-core/cache'
// ä»
æä»¶ç³»ç» (~4KB gzipped)
import { PluginManager, createConsoleLogger } from '@yyc3/i18n-core/plugins'
// ä»
ICU åŒæ (~5KB gzipped)
import { ICUParser, ICUCompiler } from '@yyc3/i18n-core/icu'
// ä»
AI ç¿»è¯ (~4KB gzipped)
import { AIProviderManager, OpenAIProvider } from '@yyc3/i18n-core/ai'
// ä»
MCP æå¡ç«¯ (~3KB gzipped)
import { MCPServer, registerI18nTools } from '@yyc3/i18n-core/mcp'
å¯çšåè·¯åŸ
| åè·¯åŸ | 倧å°äŒ°è®¡(gzipped) | 富åºå 容 | éçšåºæ¯ |
|---|---|---|---|
. |
~15KB | å šéšåèœ | å°åé¡¹ç® / å¿«éåå |
./cache |
~3KB | LRU Cache ç³»ç» | éèŠé«æ§èœçŒå |
./plugins |
~4KB | æä»¶ç®¡çåš + å 眮æä»¶ | éèŠæ©å±åèœ |
./icu |
~5KB | ICU è§£æåš/çŒè¯åš | å€ææ¶æ¯æ ŒåŒ |
./ai |
~4KB | AI ç¿»è¯ + 莚éè¯äŒ° | éèŠ LLM ç¿»è¯ |
./mcp |
~3KB | MCP Server + Transport | AI Agent éæ |
æå äœç§¯å¯¹æ¯
åºæ¯ | æªäŒå | Tree Shakingå | èç
-------------------------|--------|----------------|------
宿Žå¯Œå
¥ | 15KB | 15KB | -
ä»
çš Core + Cache | 15KB | 8KB | 47%
ä»
çš ICU åŒæ | 15KB | 5KB | 67%
ä»
çš AI Translation | 15KB | 4KB | 73%
ä»
çš MCP Server | 15KB | 3KB | 80%
ð API åè
æ žå¿å¯Œåº
// ====== äž»å
¥å£ ======
import {
// Engine
I18nEngine, i18n, t,
// Cache
LRUCache,
type CacheConfig, type CacheStats,
// Plugins
PluginManager,
createConsoleLogger, MissingKeyReporter, PerformanceTracker,
type I18nContext, type I18nPlugin,
// Formatter
formatRelativeTime, interpolate, pluralize,
type TranslateParams,
// Locale Detection
detectSystemLocale, isChineseLocale, normalizeLocale,
type LocaleDetectionResult,
// RTL Utilities
isRTL, setupDocumentDirection, flipSpacing, getAlignment,
getDirection, getOppositeAlignment, mirrorPosition,
createMirroredLayout, transformClassForRTL,
type HorizontalAlignment, type TextDirection,
// Types
type Locale, type RTLLocale, type TranslationMap,
} from '@yyc3/i18n-core'
// ====== åè·¯åŸå¯Œå
¥ ======
// Cache
import { LRUCache } from '@yyc3/i18n-core/cache'
// Plugins
import { PluginManager, createConsoleLogger } from '@yyc3/i18n-core/plugins'
// ICU
import { ICUParser, ICUCompiler } from '@yyc3/i18n-core/icu'
// AI
import { AIProviderManager, OpenAIProvider, QualityEstimator } from '@yyc3/i18n-core/ai'
// MCP
import { MCPServer, registerI18nTools, StdioTransport } from '@yyc3/i18n-core/mcp'
æ žå¿ API
t() â ç¿»è¯åœæ°
function t(key: string, params?: TranslateParams): string;
// åºæ¬çšæ³
t('welcome'); // "Welcome"
// åæ°æåŒ
t('greeting', { name: 'World' }); // "Hello, World!"
// åµå¥å¯¹è±¡
t('user.profile.name'); // ä»åµå¥å¯¹è±¡è·å
// ICU è¯æ³ (èªå𿣿µ)
t('items', { count: 5 }); // "5 items"
i18n â å
šå±åäŸ
// å
šå±åäŸïŒæ éå建å®äŸ
const i18n: I18nEngine;
// 忢è¯èš
await i18n.setLocale('zh-CN');
// è·ååœåè¯èš
i18n.currentLocale; // 'zh-CN'
// æ¹éç¿»è¯
const results = await i18n.batchTranslate(['k1', 'k2', 'k3']);
// è·åç»è®¡
const stats = i18n.getStats();
// äºä»¶çå¬
i18n.onLocaleChange((from, to) => {});
I18nEngine â åŒæç±»
class I18nEngine {
constructor(config?: I18nEngineConfig);
init(): Promise<void>;
destroy(): Promise<void>;
setLocale(locale: string): Promise<void>;
t(key: string, params?: TranslateParams): string;
batchTranslate(keys: string[]): Promise<Record<string, string>>;
getTranslations(): TranslationMap;
getStats(): EngineStats;
onLocaleChange(callback: (from: string, to: string) => void): () => void;
plugins: PluginManager;
}
ð§ é«çº§åèœ
1. åœåç©ºéŽ (Namespaces)
import { createNamespace } from '@yyc3/i18n-core';
// å建åœå空éŽ
const userNS = createNamespace('user');
const productNS = createNamespace('product');
// 䜿çšåœå空éŽ
userNS.t('profile.name'); // user.profile.name
productNS.t('detail.title'); // product.detail.title
2. è°è¯æš¡åŒ
const engine = new I18nEngine({ debug: true });
// æµè§åšæ§å¶å°è®¿é®
window.__i18n_debug__ = {
engine,
getCurrentState: () => ({
locale: engine.currentLocale,
cache: engine.cache.getStats(),
plugins: engine.plugins.list(),
}),
};
// åŒåæ¶æ¥çç¶æ
console.log(window.__i18n_debug__.getCurrentState());
3. å€å®äŸæ¯æ
import { I18nEngine } from '@yyc3/i18n-core';
// å建å€äžªç¬ç«å®äŸ
const adminI18n = new I18nEngine({ defaultLocale: 'zh-CN' });
const userI18n = new I18nEngine({ defaultLocale: 'en' });
// åèªç¬ç«è¿è¡
adminI18n.t('dashboard.title'); // äžæ
userI18n.t('home.welcome'); // English
4. èªå®ä¹é误å€ç
const engine = new I18nEngine({
onError: (error) => {
// åéå°é误远螪æå¡
Sentry.captureException(error);
},
missingKeyHandler: (key) => {
console.warn(`[i18n] Missing key: ${key}`);
return `[MISSING: ${key}]`; // è¿åå äœç¬Š
},
});
5. æ§èœçæ§
import { PerformanceTracker } from '@yyc3/i18n-core/plugins';
const tracker = new PerformanceTracker({
slowThreshold: 10, // æ
¢æ¥è¯¢éåŒ (ms)
percentiles: [50, 90, 95, 99],
}).createPlugin();
i18n.plugins.register(tracker);
// è·åæ§èœæ¥å
const report = tracker.getReport();
console.log(report.percentiles.p95); // 95åäœå»¶è¿
console.log(report.slowQueries); // æ
¢æ¥è¯¢å衚
ðš æäœ³å®è·µ
â æšèåæ³
-
䜿çšå šå±åäŸè¿è¡ç®å项ç®
import { i18n, t } from '@yyc3/i18n-core'; t('key'); // ç®æŽæäº -
䜿çšç¬ç«å®äŸè¿è¡å€§å项ç®
const engine = new I18nEngine({ /* config */ }); -
å©çš Tree Shaking åå°äœç§¯
import { ICUParser } from '@yyc3/i18n-core/icu'; // ä» åŒå ¥æéæš¡å -
å¯çšç产ç¯å¢æä»¶
if (process.env.NODE_ENV === 'production') { i18n.plugins.register(new MissingKeyReporter().createPlugin()); } -
ç»å AI ç¿»è¯æåæç
const ai = new AIProviderManager(); ai.register(new OllamaProvider()); // å 莹æ¬å°ç¿»è¯
â é¿å åæ³
-
äžèŠåšåŸªç¯äžé¢ç¹è°çš
setLocale// â é误: æ§èœé®é¢ for (const item of items) { await i18n.setLocale(item.locale); } // â æ£ç¡®: æ¹éå€ç const translations = await i18n.batchTranslate(keys); -
äžèŠå¿œç¥é误å€ç
// â é误: å¯èœæåŒåžž t(userProvidedKey); // â æ£ç¡®: é 眮 missingKeyHandler const engine = new I18nEngine({ missingKeyHandler: (key) => `[${key}]`, }); -
äžèŠåšç产ç¯å¢åŒå¯ debug æš¡åŒ
// â é误: æ³é²å éšä¿¡æ¯ const engine = new I18nEngine({ debug: true }); // â æ£ç¡®: ä» åŒåç¯å¢ const engine = new I18nEngine({ debug: process.env.NODE_ENV === 'development', });
𧪠æµè¯èŠç
æµè¯ç©éµ
| æš¡å | æµè¯æä»¶ | çšäŸæ° | éè¿ç | èŠçç |
|---|---|---|---|---|
| Core Engine | engine-v2.test.ts | 45 | 100% | 94% |
| Cache | (å«åš engine tests) | 30 | 100% | 96% |
| Plugins | plugins.test.ts | 25 | 100% | 91% |
| Formatter | formatter.test.ts | 35 | 100% | 93% |
| Detector | detector.test.ts | 20 | 100% | 89% |
| RTL Utils | rtl-utils.test.ts | 28 | 100% | 92% |
| Translate | translate.test.ts, translate-full.test.ts | 60 | 100% | 95% |
| ICU Parser/Compiler | icu/parser-compiler.test.ts | 40 | 100% | 90% |
| AI Providers | ai/providers.test.ts | 35 | 100% | 87% |
| Quality Estimator | ai/quality-estimator.test.ts | 25 | 100% | 85% |
| MCP Server | mcp/server.test.ts, mcp/i18n-tools.test.ts | 40 | 100% | 88% |
| Security | security/*.test.ts | 30 | 100% | 93% |
| Infrastructure | infra/*.test.ts | 30 | 100% | 90% |
| æ»è®¡ | 28 files | 443 | â 100% | 92.5% |
è¿è¡æµè¯
# å
šéæµè¯
pnpm test
# ç嬿š¡åŒ (åŒåæ¶)
pnpm test:watch
# èŠççæ¥å
pnpm test:coverage
# å䞪æä»¶
pnpm test -- engine-v2.test.ts
# å¹é
æµè¯å
pnpm test -- -t "should translate with interpolation"
â¡ æ§èœåºå
ååºæ¶éŽ (Node.js 20, M2 Mac)
| æäœ | å¹³åèæ¶ | P99 èæ¶ | QPS |
|---|---|---|---|
| ç®åç¿»è¯ (çŒååœäž) | 0.02ms | 0.05ms | 50,000+ |
| åžŠåæ°ç¿»è¯ | 0.05ms | 0.12ms | 20,000+ |
| ICU 倿°è§å | 0.15ms | 0.35ms | 6,500+ |
| æ¹éç¿»è¯ (100 keys) | 8ms | 15ms | 12,000+ |
| AI ç¿»è¯ (Ollama) | 1500ms | 3000ms | 0.67 |
| AI ç¿»è¯ (OpenAI) | 800ms | 2000ms | 1.25 |
å åå çš
| åºæ¯ | å åå çš | 诎æ |
|---|---|---|
| ç©ºåŒæ | ~2MB | åºç¡åŒé |
| å 蜜 1 è¯èš | ~5MB | å«ç¿»è¯æ°æ® |
| å 蜜 10 è¯èš | ~25MB | å šéšå 眮è¯èš |
| çŒå 10000 æ¡ç® | ~8MB | LRU Cache |
| AI Provider | ~50MB | æš¡åå 蜜 |
ð¡ïž å®å šç¹æ§
OWASP Level 4 å®å šæ å
| å®å šç»ŽåºŠ | å®ç°æ¹åŒ | ç¶æ |
|---|---|---|
| ReDoS 鲿€ | å®å šæ£åçŒè¯ïŒè¶ æ¶äžæ | â |
| æ¶åºæ»å»é²æ€ | åžžéæ¶éŽå笊䞲æ¯èŸ | â |
| è·¯åŸéå鲿€ | ç®åœééžæ£æµäžé»æ¢ | â |
| æ³šå ¥æ£æµ | SQL/Command æ³šå ¥æš¡åŒè¯å« | â |
| å å¯éæºæ° | äœ¿çš crypto.randomBytes | â |
å®å šç€ºäŸ
import { safeRegexCompile } from '@yyc3/i18n-core/lib/security/safe-regex';
import { constantTimeStringEqual } from '@yyc3/i18n-core/lib/security/secret-equal';
import { guardAgainstPathTraversal } from '@yyc3/i18n-core/lib/utils/path-guards';
// å®å
šçæ£å衚蟟åŒçŒè¯ (é² ReDoS)
const regex = safeRegexCompile(userInput, { timeout: 1000 });
// åžžéæ¶éŽæ¯èŸ (鲿¶åºæ»å»)
const isEqual = constantTimeStringEqual(tokenA, tokenB);
// è·¯åŸéå鲿€
guardAgainstPathTraversal('../../etc/passwd'); // æåº SecurityError
â åžžè§é®é¢
Q1: åŠäœæ·»å èªå®ä¹è¯èšïŒ
import { i18n } from '@yyc3/i18n-core';
// åšæå 蜜翻è¯
await i18n.addLocale('custom-LANG', {
welcome: '欢è¿',
greeting: 'äœ å¥œïŒ{name}ïŒ',
});
Q2: åŠäœåš SSR (æå¡ç«¯æž²æ) äžäœ¿çšïŒ
// Next.js 瀺äŸ
import { I18nEngine } from '@yyc3/i18n-core';
let engine: I18nEngine;
export async function getServerSideProps(context) {
engine = new I18nEngine();
await engine.init();
await engine.setLocale(context.locale);
return {
props: {
initialLocale: context.locale,
translations: engine.getTranslations(),
},
};
}
Q3: åŠäœå€çåšæç¿»è¯é®ïŒ
// äœ¿çš missingKeyHandler æŠæªæªç¥é®
const engine = new I18nEngine({
missingKeyHandler: (key) => {
// åéå°ç¿»è¯æå¡æè¿åé»è®€åŒ
logMissingKeyToServer(key);
return humanizeKey(key); // 'user.profile.name' â 'User Profile Name'
},
});
Q4: AI ç¿»è¯ç莚éåŠäœä¿è¯ïŒ
import { QualityEstimator } from '@yyc3/i18n-core/ai';
const qe = new QualityEstimator();
const result = await qe.estimate({
sourceText: 'Hello',
translatedText: 'äœ å¥œ',
sourceLocale: 'en',
targetLocale: 'zh-CN',
});
if (result.score > 0.9 && result.issues.length === 0) {
console.log('â
ç¿»è¯èŽšéäŒç§');
} else {
console.log('â ïž éèŠäººå·¥å®¡æ ž:', result.issues);
}
Q5: åŠäœäžç°æ i18n æ¹æ¡è¿ç§»ïŒ
请åè诊ç»ç è¿ç§»æåïŒæ¶µçä» react-i18nextãvue-i18n çæ¹æ¡ç宿Žè¿ç§»æ¥éª€ã
ð è¿ç§»æå
ä» v1.x åçº§å° v2.x
äž»èŠ Breaking Changes:
- å
ååæŽ:
@yyc3/i18nâ@yyc3/i18n-core - ç±»åéåœå:
I18nManagerâI18nEngine - æä»¶æ¥å£æŽæ°: æ°å¢å¿
éç
name屿§ - é çœ®æ ŒåŒè°æŽ: Cache å Debug é çœ®ç»æåå
诊ç»è¿ç§»æ¥éª€è¯·åé MIGRATION_GUIDE.mdã
ð€ èŽ¡ç®æå
æä»¬æ¬¢è¿ç€ŸåºèŽ¡ç®ïŒè¯·éµåŸªä»¥äžæµçšïŒ
- Fork æ¬ä»åº
- åå»ºç¹æ§åæ¯ (
git checkout -b feature/amazing-feature) - æäº€æŽæ¹ (
git commit -m 'Add amazing feature') - æšé忝 (
git push origin feature/amazing-feature) - åŒå¯ Pull Request
åŒåæµçš
# å
éä»åº
git clone https://github.com/YanYuCloudCube/Family-PAI.git
# å®è£
äŸèµ
pnpm install
# è¿å
¥ i18n-core å
ç®åœ
cd packages/i18n-core
# åŒåæš¡åŒ
pnpm build:watch
# è¿è¡æµè¯
pnpm test
# ç±»åæ£æ¥
pnpm lint
# æ ŒåŒå代ç
pnpm format
代ç è§è
- TypeScript strict mode
- äžºå ¬å ± API æ·»å JSDoc 泚é
- æ°åèœå¿ é¡»å å«å¯¹åºæµè¯
- éµåŸª OWASP å®å šçŒç è§è
ð License
MIT © YYC³ AI Team
YYC³ AI Family â å «äœæäººåAIå®¶äººçæºèœäžæ¢
äºé« · äºæ · äºå · äºç»Ž
ææ¡£çæ¬: 2.3.0 | æåæŽæ°: 2026-04-24
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.