diff --git a/docs/src/guide/use/react.md b/docs/src/guide/use/react.md index dd5884a..0614581 100644 --- a/docs/src/guide/use/react.md +++ b/docs/src/guide/use/react.md @@ -18,7 +18,15 @@ ``` ## 第二步:导入`t`翻译函数 -无论采用何种工具创建`React`应用,均可以直接从`languages`直接导入`t`函数。 + +`t`翻译函数用来进行文件翻译,普通的`React`应用`t`翻译函数可以用在两个地方: + +- 普通的`js`或`ts`文件 +- `React`组件`jsx、tsx`文件 + +### 在`js`或`ts`文件中使用 + +只需要从`languages`直接导入`t`函数即可。 ```javascript | pure import { t } from "./languages" @@ -33,42 +41,116 @@ import { t } from "../../../languages" 导入`t`函数后就可以直接使用了。 -## 第三步:自动导入`t`翻译函数 +### 在`React`组件中翻译 -当源码文件非常多时,手动导入`t`函数比较麻烦,我们提供了`vite`和`babel`两个插件可以实现自动导入`t`函数。 -如果应用是采用`Vite`+`@vitejs/plugin-react`创建的工程,则可以通过配置`@voerkai18n/vite`插件实现自动导入`t`函数。 +在`React`组件中使用`t`函数翻译与在`js`或`ts`文件中使用的最大区别在于:**当切换语言时,需要触发组件的重新渲染**。 + +- **配置根组件Provider** + +使用`VoerkaI18nProvider`包装应用根组件,本质上是创建了一个`VoerkaI18nContext.Provider` + +```jsx | pure + +// 1.当前语言Scope +import { i18nScope } from "./languages" +import { VoerkaI18nProvider } from "@voerkai18n/react" + +export default App(){ + return ( + + + + ) +} +``` + +- **组件中使用翻译函数** + +通过`useVoerkaI18n`获取当前作用域的`t`翻译函数。 + +```jsx | pure +import { useVoerkaI18n } from "@voerkai18n/react" +export function MyComponent(){ + const { t } = useVoerkaI18n() + return ( +
{t("要翻译的内容")}
+ ) +} + +``` + +注意:在组件中直接使用`import { t } from "languages`也是可以工作的,因为本质上`t`函数仅仅是一个普通的函数。但是当动态切换语言时,对应的组件不能自动重新渲染。因此,需要使用`{ t } = useVoerkaI18n()`导入`t`函数,才可以在切换语言时自动重新渲染组件。 + +### 第三步: 自动导入`t`翻译函数 + +如果应用是采用`Vite`+`@vitejs/plugin-react`创建的工程,则可以通过配置`@voerkai18n/vite`插件实现自动导入`t`函数和`翻译内容自动映射`等。 + +在`vite.config.js`中配置导入安装`@voerkai18n/vite`插件。 + +```typescript | pure +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import Inspect from 'vite-plugin-inspect' +import Voerkai18nPlugin from "@voerkai18n/vite" + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + Inspect(), // localhost:3000/__inspect/ + Voerkai18nPlugin({ debug: true }), + react() + ] +}) + +``` 详见`@voerkai18n/vite`插件介绍。 +`@voerkai18n/vite`插件主要干两件事情: + +- 对`js/ts`文件自动导入`t`函数,`jsx/tsx`文件不需要自动导入,只能使用`useVoerkaI18n`。 +- 根据`idMap.(js|ts)`内容自动替换翻译内容,用来消除冗余内容。 + ## 第四步:切换语言 -最后,一般需要在应用中提供切换语言并自动重新渲染界面的功能。针对`React`应用,提供了`useVoerkaI18n`来实现此功能。 +接下来在一般我们还需要实现语言切换的功能界面,`useVoerkaI18n`提供了: +- `language`: 当前激活语言名称 +- `defaultLanguage`: 默认语言名称 +- `changeLanguage(language)`: 用来切换当前语言 +- `languages`: 读取当应用支持的语言列表。 ```jsx | pure -// 如果没有在vite.config.js中配置`@voerkai18n/vite`插件,则需要手工导入t函数 -import { t } from "./languages" + import { useVoerkaI18n } from "@voerkai18n/react" -export default App(){ - const { activeLanguage,changeLanguage,languages } = useVoerkaI18n() - return (
-

