mirror of
https://github.com/lobehub/lobehub.git
synced 2026-03-27 13:29:15 +07:00
✨ feat: Add i18n auto flow pnpm run i18n
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
"agentTagPlaceholder": "Please enter a tag",
|
||||
"archive": "Archive",
|
||||
"autoGenerate": "Auto Generate",
|
||||
"autoGenerateTooltip": "Description of the autocomplete assistant based on prompts",
|
||||
"cancel": "Cancel",
|
||||
"close": "Close",
|
||||
"confirmRemoveSessionItemAlert": "You are about to remove this agent. Once removed, it cannot be recovered. Please confirm your action.",
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"agentTagPlaceholder": "请输入标签",
|
||||
"archive": "归档",
|
||||
"autoGenerate": "自动补全",
|
||||
"autoGenerateTooltip": "基于提示词自动补全助手描述",
|
||||
"cancel": "取消",
|
||||
"close": "关闭",
|
||||
"confirmRemoveSessionItemAlert": "即将删除该助手,删除后该将无法找回,请确认你的操作",
|
||||
@@ -29,7 +30,7 @@
|
||||
"newAgent": "新建助手",
|
||||
"noDescription": "暂无描述",
|
||||
"ok": "确定",
|
||||
"profile": "身份卡",
|
||||
"profile": "助手身份",
|
||||
"reset": "重置",
|
||||
"searchAgentPlaceholder": "搜索助手和对话...",
|
||||
"sessionSetting": "会话设置",
|
||||
|
||||
@@ -1,98 +1,97 @@
|
||||
{
|
||||
"danger": {
|
||||
"clear": {
|
||||
"action": "立即清除",
|
||||
"confirm": "确认清除所有聊天、设置数据?",
|
||||
"desc": "清除所有聊天、设置数据",
|
||||
"title": "清除所有数据"
|
||||
},
|
||||
"reset": {
|
||||
"title": "重置所有设置",
|
||||
"desc": "重置所有设置项回默认值",
|
||||
"action": "立即重置",
|
||||
"confirm": "确认重置所有设置?",
|
||||
"currentVersion": "当前版本"
|
||||
},
|
||||
"clear": {
|
||||
"title": "清除所有数据",
|
||||
"desc": "清除所有聊天、设置数据",
|
||||
"action": "立即清除",
|
||||
"confirm": "确认清除所有聊天、设置数据?"
|
||||
"currentVersion": "当前版本",
|
||||
"desc": "重置所有设置项回默认值",
|
||||
"title": "重置所有设置"
|
||||
}
|
||||
},
|
||||
|
||||
"header": "设置",
|
||||
"settingChat": {
|
||||
"title": "聊天设置",
|
||||
"inputTemplate": {
|
||||
"title": "用户输入预处理",
|
||||
"desc": "用户最新的一条消息会填充到此模板"
|
||||
},
|
||||
"compressThreshold": {
|
||||
"title": "历史消息长度压缩阈值",
|
||||
"desc": "当未压缩的历史消息超过该值时,将进行压缩"
|
||||
"desc": "当未压缩的历史消息超过该值时,将进行压缩",
|
||||
"title": "历史消息长度压缩阈值"
|
||||
},
|
||||
"historyCount": {
|
||||
"title": "附带历史消息数",
|
||||
"desc": "每次请求携带的历史消息数"
|
||||
"desc": "每次请求携带的历史消息数",
|
||||
"title": "附带历史消息数"
|
||||
},
|
||||
"inputTemplate": {
|
||||
"desc": "用户最新的一条消息会填充到此模板",
|
||||
"title": "用户输入预处理"
|
||||
},
|
||||
"maxTokens": {
|
||||
"title": "单次回复限制 (max_tokens)",
|
||||
"desc": "单次交互所用的最大 Token 数"
|
||||
"desc": "单次交互所用的最大 Token 数",
|
||||
"title": "单次回复限制 (max_tokens)"
|
||||
},
|
||||
"sendKey": {
|
||||
"title": "发送键"
|
||||
}
|
||||
},
|
||||
"title": "聊天设置"
|
||||
},
|
||||
"settingModel": {
|
||||
"title": "模型设置",
|
||||
"frequencyPenalty": {
|
||||
"desc": "值越大,越有可能降低重复字词",
|
||||
"title": "频率惩罚度 (frequency_penalty)"
|
||||
},
|
||||
"model": {
|
||||
"title": "模型"
|
||||
},
|
||||
"temperature": {
|
||||
"title": "随机性 (temperature)",
|
||||
"desc": "值越大,回复越随机"
|
||||
},
|
||||
"topP": {
|
||||
"title": "核采样 (top_p)",
|
||||
"desc": "与随机性类似,但不要和随机性一起更改"
|
||||
},
|
||||
"presencePenalty": {
|
||||
"title": "话题新鲜度 (presence_penalty)",
|
||||
"desc": "值越大,越有可能扩展到新话题"
|
||||
"desc": "值越大,越有可能扩展到新话题",
|
||||
"title": "话题新鲜度 (presence_penalty)"
|
||||
},
|
||||
"frequencyPenalty": {
|
||||
"title": "频率惩罚度 (frequency_penalty)",
|
||||
"desc": "值越大,越有可能降低重复字词"
|
||||
"temperature": {
|
||||
"desc": "值越大,回复越随机",
|
||||
"title": "随机性 (temperature)"
|
||||
},
|
||||
"title": "模型设置",
|
||||
"topP": {
|
||||
"desc": "与随机性类似,但不要和随机性一起更改",
|
||||
"title": "核采样 (top_p)"
|
||||
}
|
||||
},
|
||||
"settingOpenAI": {
|
||||
"endpoint": {
|
||||
"desc": "除默认地址外,必须包含 http(s)://",
|
||||
"title": "接口地址"
|
||||
},
|
||||
"title": "OpenAI 设置",
|
||||
"token": {
|
||||
"title": "API Key",
|
||||
"desc": "使用自己的 Key 可绕过密码访问限制",
|
||||
"placeholder": "OpenAI API Key"
|
||||
},
|
||||
"endpoint": {
|
||||
"title": "接口地址",
|
||||
"desc": "除默认地址外,必须包含 http(s)://"
|
||||
"placeholder": "OpenAI API Key",
|
||||
"title": "API Key"
|
||||
}
|
||||
},
|
||||
"settingSystem": {
|
||||
"title": "系统设置",
|
||||
"accessCode": {
|
||||
"title": "访问密码",
|
||||
"desc": "管理员已开启加密访问",
|
||||
"placeholder": "请输入访问密码"
|
||||
}
|
||||
"placeholder": "请输入访问密码",
|
||||
"title": "访问密码"
|
||||
},
|
||||
"title": "系统设置"
|
||||
},
|
||||
"settingTheme": {
|
||||
"title": "主题设置",
|
||||
"avatar": {
|
||||
"title": "头像",
|
||||
"desc": "支持 URL / Base64 / Emoji 表情符号"
|
||||
"desc": "支持 URL / Base64 / Emoji 表情符号",
|
||||
"title": "头像"
|
||||
},
|
||||
"fontSize": {
|
||||
"title": "字体大小",
|
||||
"desc": "聊天内容的字体大小"
|
||||
"desc": "聊天内容的字体大小",
|
||||
"title": "字体大小"
|
||||
},
|
||||
"lang": {
|
||||
"name": "语言设置",
|
||||
"all": "所有语言"
|
||||
}
|
||||
"all": "所有语言",
|
||||
"name": "语言设置"
|
||||
},
|
||||
"title": "主题设置"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,8 @@
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"dev": "next dev -p 3010",
|
||||
"i18n": "lobe-i18n",
|
||||
"i18n": "npm run i18n:toc && lobe-i18n",
|
||||
"i18n:toc": "ts-node --project ./tsconfig.json scripts/toc.ts",
|
||||
"lint": "eslint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix",
|
||||
"lint:md": "remark . --quiet --frail --output",
|
||||
"lint:style": "stylelint \"{src,tests}/**/*.{js,jsx,ts,tsx}\" --fix",
|
||||
@@ -35,7 +36,6 @@
|
||||
"test": "vitest --passWithNoTests",
|
||||
"test:coverage": "vitest run --coverage --passWithNoTests",
|
||||
"test:update": "vitest -u",
|
||||
"toc": "node scripts/toc.mjs",
|
||||
"type-check": "tsc --noEmit"
|
||||
},
|
||||
"lint-staged": {
|
||||
@@ -107,6 +107,7 @@
|
||||
"@umijs/lint": "^4",
|
||||
"@vitest/coverage-v8": "latest",
|
||||
"commitlint": "^17",
|
||||
"consola": "^3",
|
||||
"eslint": "^8",
|
||||
"husky": "^8",
|
||||
"i18next-browser-languagedetector": "^7",
|
||||
@@ -122,6 +123,7 @@
|
||||
"semantic-release": "^21",
|
||||
"semantic-release-config-gitmoji": "^1",
|
||||
"stylelint": "^15",
|
||||
"ts-node": "^10",
|
||||
"typescript": "^5",
|
||||
"vitest": "latest"
|
||||
},
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import fs from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import i18nConfig from '../.i18nrc.js';
|
||||
import resources from '../src/locales/resources/zh_CN.ts';
|
||||
|
||||
for (const [ns, value] of Object.entries(resources)) {
|
||||
fs.writeFileSync(
|
||||
resolve(i18nConfig.output, i18nConfig.entryLocale, `${ns}.json`),
|
||||
JSON.stringify(value, null, 2),
|
||||
);
|
||||
}
|
||||
18
scripts/genDefaultLocale.ts
Normal file
18
scripts/genDefaultLocale.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import fs from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import i18nConfig from '../.i18nrc';
|
||||
|
||||
export const genDefaultLocale = (input: string) => {
|
||||
consola.info(`Default locale is ${i18nConfig.entryLocale}...`);
|
||||
const resources = require(`../${input}/${i18nConfig.entryLocale}`);
|
||||
const data = Object.entries(resources.default);
|
||||
consola.start(`Generate default locale json, found ${data.length} namespaces...`);
|
||||
for (const [ns, value] of data) {
|
||||
const filepath = resolve(i18nConfig.output, i18nConfig.entryLocale, `${ns}.json`);
|
||||
fs.writeFileSync(filepath, JSON.stringify(value, null, 2));
|
||||
consola.success(colors.bgWhiteBright(colors.black(` ${ns} `)), colors.gray(filepath));
|
||||
}
|
||||
};
|
||||
51
scripts/genResources.ts
Normal file
51
scripts/genResources.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { consola } from 'consola';
|
||||
import { colors } from 'consola/utils';
|
||||
import { tocForResources } from 'i18next-resources-for-ts';
|
||||
import fs from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import i18nConfig from '../.i18nrc.js';
|
||||
|
||||
const locales = [i18nConfig.entryLocale, ...i18nConfig.outputLocales];
|
||||
export const genResources = (output: string) => {
|
||||
let index = '';
|
||||
let indexObj = '';
|
||||
consola.start(`Generate locale resources and types, found ${locales.length} locales...`);
|
||||
for (const locale of locales) {
|
||||
const files = fs
|
||||
.readdirSync(resolve(i18nConfig.output, locale))
|
||||
.filter((name) => name.includes('.json'));
|
||||
index += `import ${locale} from "./${locale}";\n`;
|
||||
indexObj += ` "${locale.replace('_', '-')}": ${locale},\n`;
|
||||
const ns = [];
|
||||
for (const file of files) {
|
||||
ns.push({
|
||||
name: file.replace('.json', ''),
|
||||
path: resolve(i18nConfig.output, locale, file),
|
||||
});
|
||||
}
|
||||
let toc = tocForResources(ns, resolve(output)).replaceAll('\\', '/');
|
||||
if (locale === i18nConfig.entryLocale) {
|
||||
toc = toc.replaceAll('.json', '').replaceAll('../../../locales/zh_CN', '../default');
|
||||
}
|
||||
const filepath = resolve(output, `${locale}.ts`);
|
||||
fs.writeFileSync(filepath, toc);
|
||||
consola.success(colors.bgBlue(colors.black(` ${locale} `)), colors.gray(filepath));
|
||||
}
|
||||
const indexFilepath = resolve(output, `index.ts`);
|
||||
fs.writeFileSync(
|
||||
indexFilepath,
|
||||
`${index}
|
||||
const resources = {
|
||||
${indexObj}} as const;
|
||||
export default resources;
|
||||
export const defaultResources = ${i18nConfig.entryLocale};
|
||||
export type Resources = typeof resources;
|
||||
export type DefaultResources = typeof defaultResources;
|
||||
export type Namespaces = keyof DefaultResources;
|
||||
export type Locales = keyof Resources;
|
||||
`,
|
||||
);
|
||||
|
||||
consola.success(colors.bgGreen(colors.black(` INDEX `)), colors.gray(indexFilepath));
|
||||
};
|
||||
@@ -1,40 +0,0 @@
|
||||
import { tocForResources } from 'i18next-resources-for-ts';
|
||||
import fs from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
import i18nConfig from '../.i18nrc.js';
|
||||
|
||||
const locales = [i18nConfig.entryLocale, ...i18nConfig.outputLocales];
|
||||
|
||||
const RES_OUTPUT = 'src/locales/resources';
|
||||
|
||||
let index = '';
|
||||
let indexObj = '';
|
||||
locales.forEach((locale) => {
|
||||
const files = fs
|
||||
.readdirSync(resolve(i18nConfig.output, locale))
|
||||
.filter((name) => name.includes('.json'));
|
||||
index += `import ${locale} from "./${locale}";\n`;
|
||||
indexObj += ` "${locale.replace('_', '-')}": ${locale},\n`;
|
||||
const ns = [];
|
||||
files.forEach((file) => {
|
||||
ns.push({
|
||||
name: file.replace('.json', ''),
|
||||
path: resolve(i18nConfig.output, locale, file),
|
||||
});
|
||||
});
|
||||
let toc = tocForResources(ns, resolve(RES_OUTPUT)).replaceAll('\\', '/');
|
||||
if (locale === i18nConfig.entryLocale) {
|
||||
toc = toc.replaceAll('.json', '').replaceAll('../../../locales/zh_CN', '../default');
|
||||
}
|
||||
fs.writeFileSync(resolve(RES_OUTPUT, `${locale}.ts`), toc);
|
||||
});
|
||||
|
||||
fs.writeFileSync(
|
||||
resolve(RES_OUTPUT, `index.ts`),
|
||||
`${index}
|
||||
|
||||
export default {
|
||||
${indexObj}};
|
||||
`,
|
||||
);
|
||||
7
scripts/toc.ts
Normal file
7
scripts/toc.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { genDefaultLocale } from './genDefaultLocale';
|
||||
import { genResources } from './genResources';
|
||||
|
||||
const RES_OUTPUT = 'src/locales/resources';
|
||||
|
||||
genDefaultLocale(RES_OUTPUT);
|
||||
genResources(RES_OUTPUT);
|
||||
@@ -1,7 +1,13 @@
|
||||
import en_US from './en_US';
|
||||
import zh_CN from './zh_CN';
|
||||
|
||||
export default {
|
||||
const resources = {
|
||||
'en-US': en_US,
|
||||
'zh-CN': zh_CN,
|
||||
};
|
||||
} as const;
|
||||
export default resources;
|
||||
export const defaultResources = zh_CN;
|
||||
export type Resources = typeof resources;
|
||||
export type DefaultResources = typeof defaultResources;
|
||||
export type Namespaces = keyof DefaultResources;
|
||||
export type Locales = keyof Resources;
|
||||
|
||||
@@ -1,7 +1 @@
|
||||
import resources from '@/locales/resources';
|
||||
import defaultResources from '@/locales/resources/zh_CN';
|
||||
|
||||
export type Resources = typeof resources;
|
||||
export type DefaultResources = typeof defaultResources;
|
||||
export type Namespaces = keyof DefaultResources;
|
||||
export type Locales = keyof Resources;
|
||||
export type * from '@/locales/resources';
|
||||
|
||||
@@ -22,5 +22,10 @@
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.d.ts", "**/*.tsx"]
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.d.ts", "**/*.tsx"],
|
||||
"ts-node": {
|
||||
"compilerOptions": {
|
||||
"module": "commonjs"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user