diff --git a/.github/contributing.md b/.github/contributing.md index 523323d6f..087e09b95 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -126,7 +126,7 @@ If you want to start translating the docs in a _new_ language: 1. Create the corresponding `` sub-folder for your translation. 2. Modify the i18n configuration in the `.vitepress` sub-folder. 3. Translate the docs and run the doc site to self-test locally. -4. Create a checkpoint for your language by running `pnpm run docs:translation-status []`. A checkpoint is the hash and date of the latest commit when you do the translation. The checkpoint information is stored in the status file `packages/docs/.vitepress/translation-status.json`. _It's crucial for long-term maintenance since all the further translation sync-ups are based on their previous checkpoints._ Usually, you can skip the commit argument because the default value is `main`. +4. Create a checkpoint for your language by running `pnpm run docs:translation:update []`. A checkpoint is the hash and date of the latest commit when you do the translation. The checkpoint information is stored in the status file `packages/docs/.vitepress/translation-status.json`. _It's crucial for long-term maintenance since all the further translation sync-ups are based on their previous checkpoints._ Usually, you can skip the commit argument because the default value is `main`. 5. Commit all the changes and create a pull request to our GitHub repo. We will have a paragraph at the top of each translation page that shows the translation status. That way, users can quickly determine if the translation is up-to-date or lags behind the English version. @@ -135,9 +135,9 @@ Speaking of the up-to-date translation, we also need good long-term maintenance 1. See what translation you need to sync up with the original docs. There are two popular ways: 1. Via the [GitHub Compare](https://github.com/vuejs/router/compare/) page, only see the changes in `packages/docs/*` from the checkpoint hash to `main` branch. You can find the checkpoint hash for your language via the translation status file `packages/docs/.vitepress/translation-status.json`. The compare page can be directly opened with the hash as part of the URL, e.g. https://github.com/vuejs/router/compare/e008551...main - 2. Via a local command: `pnpm run docs:compare-to-translate []`. + 2. Via a local command: `pnpm run docs:translation:compare []`. 2. Create your own branch and start the translation update, following the previous comparison. -3. Create a checkpoint for your language by running `pnpm run docs:translation-status []`. +3. Create a checkpoint for your language by running `pnpm run docs:translation:update []`. 4. Commit all the changes and create a pull request to our GitHub repo. @@ -149,7 +149,7 @@ You can also host the translation on your own. To create one, fork our GitHub re - Ensure you maintain the _checkpoint_ properly. Also, ensure the _translation status_ is well-displayed on the top of each translation page. - Utilize the diff result between the latest official repository and your own checkpoint to guide your translation. -Tip: you can add the official repo as a remote to your forked repo. This way, you can still run `pnpm run docs:translation-status []` and `npm run docs:compare-to-translate []` to get the checkpoint and diff result: +Tip: you can add the official repo as a remote to your forked repo. This way, you can still run `pnpm run docs:translation:update []` and `npm run docs:translation:compare []` to get the checkpoint and diff result: ```bash # prepare the upstream remote @@ -157,10 +157,10 @@ git remote add upstream git@github.com:vuejs/router.git git fetch upstream main # set the checkpoint -pnpm run docs:translation-status upstream/main +pnpm run docs:translation:update upstream/main # get the diff result -pnpm run docs:compare-to-translate upstream/main +pnpm run docs:translation:compare upstream/main ``` diff --git a/package.json b/package.json index 53fe65d15..a839fede3 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,9 @@ "build:dts": "pnpm run -r build:dts", "docs": "pnpm run --filter ./packages/docs -r docs", "docs:api": "pnpm run --filter ./packages/docs -r docs:api", - "docs:compare-to-translate": "pnpm run --filter ./packages/docs -r docs:compare-to-translate", - "docs:translation-status": "pnpm run --filter ./packages/docs -r docs:translation-status", + "docs:translation:compare": "pnpm run --filter ./packages/docs -r docs:translation:compare", + "docs:translation:update": "pnpm run --filter ./packages/docs -r docs:translation:update", + "docs:translation:status": "pnpm run --filter ./packages/docs -r docs:translation:status", "docs:build": "pnpm run docs:api && pnpm run --filter ./packages/docs -r docs:build", "docs:preview": "pnpm run --filter ./packages/docs -r docs:preview", "play": "pnpm run -r play", diff --git a/packages/docs/.vitepress/theme/index.ts b/packages/docs/.vitepress/theme/index.ts index 8586a726a..a024db948 100644 --- a/packages/docs/.vitepress/theme/index.ts +++ b/packages/docs/.vitepress/theme/index.ts @@ -3,11 +3,16 @@ import { Theme } from 'vitepress' import DefaultTheme from 'vitepress/theme' import AsideSponsors from './components/AsideSponsors.vue' // import HomeSponsors from './components/HomeSponsors.vue' -import TranslationStatus from './components/TranslationStatus.vue' +import TranslationStatus from 'vitepress-translation-helper/ui/TranslationStatus.vue' import './styles/vars.css' import './styles/sponsors.css' import VueSchoolLink from './components/VueSchoolLink.vue' import VueMasteryLogoLink from './components/VueMasteryLogoLink.vue' +import status from '../translation-status.json' + +const i18nLabels = { + zh: '该翻译已同步到了 ${date} 的版本,其对应的 commit hash 是 ${hash}。', +} const theme: Theme = { ...DefaultTheme, @@ -15,7 +20,7 @@ const theme: Theme = { return h(DefaultTheme.Layout, null, { // 'home-features-after': () => h(HomeSponsors), 'aside-ads-before': () => h(AsideSponsors), - 'doc-before': () => h(TranslationStatus), + 'doc-before': () => h(TranslationStatus, { status, i18nLabels }), }) }, diff --git a/packages/docs/compare-to-translate.mjs b/packages/docs/compare-to-translate.mjs deleted file mode 100644 index 7e92d45d6..000000000 --- a/packages/docs/compare-to-translate.mjs +++ /dev/null @@ -1,45 +0,0 @@ -// @ts-check -import { readFile } from 'fs/promises' -import simpleGit from 'simple-git' - -// The path to the translation status file. -const STATUS_FILE_PATH = './.vitepress/translation-status.json' - -const usage = ` -Usage: pnpm run docs:compare-to-translate [] - locale: The target locale to compare. - commit: The target commit to compare. It could be a branch, a tag, or a hash. Default to 'main'.` - -async function getLocaleHash (lang) { - try { - const content = await readFile(STATUS_FILE_PATH, 'utf8') - const data = JSON.parse(content) - return data[lang]?.hash - } catch (err) { - console.log('No previous status file. Will create a new one.') - } -} - -async function main() { - if (process.argv.find(arg => arg === '--help' || arg === '-h')) { - console.log(usage) - return - } - - const locale = process.argv[2] - const commit = process.argv[3] || 'main' - - const hash = await getLocaleHash(locale) - if (hash) { - console.log(`The last checkpoint of docs(${locale}) is "${hash}".\n`) - const git = simpleGit() - const result = await git.diff([`${hash}..${commit}`, '.']) - console.log(result) - console.log(`\nAfter finishing the translation, you can run\n"pnpm run docs:translation-status ${locale} ${hash}"\nor\n"pnpm run docs:translation-status ${locale}${commit !== 'main' ? ' ' + commit : ''}"\nto update the translation status file.`) - } else { - console.log(`No docs(${locale}) checkpoint found.\n`) - console.log(usage) - } -} - -main() diff --git a/packages/docs/generate-translation-status.mjs b/packages/docs/generate-translation-status.mjs deleted file mode 100644 index 1a165e8c1..000000000 --- a/packages/docs/generate-translation-status.mjs +++ /dev/null @@ -1,60 +0,0 @@ -// @ts-check -import { writeFile, readFile } from 'fs/promises' -import simpleGit from 'simple-git' - -// The path to the translation status file. -const STATUS_FILE_PATH = './.vitepress/translation-status.json' - -const usage = ` -Usage: pnpm run docs:translation-status [] - locale: The target locale to update. - commit: The target commit to update. It could be a branch, a tag, or a hash. Default to 'main'.` - -async function getCommitInfo (commit) { - try { - const git = simpleGit() - const log = await git.log([commit, '-n', '1']) - const { hash, date } = log.latest - return { hash, date: new Date(date).toISOString().substring(0, 10) } - } catch (err) { - return { hash: '', date: '' } - } -} - -async function writeLangMap (lang, hash, date) { - const data = {} - try { - const previousContent = await readFile(STATUS_FILE_PATH, 'utf8') - const previousJson = JSON.parse(previousContent) - Object.assign(data, previousJson) - } - catch (err) { - console.log('No previous status file. Will create a new one.') - } - data[lang] = { - hash, - date, - } - await writeFile(STATUS_FILE_PATH, JSON.stringify(data, null, 2)) -} - -async function main() { - if (process.argv.find(arg => arg === '--help' || arg === '-h')) { - console.log(usage) - return - } - - const locale = process.argv[2] - const commit = process.argv[3] || 'main' - - const { hash, date } = await getCommitInfo(commit) - if (!hash) { - console.log(`❌ No commit found for "${commit}".`) - return - } else { - await writeLangMap(locale, hash, date) - console.log(`✅ Updated ${locale} to "${hash}" (${date})`) - } -} - -main() diff --git a/packages/docs/package.json b/packages/docs/package.json index 338bc047c..f200ed27e 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -6,14 +6,16 @@ "scripts": { "docs": "vitepress dev .", "docs:api": "node run-typedoc.mjs", - "docs:compare-to-translate": "node compare-to-translate.mjs", - "docs:translation-status": "node generate-translation-status.mjs", + "docs:translation:compare": "v-translation compare", + "docs:translation:update": "v-translation update", + "docs:translation:status": "v-translation status", "docs:build": "vitepress build .", "docs:preview": "vitepress preview ." }, "dependencies": { "simple-git": "^3.18.0", "vitepress": "1.0.0-rc.35", + "vitepress-translation-helper": "^0.1.3", "vue-router": "workspace:*" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28dca4027..7a8a2259a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: vitepress: specifier: 1.0.0-rc.35 version: 1.0.0-rc.35(@algolia/client-search@4.19.1)(search-insights@2.7.0)(typescript@5.3.3) + vitepress-translation-helper: + specifier: ^0.1.3 + version: 0.1.3(vitepress@1.0.0-rc.35)(vue@3.4.8) vue-router: specifier: workspace:* version: link:../router @@ -1842,6 +1845,16 @@ packages: source-map-js: 1.0.2 dev: false + /@vue/compiler-core@3.4.8: + resolution: {integrity: sha512-GjAwOydZV6UyVBi1lYW5v4jjfU6wOeyi3vBATKJOwV7muYF0/nZi4kfdJc0pwdT5lXwbbx57lyA2Y356rFpw1A==} + dependencies: + '@babel/parser': 7.23.6 + '@vue/shared': 3.4.8 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.0.2 + dev: false + /@vue/compiler-dom@3.3.11: resolution: {integrity: sha512-zoAiUIqSKqAJ81WhfPXYmFGwDRuO+loqLxvXmfUdR5fOitPoUiIeFI9cTTyv9MU5O1+ZZglJVTusWzy+wfk5hw==} dependencies: @@ -1862,6 +1875,13 @@ packages: '@vue/shared': 3.4.5 dev: false + /@vue/compiler-dom@3.4.8: + resolution: {integrity: sha512-GsPyji42zmkSJlaDFKXvwB97ukTlHzlFH/iVzPFYz/APnSzuhu/CMFQbsYmrtsnc2yscF39eC4rKzvKR27aBug==} + dependencies: + '@vue/compiler-core': 3.4.8 + '@vue/shared': 3.4.8 + dev: false + /@vue/compiler-sfc@3.3.11: resolution: {integrity: sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==} dependencies: @@ -1890,6 +1910,20 @@ packages: source-map-js: 1.0.2 dev: false + /@vue/compiler-sfc@3.4.8: + resolution: {integrity: sha512-3ZcurOa6bQdZ6VZLtMqYSUZqpsMqfX0MC3oCxQG0VIJFCqouZAgRYJN1c8QvGs7HW5wW8aXVvUOQU0ILVlYHKA==} + dependencies: + '@babel/parser': 7.23.6 + '@vue/compiler-core': 3.4.8 + '@vue/compiler-dom': 3.4.8 + '@vue/compiler-ssr': 3.4.8 + '@vue/shared': 3.4.8 + estree-walker: 2.0.2 + magic-string: 0.30.5 + postcss: 8.4.32 + source-map-js: 1.0.2 + dev: false + /@vue/compiler-ssr@3.3.11: resolution: {integrity: sha512-Zd66ZwMvndxRTgVPdo+muV4Rv9n9DwQ4SSgWWKWkPFebHQfVYRrVjeygmmDmPewsHyznCNvJ2P2d6iOOhdv8Qg==} dependencies: @@ -1903,6 +1937,13 @@ packages: '@vue/shared': 3.4.5 dev: false + /@vue/compiler-ssr@3.4.8: + resolution: {integrity: sha512-nxN79LHeAemhBpIa2PQ6rz57cW7W4C/XIJCOMSn2g49u6q2ekirmJI0osAOTErQPApOR0KwP2QyeTexX4zQCrw==} + dependencies: + '@vue/compiler-dom': 3.4.8 + '@vue/shared': 3.4.8 + dev: false + /@vue/devtools-api@6.5.1: resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==} dev: false @@ -1947,6 +1988,12 @@ packages: '@vue/shared': 3.4.5 dev: false + /@vue/reactivity@3.4.8: + resolution: {integrity: sha512-UJYMQ3S2rqIGw9IvKomD4Xw2uS5VlcKEEmwcfboGOdrI79oqebxnCgTvXWLMClvg3M5SF0Cyn+9eDQoyGMLu9Q==} + dependencies: + '@vue/shared': 3.4.8 + dev: false + /@vue/runtime-core@3.3.11: resolution: {integrity: sha512-g9ztHGwEbS5RyWaOpXuyIVFTschclnwhqEbdy5AwGhYOgc7m/q3NFwr50MirZwTTzX55JY8pSkeib9BX04NIpw==} dependencies: @@ -1960,6 +2007,13 @@ packages: '@vue/shared': 3.4.5 dev: false + /@vue/runtime-core@3.4.8: + resolution: {integrity: sha512-sMRXOy89KnwY6fWG5epgPOsCWzpo/64FrA0QkjIeNeGnoA2YyZ6bBUxpFUyqhJ8VbrDhXEFH+6LHMOYrpzX/ZQ==} + dependencies: + '@vue/reactivity': 3.4.8 + '@vue/shared': 3.4.8 + dev: false + /@vue/runtime-dom@3.3.11: resolution: {integrity: sha512-OlhtV1PVpbgk+I2zl+Y5rQtDNcCDs12rsRg71XwaA2/Rbllw6mBLMi57VOn8G0AjOJ4Mdb4k56V37+g8ukShpQ==} dependencies: @@ -1975,6 +2029,14 @@ packages: csstype: 3.1.3 dev: false + /@vue/runtime-dom@3.4.8: + resolution: {integrity: sha512-L4gZcYo8f3d7rQqQIHkPvyczkjjQ55cJqz2G0v6Ptmqa1mO2zkqN9F8lBT6aGPYy3hd0RDiINbs4jxhSvvy10Q==} + dependencies: + '@vue/runtime-core': 3.4.8 + '@vue/shared': 3.4.8 + csstype: 3.1.3 + dev: false + /@vue/server-renderer@3.3.11(vue@3.3.11): resolution: {integrity: sha512-AIWk0VwwxCAm4wqtJyxBylRTXSy1wCLOKbWxHaHiu14wjsNYtiRCSgVuqEPVuDpErOlRdNnuRgipQfXRLjLN5A==} peerDependencies: @@ -1994,6 +2056,16 @@ packages: vue: 3.4.5(typescript@5.3.3) dev: false + /@vue/server-renderer@3.4.8(vue@3.4.8): + resolution: {integrity: sha512-pBeHM59Owevr3P0Fl1XOjBmq4DTy5JDcjMG4NuzJEVDlZYzY8fHybx0wdjkY5lK5mCtUyBtw6Mz4d87aosc1Sw==} + peerDependencies: + vue: 3.4.8 + dependencies: + '@vue/compiler-ssr': 3.4.8 + '@vue/shared': 3.4.8 + vue: 3.4.8(typescript@5.3.3) + dev: false + /@vue/shared@3.3.11: resolution: {integrity: sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==} @@ -2005,6 +2077,10 @@ packages: resolution: {integrity: sha512-6XptuzlMvN4l4cDnDw36pdGEV+9njYkQ1ZE0Q6iZLwrKefKaOJyiFmcP3/KBDHbt72cJZGtllAc1GaHe6XGAyg==} dev: false + /@vue/shared@3.4.8: + resolution: {integrity: sha512-ChLCWzXiJboQ009oVkemhEoUdrxHme7v3ip+Kh+/kDDeF1WtHWGt0knRLGm1Y4YqCRTSs9QxsZIY8paJj5Szrw==} + dev: false + /@vue/test-utils@2.4.3(@vue/server-renderer@3.3.11)(vue@3.3.11): resolution: {integrity: sha512-F4K7mF+ad++VlTrxMJVRnenKSJmO6fkQt2wpRDiKDesQMkfpniGWsqEi/JevxGBo2qEkwwjvTUAoiGJLNx++CA==} peerDependencies: @@ -5430,7 +5506,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} @@ -6447,6 +6522,16 @@ packages: - supports-color dev: false + /simple-git@3.22.0: + resolution: {integrity: sha512-6JujwSs0ac82jkGjMHiCnTifvf1crOiY/+tfs/Pqih6iow7VrpNKRRNdWm6RtaXpvvv/JGNYhlUtLhGFqHF+Yw==} + dependencies: + '@kwsites/file-exists': 1.1.1 + '@kwsites/promise-deferred': 1.1.1 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: true @@ -7119,6 +7204,21 @@ packages: fsevents: 2.3.3 dev: true + /vitepress-translation-helper@0.1.3(vitepress@1.0.0-rc.35)(vue@3.4.8): + resolution: {integrity: sha512-KandbALKgfKmRwYBX1Wt/A/38fhACmK+962S3hYgdvzSgwM2EOO5XgEUxPKXEil5kR1eNZKJJIPbQp52h8kCpA==} + hasBin: true + peerDependencies: + vitepress: 1.0.0-rc.36 + vue: ^3.4.8 + dependencies: + minimist: 1.2.8 + simple-git: 3.22.0 + vitepress: 1.0.0-rc.35(@algolia/client-search@4.19.1)(search-insights@2.7.0)(typescript@5.3.3) + vue: 3.4.8(typescript@5.3.3) + transitivePeerDependencies: + - supports-color + dev: false + /vitepress@1.0.0-rc.35(@algolia/client-search@4.19.1)(search-insights@2.7.0)(typescript@5.3.3): resolution: {integrity: sha512-+2VnFwtYIiKWWAnMjWg7ik0PfsUdrNoZIZKeu5dbJtrkzKO/mTvlA3owiT5VBKJsZAgI17B5UV37aYfUvGrN6g==} hasBin: true @@ -7251,6 +7351,22 @@ packages: typescript: 5.3.3 dev: false + /vue@3.4.8(typescript@5.3.3): + resolution: {integrity: sha512-vJffFOe6DqWsAI10v3tDhb1nJrj7CF3CbdQwOznywAsFNoyvrQ1AWQdcIWJpmRpRnw7NFzstzh6fh4w7n1PNdg==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@vue/compiler-dom': 3.4.8 + '@vue/compiler-sfc': 3.4.8 + '@vue/runtime-dom': 3.4.8 + '@vue/server-renderer': 3.4.8(vue@3.4.8) + '@vue/shared': 3.4.8 + typescript: 5.3.3 + dev: false + /w3c-hr-time@1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} deprecated: Use your platform's native performance.now() and performance.timeOrigin.