{t("当前语言")}:{activeLanguage}

-
{ - languages.map(lang=>{ - return () - })} -
-
) + +export function MyComponent(){ + const { t, language,changeLanguage,languages,defaultLanguage } = useVoerkaI18n() + return ( +
+

{t("当前语言")}:{language}

+

{t("默认语言")}:{defaultLanguage}

+
{ + languages.map(lang=>{ + return () + })} +
+
+ ) +} ``` + ## 小结 -- `useVoerkaI18n`返回当前激活语言、切换语言函数、支持的语言列表。 -- 如果需要在切换语言时进行全局重新渲染,一般需要在顶层`App组件`中使用此`hook`, 这样可以确保在切换语言时整个应用进行重新渲染。 -- 一般切换语言的功能界面不会直接在`App组件`中使用,您可以使用一个专门的组件来切换语言。 +- 使用``封装根组件 +- `const { t } = useVoerkaI18n()`来导入翻译函数 +- 使用`const { language,changeLanguage } = useVoerkaI18n()`来访问切换语言的函数 +- 在普通`ts/js`文件中使用`import { t } from "./languages"`来导入`t`翻译函数 +- `@voerkai18n/vite`插件是可选的,仅仅普通`ts/js`文件使用`t`翻译函数时用来自动导入。 diff --git a/packages/apps/reactapp/src/main.js b/packages/apps/reactapp/src/main.js index c7dec7f..e0a3ad5 100644 --- a/packages/apps/reactapp/src/main.js +++ b/packages/apps/reactapp/src/main.js @@ -1,2 +1,2 @@ - \ No newline at end of file + console.log(t("这是一个测试")) \ No newline at end of file diff --git a/packages/apps/reactapp/vite.config.js b/packages/apps/reactapp/vite.config.js index 4a27ff7..c6187d6 100644 --- a/packages/apps/reactapp/vite.config.js +++ b/packages/apps/reactapp/vite.config.js @@ -7,7 +7,7 @@ import Voerkai18nPlugin from "@voerkai18n/vite" export default defineConfig({ plugins: [ Inspect(), // localhost:3000/__inspect/ - // Voerkai18nPlugin({ debug: true }), + Voerkai18nPlugin({ debug: true }), react() ] }) diff --git a/packages/autopublish/index.js b/packages/autopublish/index.js deleted file mode 100644 index 1b87c2b..0000000 --- a/packages/autopublish/index.js +++ /dev/null @@ -1,458 +0,0 @@ -/** - * 用于多包环境下的自动发布 - * - * autopublish - * - * 1.在package.json中添加scripts - * { - * scripts:{ - * "publish":"autopublish [options]", - * } - * } - * 2. 参数 - * -q: 默认情况下会比对最后一次发布的时间,来决定是否自动发布 - * 当-q参数被指定时,会询问用户 - * - * - * - * - */ - -const fs = require("fs-extra"); -const inquirer = require("inquirer"); -const semver = require("semver") -const path = require("path"); -const shelljs = require("shelljs"); -const createLogger = require("logsets"); -const TaskListPlugin = require("logsets/plugins/tasklist") -const TablePlugin = require("logsets/plugins/table") - -const { Command ,Option} = require('commander'); - -const dayjs = require("dayjs"); -const relativeTime = require("dayjs/plugin/relativeTime"); -const { rejects } = require("assert"); -const { Console } = require("console"); -const { resourceLimits } = require("worker_threads"); -dayjs.extend(relativeTime); -require('dayjs/locale/zh-CN') -dayjs.locale("zh-CN"); - -const logger = createLogger(); -logger.use(TaskListPlugin) -logger.use(TablePlugin) - -const program =new Command() - - // 排除要发布的包 - const exclude_packages = ["autopublish"] - - function getPackages(){ - let workspaceRoot = process.cwd() - if(!fs.existsSync(path.join(workspaceRoot,"pnpm-workspace.yaml"))){ - console.log("命令只能在工作区根目录下执行") - return - } - // 读取所有包 - let packages = fs.readdirSync(path.join(workspaceRoot,"packages")).map(packageName=>{ - const packageFolder = path.join(workspaceRoot,"packages",packageName) - const pkgFile = path.join(workspaceRoot,"packages",packageName,"package.json") - if(fs.existsSync(pkgFile)){ - const { name, version,lastPublish,dependencies,devDependencies,description }= fs.readJSONSync(pkgFile) - // 读取工作区包依赖 - let packageDependencies =[] - Object.entries({...dependencies,...devDependencies}).forEach(([name,version])=>{ - if(version.startsWith("workspace:") && !exclude_packages.includes(name.replace("@voerkai18n/",""))){ - packageDependencies.push(name) - } - }) - return { - name, // 完整包名 - description, - value:packageName, // 文件夹名称 - version, - lastPublish, - isDirty: packageIsDirty(packageFolder), // 包自上次发布之后是否已修改 - dependencies:packageDependencies // 依赖的工作区包 - } - } - }).filter(pkgInfo=>pkgInfo && !exclude_packages.includes(pkgInfo.value)) - - // 根据依赖关系进行排序 - for(let i=0;i { - if(package.isDirty){ - packages.forEach(p=>{ - if(p.name!==package.name && p.dependencies.includes(package.name)){ - p.isDirty = true - } - }) - } - }) - return packages - } - - function assertInWorkspaceRoot(){ - const workspaceRoot = process.cwd() - if(!fs.existsSync(path.join(workspaceRoot,"pnpm-workspace.yaml"))){ - throw new Error("命令只能在工作区根目录下执行") - } - } - - function assertInPackageRoot(){ - const currentFolder = process.cwd() - const workspaceRoot = path.join(currentFolder,"../../") - - const inPackageRoot = fs.existsSync(path.join(currentFolder,"package.json")) && fs.existsSync(path.join(workspaceRoot,"pnpm-workspace.yaml")) - - if(!inPackageRoot){ - throw new Error("命令只能在工作区的包目录下执行") - } -} - - /** - * 执行脚本,出错会返回错误信息 - * @param {*} script - */ -function execShellScript(script,options={}){ - let {code,stdout} = shelljs.exec(script,options) - if(code>0){ - new Error(`执行<${script}>失败: ${stdout.trim()}`) - } -} -/** - * 异步执行脚本 - * @param {*} script - * @param {*} options - * @returns - */ -async function asyncExecShellScript(script,options={}){ - return new Promise((resolve,reject)=>{ - shelljs.exec(script,{...options,async:true},(code,stdout)=>{ - if(code>0){ - reject(new Error(`执行<${script}>失败: ${stdout.trim()}`)) - }else{ - resolve() - } - }) - }) -} - /** - * 执行脚本并返回结果 - * @param {*} script - */ -function execShellScriptReturns(script,options={}){ - return shelljs.exec(script,options).stdout.trim() -} - -/** - * 读取指定包最近一次更新的时间 - * 通过遍历所有文件夹 - * @param {*} folder - * @returns - */ - function getFolderLastModified(folder,patterns=[],options={}){ - patterns.push(...[ - "package.json", - "**", - "**/*", - "!node_modules/**", - "!node_modules/**/*", - "!**/node_modules/**", - "!**/node_modules/**/*", - ]) - - const glob = require("fast-glob") - let files = glob.sync(patterns, { - cwd: folder, - absolute:true, - ...options - }) - let lastUpdateTime = null - for(let file of files){ - const { mtimeMs } = fs.statSync(file) - lastUpdateTime = lastUpdateTime ? Math.max(lastUpdateTime,mtimeMs) : mtimeMs - } - return lastUpdateTime -} - -function getFileLastModified(file){ - const { mtimeMs } = fs.statSync(file) - return mtimeMs -} - -/** - * - * @param {*} packageInfo {name:"@voerkai18n/autopublish",value:"",version:"1.0.0",lastPublish:"2020-05-01T00:00:00.000Z"} - */ -async function runPackageScript(workspaceRoot,packageInfo,{silent=false}={}){ - const packageFolder = path.join(workspaceRoot,"packages",packageInfo.value) - const package = fs.readJSONSync(path.join(packageFolder,"package.json")) - const lastModified = getFolderLastModified(packageFolder) - // 进入包所在的文件夹 - shelljs.cd(packageFolder) - // 每个包必须定义自己的发布脚本 - if("release" in package.scripts){ - await asyncExecShellScript(`pnpm release`,{silent}) - }else{ - const reason = `包[{}]没有定义自动发布脚本release` - if(showLog) logger.log(reason,package.name) - throw new Error(`未配置脚本`) - } -} - - -/** - * - * 返回指定包自上次发布之后是否有更新过 - * - * @param {*} packageFolder - * - * - */ -function packageIsDirty(packageFolder){ - const pkgFile = path.join(packageFolder,"package.json") - if(!fs.existsSync(pkgFile)){ - logger.log("当前包[{}]不存在package.json文件",packageFolder) - throw new Error("当前包不存在package.json文件") - } - const package = fs.readJSONSync(pkgFile) - const lastModified = getFolderLastModified(packageFolder) - const lastPublish = package.lastPublish - // 由于上一次发布时会更新package.json文件,如果最后更新的文件时间==package.json文件最后更新时间,则说明没有更新 - const pkgLastModified = getFileLastModified(pkgFile) - - return dayjs(lastModified).isAfter(dayjs(lastPublish)) && !dayjs(pkgLastModified).isSame(dayjs(lastModified)) -} - -/** - * 发布所有包 - * - * 将比对最后发布时间和最后修改时间的差别来决定是否发布 - * - * - * @param {*} packages - */ -async function publishAllPackages(packages,options={}){ - const tasks = logger.tasklist() - const workspaceRoot = process.cwd() - // 依次对每个包进行发布 - for(let package of packages){ - tasks.add(`发布包[${package.name}]`) - try{ - if(package.isDirty){ - await runPackageScript(workspaceRoot,package,{silent:true,...options}) - let { version } = fs.readJSONSync(path.join(workspaceRoot,"packages",package.value,"package.json")) - tasks.complete(`${package.version}->${version}`) - }else{ - tasks.skip() - } - }catch(e){ - tasks.error(`${e.message}`) - } - } -} - - - -/** - * 发布包,并且在package.json中记录最后发布时间 - * 本命令只能在包文件夹下执行 - * @param {*} options - */ -async function publishPackage(options){ - const { versionIncrementStep,silent=true } = options - - // 此命令需要切换到包所在目录 - const packageFolder = process.cwd() - const packageName = path.basename(packageFolder) - const pkgFile = path.join(packageFolder,"package.json") - - if(!fs.existsSync(pkgFile)){ - logger.log("当前包[{}]不存在package.json文件",packageName) - throw new Error("当前包不存在package.json文件,请在包文件夹下执行") - } - - let package = fs.readJSONSync(pkgFile) - const oldVersion = package.version - let packageBackup = Object.assign({},package) // 备份package.json,当操作失败时,还原 - - logger.log("发布包:{}",`@voerkai18n/${packageName}`) - - const tasks = logger.tasklist() - - try{ - // 第一步: 更新版本号和发布时间 - tasks.add("更新版本号") - await asyncExecShellScript(`npm version ${versionIncrementStep}`,{silent}) - // 重新读取包 - package = fs.readJSONSync(pkgFile) - packageBackup = Object.assign({},package) - tasks.complete(`${oldVersion}->${package.version}`) - - // 第二步:构建包 - if("build" in package.scripts){ - tasks.add("构建包") - await asyncExecShellScript(`pnpm build`,{silent}) - tasks.complete() - } - - - // 第三步:发布 - // 由于工程可能引用了工作区内的其他包,必须pnpm publish才能发布 - // pnpm publish会修正引用工作区其他包到的依赖信息,而npm publish不能识别工作区内的依赖,会导致报错 - tasks.add("发布包") - await asyncExecShellScript(`pnpm publish --no-git-checks --access public`,{silent}) - tasks.complete() - - // 第四步:更新发布时间 - tasks.add("更新发布时间") - package.lastPublish = dayjs().format() - fs.writeFileSync(pkgFile,JSON.stringify(package,null,4)) - tasks.complete() - - }catch(e){// 如果发布失败,则还原package.json - fs.writeFileSync(pkgFile,JSON.stringify(packageBackup,null,4)) - tasks.error(`${e.message}`) - } - -} - - - -program - .command("list") - .description("列出各个包的最后一次提交时间和版本信息") - .action(options => { - assertInWorkspaceRoot() - workspaceRoot = process.cwd() - const table = logger.table({grid:1}) - table.addHeader("包名","版本号","最后提交时间","最后修改时间") - getPackages().forEach(package => { - const lastPublish = package.lastPublish ? dayjs(package.lastPublish).format("MM/DD hh:mm:ss") : "None" - const lastPublishRef = package.lastPublish ? `(${dayjs(package.lastPublish).fromNow()})` : "" - const lastModified = getFolderLastModified(path.join(workspaceRoot,"packages",package.value)) - const lastUpdate = dayjs(lastModified).format("MM/DD hh:mm:ss") - const lastUpdateRef = dayjs(lastModified).fromNow() - if(package.lastPublish){ - table.addRow(package.name,package.version,`${lastPublish}(${lastPublishRef})`,`${lastUpdate}(${lastUpdateRef})`) - }else{ - table.addRow(package.name,package.version,"None",`${lastUpdate}(${lastUpdateRef})`) - } - }) - table.render() - generatePackageVersionDoc() - }) - -// 生成包版本列表文件到文档中 -function generatePackageVersionDoc(){ - let workspaceRoot = path.join(__dirname,"../../") - shelljs.cd(workspaceRoot) - let results = [] - results.push("# 版本信息") - results.push("| 包| 版本号| 最后更新|说明|") - results.push("| --- | :---:| --- |---|") - getPackages().forEach(package => { - const lastPublish = package.lastPublish ? dayjs(package.lastPublish).format("YYYY/MM/DD") : "None" - results.push(`|**${package.name}**|${package.version}|${lastPublish}|${package.description}|`) - }) - - fs.writeFileSync(path.join(workspaceRoot,"docs/src/guide/intro/versions.md"), results.join("\n")) -} - -async function answerForSelectPackages(packages,options){ - const workspaceRoot = process.cwd() - return new Promise((resolve,reject) => { - inquirer - .prompt([ - { - type: "checkbox", - name: "selectPackages", - message: "请选择要发布的库:", - choices: packages.map(package => { - const lastPublish = package.lastPublish ? dayjs(package.lastPublish).format("MM/DD hh:mm:ss") : "None" - const lastPublishRef = package.lastPublish ? `(${dayjs(package.lastPublish).fromNow()})` : "" - const lastModified = getFolderLastModified(path.join(workspaceRoot,"packages",package.value)) - const lastUpdate = dayjs(lastModified).format("MM/DD hh:mm:ss") - const lastUpdateRef = dayjs(lastModified).fromNow() - return { - ...package, - value: package, - name:`${package.name.padEnd(24)}Version: ${package.version.padEnd(8)} LastPublish: ${lastPublish.padEnd(16)}${lastPublishRef} lastModified: ${lastUpdate}(${lastUpdateRef})`, } - }), - pageSize:12, - loop: false - }, - ]) - .then((answers) => { - resolve(answers.selectPackages) - }) - .catch((error) => { - logger.log(error.message) - reject(error) - }); - }) -} -/** - * 发布包的模式 - * - * 1. 在包中使用 - * { - * scripts:{ - * "release":"pnpm autopublish" - * } - * } - * - * 2. 发布所有包 - * { - * scripts:{ - * "autopublish":"pnpm autopublish -a" - * } - * } - * > pnpm autopublish -- -a // 自动发布,会询问要发布的 - * > pnpm autopublish -- -a --no-ask // 自动发布,不会询问全自动发布 - * - */ -const VERSION_STEPS = ["major", "minor", "patch","premajor","preminor","prepatch","prerelease"] -program - .description("自动发布包") - .option("-a, --all", "发布所有包") - .option("-n, --no-ask", "不询问") - .option("-s, --no-silent", "静默显示脚本输出") - .addOption(new Option('-i, --version-increment-step [value]', '版本增长方式').default("patch").choices(VERSION_STEPS)) - .action(async (options) => { - // 发布所有包时只能在工作区根目录下执行 - if(options.all){ - assertInWorkspaceRoot() - }else{// 发布指定包时只能在包目录下执行 - assertInPackageRoot() - } - if(options.all){ // 自动发布所有包 - const workspaceRoot = process.cwd() - let packages = getPackages() - if(options.ask){ - packages = await answerForSelectPackages(packages,options) - } - if(packages.length > 0){ - await publishAllPackages(packages,options) - } - }else{// 只发布指定的包 - await publishPackage(options) - } - // 在文档中输出各包的版本信息 - generatePackageVersionDoc() - }) - - program.parseAsync(process.argv); - - \ No newline at end of file diff --git a/packages/autopublish/package.json b/packages/autopublish/package.json deleted file mode 100644 index 0b0839d..0000000 --- a/packages/autopublish/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@voerkai18n/autopublish", - "version": "1.0.3", - "description": "自动发布工作区的包", - "main": "index.js", - "private": true, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "release": "node ./index.js publish" - }, - "author": "", - "license": "ISC", - "bin": { - "autopublish": "./index.js" - }, - "dependencies": { - "commander": "^9.0.0", - "fast-glob": "^3.2.11" - }, - "lastPublish": "2022-04-06T15:36:15+08:00" -} diff --git a/packages/autopublish/readme.md b/packages/autopublish/readme.md deleted file mode 100644 index c1f3730..0000000 --- a/packages/autopublish/readme.md +++ /dev/null @@ -1,111 +0,0 @@ - - -# 概述 - -`@voerkai18n`项目是一个标准的`monorepo`包工程,包含了`@voerkai18n/cli`、`@voerkai18n/runtime`、`@voerkai18n/utils`、`@voerkai18n/vue`、`@voerkai18n/vite`、`@voerkai18n/babel`、`@voerkai18n/react`、`@voerkai18n/formatters`等多个包,发布包时容易引起混乱问题,最大问题时: -- 经常忘记哪个包最近什么时间修改,哪个包应该发布。 -- 由于包之间存在依赖关系,需要按一定的顺序进行发布 - -`@voerkai18n/autopublish`用来实现全自动或手动辅助进行发布。 - -**源码与文档:**[https://gitee.com/zhangfisher/voerka-i18n](https://gitee.com/zhangfisher/voerka-i18n) - -[![fisher/voerka-i18n](https://gitee.com/zhangfisher/voerka-i18n/widgets/widget_card.svg?colors=4183c4,ffffff,ffffff,e3e9ed,666666,9b9b9b)](https://gitee.com/zhangfisher/voerka-i18n) - -# 使用 - -## 准备 - -`@voerkai18n/autopublish`用于采用`pnpmp`创建的`monorepo`包工程,不支持`lerna/yarn`。 -按照常规约定,包存放在`/packages/`。 - -## 第一步:配置包的发布脚本 - -将`@voerkai18n/autopublish`添加为包的开发依赖。 - -```javascript -// 进入包文件夹后执行 -> pnpm add -D @voerkai18n/autopublish -``` -然后,配置发布脚本: -```json -{ - "scripts":{ - "build":"默认的包构建命令", - "release":"pnpm autopublish" - }, - "devDependencies": { - "@voerkai18n/autopublish": "workspace:^1.0.0" - } -} -``` - -- 发布脚本必须为`release`,不能是其他名称,特别是`publish` -- `pnpm autopublish`也可以在包路径下单独执行。 -- `pnpm autopublish`默认依次执行: - - `npm version patch`:升级版本号 - - `pnpm run build`(可选) - - `pnpm publish --no-git-checks --access publish` -- 默认每次发布均会升级`patch`版本号,可以通过`pnpm autopublish -i <版本递增方式>`来增加版本号,递增方式可选:[`"major"`, `"minor"`, `"patch"`,`"premajor"`,`"preminor"`,`"prepatch"`,`"prerelease"`] -- 每次执行`pnpm autopublish`均会在当前包的`package.json`中添加`lastPublish`字段,用来记录发布的时间。这是下一次发布时进行自动比对发布的依据。 - - -## 第二步:配置工作区发布脚本 - -在当前工程的根文件夹下配置`package.json` -```json -{ - "scripts":{ - "list:package": "node ./packages/autopublish/index.js list", - "autopublish": "node ./packages/autopublish/index.js" - }, - "devDependencies": { - "@voerkai18n/autopublish": "workspace:^1.0.0" - } -} -``` -## 第三步:自动发布所有包 - -```javascript -> pnpm autopublish -- -a -n -``` - -`pnpm autopublish`会自动枚举出当前所有包,然后对比包路径`packages/<包名>`最后修改时间和`package.json`的`lastPublish`字段值,如果: -- 最后修改时间大于最后发布时间,则发布该包 -- 最后修改时间关于或者小于最后发布时间,则忽略发布该包 - -因此,每次当修改完工程后,可以自动执行`pnpm autopublish -- -a -n`就可以进行全自动发布。 - -`pnpm autopublish`命令行参数: -```shell -自动发布包 - -Options: - -a, --all 发布所有包 - -n, --no-ask 不询问 - -s, --no-silent 静默显示脚本输出 - -i, --version-increment-step [value] 版本增长方式 (choices: "major", "minor", "patch", "premajor", "preminor", "prepatch", - "prerelease", default: "patch") - -h, --help display help for command - -Commands: - list 列出各个包的最后一次提交时间和版本信息 -``` - -- `-a`代表要发布所有包,如果没有启用`-n`,则会让用户选择要发布哪一个包。如果启用`-n`参数,则会全自动比对发布时间和修改时间后发布。 -- `-no-ask`代表不会询问让用户选择要发布的包. -- `--no-silent`代表是否不输出脚本输出。 -- 由于包之间存在依赖关系,`autopublish`会根据依赖关系进行排序发布和关联发布。比如`@voerkai18n/cli`依赖于`@voerkai18n/utils`,当`@voerkai18n/utils`有更新需要发布时,`@voerkai18n/cli`也会自动发布。 - - -## 第四步: 手动选择发布 - -`pnpm autopublish -- -a -n`会根据发布时间和修改时间进行自动发布。也支持手动选择要发布的包。 -```javascript -> pnpm autopublish -- -a -```` -如果不启用`-n`参数,则会列出当前工作区的所有包,让用户选择要发布的包。 - -## 列出包 - -`pnpm autopublish -- list`列出当前工程的所有包,并显示当前包最近更新和最近发布时间。 \ No newline at end of file diff --git a/packages/autopublish/utils.js b/packages/autopublish/utils.js deleted file mode 100644 index 95ffe49..0000000 --- a/packages/autopublish/utils.js +++ /dev/null @@ -1,24 +0,0 @@ -const shelljs = require("shelljs"); -const path = require("path") - - - -/** - * 检测当前工程是否是git工程 - */ -function isGitRepo(){ - return shelljs.exec("git status", {silent: true}).code === 0; -} - - -function getProjectName(){ - const pkgFile = path.join(process.cwd(), "package.json") - const pkg = fs.readJSONSync(pkgFile); - return pkg.name; -} - - -module.exports ={ - isMonorepo, - isGitRepo -} \ No newline at end of file diff --git a/packages/react/index.d.ts b/packages/react/index.d.ts index 7aef643..aceda91 100644 --- a/packages/react/index.d.ts +++ b/packages/react/index.d.ts @@ -4,6 +4,7 @@ import type React from "react" export type useVoerkaI18n = ()=>{ language:string changeLanguage:(newLanguage:string)=>Promise + defaultLanguage:string, // 默认语言 languages:VoerkaI18nSupportedLanguages, t:VoerkaI18nTranslate } diff --git a/packages/react/index.jsx b/packages/react/index.jsx index d1212ed..fab69da 100644 --- a/packages/react/index.jsx +++ b/packages/react/index.jsx @@ -3,6 +3,7 @@ import React, { useState, useEffect,useContext,useCallback} from 'react'; export const VoerkaI18nContext = React.createContext({ languages:null, language:'zh', + defaultLanguage:null, changeLanguage:() => {}, t:()=>{} }) @@ -30,6 +31,7 @@ export function VoerkaI18nProvider(props){ diff --git a/packages/vite/index.js b/packages/vite/index.js index 1521263..59c6907 100644 --- a/packages/vite/index.js +++ b/packages/vite/index.js @@ -59,11 +59,12 @@ const importTRegex = /^[^\w\r\n]*import\s*\{(.*)\bt\b(.*)\}\sfrom/gm function replaceCode(code, idmap) { return code.replaceAll(TranslateRegex, (message) => { - if(message in idmap) { - return idmap[message] - }else{ - return message - } + if(message in idmap) { + return idmap[message] + }else{ + const msg = unescape(message.replaceAll("\\u","%u")) + return msg in idmap ? idmap[msg] : message + } }) } @@ -94,6 +95,7 @@ module.exports = function VoerkaI18nPlugin(opts={}) { /\.vue(\?.*)?/, // 所有vue文件 "!(?中导入 const setupScriptRegex = /(^\s*\)/gmi if(setupScriptRegex.test(code)){ @@ -150,7 +153,7 @@ module.exports = function VoerkaI18nPlugin(opts={}) { }else{// 如果没有中导入 code = code.replace(/(^\s*\)/gmi,`$1\nimport { t } from '${importSource}';`) } - }else{// 普通js文件需要添加到最前面 + }else if(['.js','.ts'].includes(extName)){// 普通js/ts文件需要添加到最前面 code = code = `import { t } from '${importSource}';\n${code}` } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3eb518a..6b3c7d1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -229,6 +229,7 @@ importers: rollup-plugin-clear: ^2.0.7 rollup-plugin-terser: ^7.0.2 dependencies: + '@babel/runtime': 7.18.9 '@babel/runtime-corejs3': 7.20.7 core-js: 3.21.1 devDependencies: @@ -236,7 +237,6 @@ importers: '@babel/core': 7.18.10 '@babel/plugin-transform-runtime': 7.18.10_@babel+core@7.18.10 '@babel/preset-env': 7.18.10_@babel+core@7.18.10 - '@babel/runtime': 7.18.9 '@rollup/plugin-babel': 5.3.1_tui6liyexu3zy4m5r2rytc7ixu '@rollup/plugin-commonjs': 21.1.0_rollup@2.77.2 '@rollup/plugin-node-resolve': 13.3.0_rollup@2.77.2 @@ -1504,7 +1504,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.9 - dev: true /@babel/standalone/7.18.10: resolution: {integrity: sha512-0KWHiRX9TUHiWE+dKYYEOIiRJcPwGU6u8Bq/p+ldekj7Kew9PCwl4S4FTSEPpTrn3Vc+r3iRSaN1l9AcGgLx4Q==}