From dc166f31b08e0658379f7092cacaf31a28a78a9d Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Mon, 16 Dec 2024 21:29:32 +0800 Subject: [PATCH 01/22] chore: use watchImmediate (#306) --- .../client/composables/useBaiduAnalytics.ts | 1 + plugins/blog/plugin-comment/package.json | 1 + .../src/client/components/ArtalkComment.ts | 25 ++++++++----------- .../src/client/components/TwikooComment.ts | 14 +++-------- .../src/client/components/WalineComment.ts | 5 ++-- .../src/client/helpers/comment.ts | 15 +++++------ plugins/development/plugin-rtl/package.json | 1 + .../src/client/composables/useRtl.ts | 5 ++-- .../src/client/composables/useCopyCode.ts | 13 ++++++---- .../src/client/components/Notice.ts | 24 ++++++++---------- .../src/client/helpers/photo-swipe.ts | 8 +++--- .../features/plugin-watermark/package.json | 1 + .../src/client/composables/setupWatermark.ts | 25 +++++++++---------- .../src/client/helper/watermark.ts | 15 +++++------ .../src/client/helpers/revealJs.ts | 8 +++--- .../src/client/helpers/docsearch.ts | 8 +++--- .../src/client/components/SearchModal.ts | 3 ++- .../src/client/composables/useResults.ts | 12 +++------ .../src/client/composables/useSuggestions.ts | 13 ++++------ .../src/client/helpers/search.ts | 8 +++--- .../composables/setupDevServerRedirect.ts | 7 +++--- pnpm-lock.yaml | 9 +++++++ .../src/client/composables/useDarkMode.ts | 6 ++--- 23 files changed, 106 insertions(+), 121 deletions(-) diff --git a/plugins/analytics/plugin-baidu-analytics/src/client/composables/useBaiduAnalytics.ts b/plugins/analytics/plugin-baidu-analytics/src/client/composables/useBaiduAnalytics.ts index b3a5b4d897..b4c76f1429 100644 --- a/plugins/analytics/plugin-baidu-analytics/src/client/composables/useBaiduAnalytics.ts +++ b/plugins/analytics/plugin-baidu-analytics/src/client/composables/useBaiduAnalytics.ts @@ -32,5 +32,6 @@ export const useBaiduAnalytics = (id: string): void => { (newLocation) => { window._hmt!.push(['_trackPageview', newLocation]) }, + { flush: 'post' }, ) } diff --git a/plugins/blog/plugin-comment/package.json b/plugins/blog/plugin-comment/package.json index cdff79f428..c569d83fa4 100644 --- a/plugins/blog/plugin-comment/package.json +++ b/plugins/blog/plugin-comment/package.json @@ -48,6 +48,7 @@ }, "dependencies": { "@vuepress/helper": "workspace:*", + "@vueuse/core": "12.0.0", "giscus": "^1.5.0", "vue": "^3.5.13" }, diff --git a/plugins/blog/plugin-comment/src/client/components/ArtalkComment.ts b/plugins/blog/plugin-comment/src/client/components/ArtalkComment.ts index f41619f7a6..0a9c1d7daf 100644 --- a/plugins/blog/plugin-comment/src/client/components/ArtalkComment.ts +++ b/plugins/blog/plugin-comment/src/client/components/ArtalkComment.ts @@ -1,4 +1,5 @@ import { LoadingIcon, isString, wait } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type Artalk from 'artalk' import type { VNode } from 'vue' import { @@ -74,33 +75,26 @@ export default defineComponent({ }) } - const updateArtalk = (): void => { - artalk!.update({ - site: site.value.title, - pageTitle: page.value.title, - pageKey: props.identifier, - }) - artalk!.reload() - } - onMounted(() => { - watch( + watchImmediate( () => artalkOptions.value, () => { artalk?.destroy() void initArtalk() }, - { immediate: true }, ) watch( () => props.identifier, () => { - if (artalk) - void nextTick().then(() => { - updateArtalk() - }) + artalk?.update({ + site: site.value.title, + pageTitle: page.value.title, + pageKey: props.identifier, + }) + artalk?.reload() }, + { flush: 'post' }, ) watch( @@ -108,6 +102,7 @@ export default defineComponent({ (value) => { artalk?.setDarkMode(value) }, + { flush: 'post' }, ) }) diff --git a/plugins/blog/plugin-comment/src/client/components/TwikooComment.ts b/plugins/blog/plugin-comment/src/client/components/TwikooComment.ts index 69d0429da9..f09d032cc9 100644 --- a/plugins/blog/plugin-comment/src/client/components/TwikooComment.ts +++ b/plugins/blog/plugin-comment/src/client/components/TwikooComment.ts @@ -1,14 +1,7 @@ import { LoadingIcon, wait } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type { VNode } from 'vue' -import { - computed, - defineComponent, - h, - nextTick, - onMounted, - ref, - watch, -} from 'vue' +import { computed, defineComponent, h, nextTick, onMounted, ref } from 'vue' import { usePageLang } from 'vuepress/client' import { useTwikooOptions } from '../helpers/index.js' @@ -52,10 +45,9 @@ export default defineComponent({ } onMounted(() => { - watch( + watchImmediate( () => [props.identifier, twikooOptions.value], () => initTwikoo(), - { immediate: true }, ) }) diff --git a/plugins/blog/plugin-comment/src/client/components/WalineComment.ts b/plugins/blog/plugin-comment/src/client/components/WalineComment.ts index 277c528508..f8bdb6451f 100644 --- a/plugins/blog/plugin-comment/src/client/components/WalineComment.ts +++ b/plugins/blog/plugin-comment/src/client/components/WalineComment.ts @@ -1,4 +1,5 @@ import { LoadingIcon, useLocaleConfig, wait } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import { pageviewCount } from '@waline/client/pageview' import type { VNode } from 'vue' import { @@ -8,7 +9,6 @@ import { h, nextTick, onMounted, - watch, } from 'vue' import { usePageFrontmatter, usePageLang } from 'vuepress/client' import type { @@ -72,7 +72,7 @@ export default defineComponent({ })) onMounted(() => { - watch( + watchImmediate( () => [ props.identifier, walineOptions.value.serverURL, @@ -93,7 +93,6 @@ export default defineComponent({ }) } }, - { immediate: true }, ) }) diff --git a/plugins/blog/plugin-comment/src/client/helpers/comment.ts b/plugins/blog/plugin-comment/src/client/helpers/comment.ts index bf01b96c6c..dbe83c1faa 100644 --- a/plugins/blog/plugin-comment/src/client/helpers/comment.ts +++ b/plugins/blog/plugin-comment/src/client/helpers/comment.ts @@ -1,6 +1,7 @@ import { isFunction } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type { App, MaybeRefOrGetter, Ref } from 'vue' -import { computed, inject, isRef, readonly, ref, watch } from 'vue' +import { computed, inject, isRef, readonly, ref } from 'vue' import type { ArtalkOptions, CommentOptions, @@ -22,15 +23,11 @@ const defineCommentConfig = ( options: MaybeRefOrGetter, ): void => { if (isRef(options)) { - watch( - () => options.value, - (value) => { - comment.value = { ...commentOptions, ...value } - }, - { immediate: true }, - ) + watchImmediate(options, (value) => { + comment.value = { ...commentOptions, ...value } + }) } else if (isFunction(options)) { - watch(computed(options), (value) => { + watchImmediate(computed(options), (value) => { comment.value = { ...commentOptions, ...value } }) } else { diff --git a/plugins/development/plugin-rtl/package.json b/plugins/development/plugin-rtl/package.json index ea6b45de6c..f057474ec6 100644 --- a/plugins/development/plugin-rtl/package.json +++ b/plugins/development/plugin-rtl/package.json @@ -41,6 +41,7 @@ }, "dependencies": { "@vuepress/helper": "workspace:*", + "@vueuse/core": "^12.0.0", "vue": "^3.5.13" }, "peerDependencies": { diff --git a/plugins/development/plugin-rtl/src/client/composables/useRtl.ts b/plugins/development/plugin-rtl/src/client/composables/useRtl.ts index db62cb675b..e9c572f345 100644 --- a/plugins/development/plugin-rtl/src/client/composables/useRtl.ts +++ b/plugins/development/plugin-rtl/src/client/composables/useRtl.ts @@ -1,5 +1,6 @@ import { entries } from '@vuepress/helper/client' -import { onMounted, watch } from 'vue' +import { watchImmediate } from '@vueuse/core' +import { onMounted } from 'vue' import { useRouteLocale } from 'vuepress/client' import { getElement } from '../utils/index.js' @@ -46,6 +47,6 @@ export const useRtl = ( } onMounted(() => { - watch(routeLocale, toggleRTL, { immediate: true }) + watchImmediate(routeLocale, toggleRTL) }) } diff --git a/plugins/features/plugin-copy-code/src/client/composables/useCopyCode.ts b/plugins/features/plugin-copy-code/src/client/composables/useCopyCode.ts index 698f7f4afe..9415f8abf3 100644 --- a/plugins/features/plugin-copy-code/src/client/composables/useCopyCode.ts +++ b/plugins/features/plugin-copy-code/src/client/composables/useCopyCode.ts @@ -1,6 +1,11 @@ import { useLocaleConfig, wait } from '@vuepress/helper/client' -import { useClipboard, useEventListener, useMediaQuery } from '@vueuse/core' -import { computed, nextTick, watch } from 'vue' +import { + useClipboard, + useEventListener, + useMediaQuery, + watchImmediate, +} from '@vueuse/core' +import { computed, nextTick } from 'vue' import { usePageData } from 'vuepress/client' import type { CopyCodePluginLocaleConfig } from '../../shared/index.js' @@ -90,9 +95,7 @@ export const useCopyCode = ({ .forEach(insertCopyButton) } - watch(() => [page.value.path, enabled.value], appendCopyButton, { - immediate: true, - }) + watchImmediate(() => [page.value.path, enabled.value], appendCopyButton) const { copy } = useClipboard({ legacy: true }) const timeoutIdMap = new WeakMap>() diff --git a/plugins/features/plugin-notice/src/client/components/Notice.ts b/plugins/features/plugin-notice/src/client/components/Notice.ts index f72c1803e2..e14ad978a1 100644 --- a/plugins/features/plugin-notice/src/client/components/Notice.ts +++ b/plugins/features/plugin-notice/src/client/components/Notice.ts @@ -1,4 +1,5 @@ import { isLinkAbsolute, isLinkHttp, startsWith } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type { PropType } from 'vue' import { TransitionGroup, @@ -7,7 +8,6 @@ import { h, onMounted, ref, - watch, } from 'vue' import { useRoutePath, useRouter } from 'vuepress/client' import type { NoticeItemOptions } from '../../shared/index.js' @@ -86,19 +86,15 @@ export const Notice = defineComponent({ } onMounted(() => { - watch( - matchedConfig, - () => { - if (matchedConfig.value) { - const hasBeenClosed = ( - matchedConfig.value.showOnce ? localStorage : sessionStorage - ).getItem(matchedConfig.value.key) - - isVisible.value = !hasBeenClosed - } - }, - { immediate: true }, - ) + watchImmediate(matchedConfig, () => { + if (matchedConfig.value) { + const hasBeenClosed = ( + matchedConfig.value.showOnce ? localStorage : sessionStorage + ).getItem(matchedConfig.value.key) + + isVisible.value = !hasBeenClosed + } + }) }) return () => diff --git a/plugins/features/plugin-photo-swipe/src/client/helpers/photo-swipe.ts b/plugins/features/plugin-photo-swipe/src/client/helpers/photo-swipe.ts index 79f73b6fbd..f3f984f751 100644 --- a/plugins/features/plugin-photo-swipe/src/client/helpers/photo-swipe.ts +++ b/plugins/features/plugin-photo-swipe/src/client/helpers/photo-swipe.ts @@ -1,7 +1,8 @@ import { isFunction } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type { PhotoSwipeOptions as OriginalPhotoSwipeOptions } from 'photoswipe' import type { App, InjectionKey, MaybeRefOrGetter, Ref } from 'vue' -import { computed, inject, isRef, ref, watch } from 'vue' +import { computed, inject, isRef, ref } from 'vue' export type PhotoSwipeOptions = Omit< OriginalPhotoSwipeOptions, @@ -23,15 +24,14 @@ export const definePhotoSwipeConfig = ( options: MaybeRefOrGetter, ): void => { if (isRef(options)) { - watch( + watchImmediate( () => options.value, (value) => { photoswipeOptions.value = value }, - { immediate: true }, ) } else if (isFunction(options)) { - watch(computed(options), (value) => { + watchImmediate(computed(options), (value) => { photoswipeOptions.value = value }) } else { diff --git a/plugins/features/plugin-watermark/package.json b/plugins/features/plugin-watermark/package.json index b0d43cfd4b..207ca36e86 100644 --- a/plugins/features/plugin-watermark/package.json +++ b/plugins/features/plugin-watermark/package.json @@ -36,6 +36,7 @@ "clean": "rimraf --glob ./lib ./*.tsbuildinfo" }, "dependencies": { + "@vueuse/core": "^12.0.0", "@vuepress/helper": "workspace:*", "vue": "^3.5.13", "watermark-js-plus": "^1.5.7" diff --git a/plugins/features/plugin-watermark/src/client/composables/setupWatermark.ts b/plugins/features/plugin-watermark/src/client/composables/setupWatermark.ts index df1e896482..fb8685cc85 100644 --- a/plugins/features/plugin-watermark/src/client/composables/setupWatermark.ts +++ b/plugins/features/plugin-watermark/src/client/composables/setupWatermark.ts @@ -1,6 +1,7 @@ import { wait } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type { MaybeRef, Ref } from 'vue' -import { isRef, nextTick, onMounted, toValue, watch } from 'vue' +import { isRef, onMounted, toValue, watch } from 'vue' import { useRoutePath, useSiteLocaleData, withBase } from 'vuepress/client' import { Watermark } from 'watermark-js-plus' import type { WatermarkOptions } from '../helper/index.js' @@ -36,19 +37,17 @@ export const setupWatermark = ( } } - watch( + watchImmediate( [enabled, routePath], - () => - nextTick(() => { - if (enabled.value) { - void wait(delay).then(() => { - updateWaterMark(toValue(options)) - }) - } else { - watermark.destroy() - } - }), - { immediate: true }, + async () => { + if (enabled.value) { + await wait(delay) + updateWaterMark(toValue(options)) + } else { + watermark.destroy() + } + }, + { flush: 'post' }, ) if (isRef(options)) watch(options, updateWaterMark) diff --git a/plugins/features/plugin-watermark/src/client/helper/watermark.ts b/plugins/features/plugin-watermark/src/client/helper/watermark.ts index 039beeda43..9b01d0b005 100644 --- a/plugins/features/plugin-watermark/src/client/helper/watermark.ts +++ b/plugins/features/plugin-watermark/src/client/helper/watermark.ts @@ -1,4 +1,5 @@ import { isFunction, isPlainObject } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type { App, ComputedRef, @@ -7,7 +8,7 @@ import type { MaybeRefOrGetter, Ref, } from 'vue' -import { computed, inject, isRef, ref, toValue, watch } from 'vue' +import { computed, inject, isRef, ref, toValue } from 'vue' import { usePageFrontmatter } from 'vuepress/client' import type { WatermarkOptions as WatermarkRawOptions } from 'watermark-js-plus' import type { WatermarkPluginFrontmatter } from '../../shared/index.js' @@ -57,15 +58,11 @@ export const defineWatermarkConfig = ( userConfig: MaybeRefOrGetter, ): void => { if (isRef(userConfig)) { - watch( - userConfig, - (value) => { - watermarkOptions.value = value - }, - { immediate: true }, - ) + watchImmediate(userConfig, (value) => { + watermarkOptions.value = value + }) } else if (isFunction(userConfig)) { - watch(computed(userConfig), (value) => { + watchImmediate(computed(userConfig), (value) => { watermarkOptions.value = value }) } else { diff --git a/plugins/markdown/plugin-revealjs/src/client/helpers/revealJs.ts b/plugins/markdown/plugin-revealjs/src/client/helpers/revealJs.ts index 420f34cb8f..503f3660d9 100644 --- a/plugins/markdown/plugin-revealjs/src/client/helpers/revealJs.ts +++ b/plugins/markdown/plugin-revealjs/src/client/helpers/revealJs.ts @@ -1,7 +1,8 @@ +import { watchImmediate } from '@vueuse/core' // eslint-disable-next-line import/no-rename-default import type Reveal from 'reveal.js' import type { App, InjectionKey, MaybeRefOrGetter, Ref } from 'vue' -import { computed, inject, isRef, ref, watch } from 'vue' +import { computed, inject, isRef, ref } from 'vue' import { isFunction } from 'vuepress/shared' declare const __VUEPRESS_DEV__: boolean @@ -20,15 +21,14 @@ export const defineRevealJsConfig = ( options: MaybeRefOrGetter, ): void => { if (isRef(options)) { - watch( + watchImmediate( () => options.value, (value) => { revealOptions.value = value }, - { immediate: true }, ) } else if (isFunction(options)) { - watch(computed(options), (value) => { + watchImmediate(computed(options), (value) => { revealOptions.value = value }) } else { diff --git a/plugins/search/plugin-docsearch/src/client/helpers/docsearch.ts b/plugins/search/plugin-docsearch/src/client/helpers/docsearch.ts index f0f17b4ea0..2dbe12ce19 100644 --- a/plugins/search/plugin-docsearch/src/client/helpers/docsearch.ts +++ b/plugins/search/plugin-docsearch/src/client/helpers/docsearch.ts @@ -1,7 +1,8 @@ import type { DocSearchProps } from '@docsearch/react' import { deepAssign, isFunction } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type { App, ComputedRef, InjectionKey, MaybeRefOrGetter, Ref } from 'vue' -import { computed, inject, isRef, readonly, ref, watch } from 'vue' +import { computed, inject, isRef, readonly, ref } from 'vue' import { useRouteLocale } from 'vuepress/client' import type { DocSearchOptions } from '../../shared/index.js' @@ -30,15 +31,14 @@ export const defineDocSearchConfig = ( options: MaybeRefOrGetter, ): void => { if (isRef(options)) { - watch( + watchImmediate( () => options.value, (value) => { docsearchOptions.value = deepAssign({}, docSearchDefineOptions, value) }, - { immediate: true }, ) } else if (isFunction(options)) { - watch(computed(options), (value) => { + watchImmediate(computed(options), (value) => { docsearchOptions.value = deepAssign({}, docSearchDefineOptions, value) }) } else { diff --git a/plugins/search/plugin-slimsearch/src/client/components/SearchModal.ts b/plugins/search/plugin-slimsearch/src/client/components/SearchModal.ts index 7a78afa804..d4dbc0a114 100644 --- a/plugins/search/plugin-slimsearch/src/client/components/SearchModal.ts +++ b/plugins/search/plugin-slimsearch/src/client/components/SearchModal.ts @@ -4,6 +4,7 @@ import { useDebounceFn, useEventListener, useScrollLock, + watchImmediate, } from '@vueuse/core' import type { VNode } from 'vue' import { @@ -110,7 +111,7 @@ export default defineComponent({ Math.min(options.searchDelay, options.suggestDelay), ) - watch(input, updateQueries, { immediate: true }) + watchImmediate(input, updateQueries) onMounted(() => { const isLocked = useScrollLock(document.body) diff --git a/plugins/search/plugin-slimsearch/src/client/composables/useResults.ts b/plugins/search/plugin-slimsearch/src/client/composables/useResults.ts index 3edb2302f4..f5357582bf 100644 --- a/plugins/search/plugin-slimsearch/src/client/composables/useResults.ts +++ b/plugins/search/plugin-slimsearch/src/client/composables/useResults.ts @@ -1,6 +1,6 @@ -import { useDebounceFn } from '@vueuse/core' +import { useDebounceFn, watchImmediate } from '@vueuse/core' import type { Ref } from 'vue' -import { computed, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue' +import { computed, onMounted, onUnmounted, ref, shallowRef } from 'vue' import { usePageData, useRouteLocale } from 'vuepress/client' import { options } from '../define.js' @@ -59,12 +59,8 @@ export const useResults = (queries: Ref): Results => { { maxWait: 5000 }, ) - watch( - [queries, routeLocale], - ([newQueries]) => { - void performSearch(newQueries.join(' ')) - }, - { immediate: true }, + watchImmediate([queries, routeLocale], ([newQueries]) => + performSearch(newQueries.join(' ')), ) onUnmounted(() => { diff --git a/plugins/search/plugin-slimsearch/src/client/composables/useSuggestions.ts b/plugins/search/plugin-slimsearch/src/client/composables/useSuggestions.ts index 184b345fbe..6020c7b8b6 100644 --- a/plugins/search/plugin-slimsearch/src/client/composables/useSuggestions.ts +++ b/plugins/search/plugin-slimsearch/src/client/composables/useSuggestions.ts @@ -1,6 +1,7 @@ import { startsWith } from '@vuepress/helper/client' +import { watchImmediate } from '@vueuse/core' import type { Ref } from 'vue' -import { onMounted, onUnmounted, ref, watch } from 'vue' +import { onMounted, onUnmounted, ref } from 'vue' import { usePageData, useRouteLocale } from 'vuepress/client' import { useSearchOptions } from '../helpers/index.js' @@ -57,13 +58,9 @@ export const useSuggestions = (queries: Ref): SuggestionsRef => { else suggestions.value = [] } - watch( - [queries, routeLocale], - ([newQueries]) => { - performSuggestion(newQueries.join(' ')) - }, - { immediate: true }, - ) + watchImmediate([queries, routeLocale], ([newQueries]) => { + performSuggestion(newQueries.join(' ')) + }) onUnmounted(() => { terminate() diff --git a/plugins/search/plugin-slimsearch/src/client/helpers/search.ts b/plugins/search/plugin-slimsearch/src/client/helpers/search.ts index c9c7b68aff..37bac18aba 100644 --- a/plugins/search/plugin-slimsearch/src/client/helpers/search.ts +++ b/plugins/search/plugin-slimsearch/src/client/helpers/search.ts @@ -1,5 +1,6 @@ +import { watchImmediate } from '@vueuse/core' import type { App, ComputedRef, InjectionKey, MaybeRefOrGetter, Ref } from 'vue' -import { computed, inject, isRef, readonly, ref, watch } from 'vue' +import { computed, inject, isRef, readonly, ref } from 'vue' import type { PageData } from 'vuepress/client' import { useRouteLocale } from 'vuepress/client' @@ -46,15 +47,14 @@ export const defineSearchConfig = ( options: MaybeRefOrGetter, ): void => { if (isRef(options)) { - watch( + watchImmediate( () => options.value, (value) => { searchOptions.value = value }, - { immediate: true }, ) } else if (isFunction(options)) { - watch(computed(options), (value) => { + watchImmediate(computed(options), (value) => { searchOptions.value = value }) } else { diff --git a/plugins/tools/plugin-redirect/src/client/composables/setupDevServerRedirect.ts b/plugins/tools/plugin-redirect/src/client/composables/setupDevServerRedirect.ts index c139045f79..8ac875ed1b 100644 --- a/plugins/tools/plugin-redirect/src/client/composables/setupDevServerRedirect.ts +++ b/plugins/tools/plugin-redirect/src/client/composables/setupDevServerRedirect.ts @@ -1,7 +1,7 @@ import { redirectMap } from '@temp/redirect/map.js' import { entries, isLinkHttp } from '@vuepress/helper/client' -import { usePreferredLanguages } from '@vueuse/core' -import { computed, watch } from 'vue' +import { usePreferredLanguages, watchImmediate } from '@vueuse/core' +import { computed } from 'vue' import { useRoute, useRouteLocale, useRouter } from 'vuepress/client' import type { RedirectBehaviorConfig } from '../../shared/index.js' import { normalizePath } from '../../shared/index.js' @@ -88,7 +88,7 @@ export const setupDevServerRedirect = ({ } } - watch( + watchImmediate( () => route.path, (path) => { // handle redirects @@ -102,6 +102,5 @@ export const setupDevServerRedirect = ({ if (autoLocale && isRootLocale.value) handleLocaleRedirect() }, - { immediate: true }, ) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 728f2688c5..860fc06c6b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -334,6 +334,9 @@ importers: '@vuepress/helper': specifier: workspace:* version: link:../../../tools/helper + '@vueuse/core': + specifier: 12.0.0 + version: 12.0.0(typescript@5.7.2) '@waline/client': specifier: ^3.4.1 version: 3.4.2(typescript@5.7.2) @@ -419,6 +422,9 @@ importers: '@vuepress/helper': specifier: workspace:* version: link:../../../tools/helper + '@vueuse/core': + specifier: ^12.0.0 + version: 12.0.0(typescript@5.7.2) vue: specifier: ^3.5.13 version: 3.5.13(typescript@5.7.2) @@ -600,6 +606,9 @@ importers: '@vuepress/helper': specifier: workspace:* version: link:../../../tools/helper + '@vueuse/core': + specifier: ^12.0.0 + version: 12.0.0(typescript@5.7.2) vue: specifier: ^3.5.13 version: 3.5.13(typescript@5.7.2) diff --git a/themes/theme-default/src/client/composables/useDarkMode.ts b/themes/theme-default/src/client/composables/useDarkMode.ts index ef2978d742..8c633ed098 100644 --- a/themes/theme-default/src/client/composables/useDarkMode.ts +++ b/themes/theme-default/src/client/composables/useDarkMode.ts @@ -1,7 +1,7 @@ import { useThemeLocaleData } from '@theme/useThemeData' -import { usePreferredDark, useStorage } from '@vueuse/core' +import { usePreferredDark, useStorage, watchImmediate } from '@vueuse/core' import type { InjectionKey, WritableComputedRef } from 'vue' -import { computed, inject, onMounted, onUnmounted, provide, watch } from 'vue' +import { computed, inject, onMounted, onUnmounted, provide } from 'vue' export type DarkModeRef = WritableComputedRef @@ -19,7 +19,7 @@ const applyDarkmodeToHTML = (isDarkMode: DarkModeRef): void => { } onMounted(() => { - watch(isDarkMode, update, { immediate: true }) + watchImmediate(isDarkMode, update) }) onUnmounted(() => { From 4fdde2cca2c89344d692ebad7a806a48959a3d46 Mon Sep 17 00:00:00 2001 From: pengzhanbo Date: Tue, 17 Dec 2024 13:24:07 +0800 Subject: [PATCH 02/22] feat(plugin-git): improve contributors sorting (#309) --- plugins/development/plugin-git/src/node/resolveContributors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/development/plugin-git/src/node/resolveContributors.ts b/plugins/development/plugin-git/src/node/resolveContributors.ts index 43827546af..404e17b57b 100644 --- a/plugins/development/plugin-git/src/node/resolveContributors.ts +++ b/plugins/development/plugin-git/src/node/resolveContributors.ts @@ -17,7 +17,7 @@ export const getRawContributors = ( ): GitContributor[] => { const contributors = new Map() - for (const commit of commits) { + for (const commit of commits.reverse()) { const authors = [ { name: commit.author, email: commit.email }, ...commit.coAuthors, From 3e9cd968e5d0bf9679d24c0e7cf61ab97d7c6a4a Mon Sep 17 00:00:00 2001 From: LHJ Piper <39236178+PiperLiu@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:36:27 +0800 Subject: [PATCH 03/22] fix(create-vuepress): wrong registry command (#312) --- tools/create-vuepress/src/utils/getRegistry.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/create-vuepress/src/utils/getRegistry.ts b/tools/create-vuepress/src/utils/getRegistry.ts index 976f3a5ee5..6085511908 100644 --- a/tools/create-vuepress/src/utils/getRegistry.ts +++ b/tools/create-vuepress/src/utils/getRegistry.ts @@ -34,7 +34,7 @@ export const getRegistry = async ( execaCommandSync( `${packageManager} config set ${ isYarnModern ? 'npmRegistryServer' : 'registry' - }} ${NPM_MIRROR_REGISTRY}`, + } ${NPM_MIRROR_REGISTRY}`, ) } From 5308fb48310d3f0c6af4adc1a98f2e6747c85f33 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Sat, 21 Dec 2024 00:47:20 +0800 Subject: [PATCH 04/22] feat: rebuild built-in locale data (#315) --- docs/tools/helper/node/locales.md | 67 ++ docs/zh/tools/helper/node/locales.md | 67 ++ .../plugin-comment/src/node/commentPlugin.ts | 8 +- .../blog/plugin-comment/src/node/locales.ts | 239 +++--- .../plugin-reading-time/src/node/locales.ts | 281 ++++--- .../src/node/readingTimePlugin.ts | 8 +- .../src/node/backToTopPlugin.ts | 8 +- .../plugin-back-to-top/src/node/locales.ts | 111 +-- .../plugin-catalog/src/node/catalogPlugin.ts | 8 +- .../plugin-catalog/src/node/locales.ts | 131 +--- .../src/node/copyCodePlugin.ts | 8 +- .../plugin-copy-code/src/node/locales.ts | 132 +--- .../src/node/copyrightPlugin.ts | 12 +- .../plugin-copyright/src/node/locales.ts | 251 +++--- .../plugin-photo-swipe/src/node/locales.ts | 412 +++++----- .../src/node/photoSwipePlugin.ts | 8 +- .../plugin-markdown-hint/src/node/locales.ts | 448 ++++++----- .../src/node/markdownHintPlugin.ts | 8 +- .../pwa/plugin-pwa/src/node/getManifest.ts | 4 +- plugins/pwa/plugin-pwa/src/node/locales.ts | 668 ++++++++-------- .../src/node/prepareClientConfigFile.ts | 8 +- .../plugin-slimsearch/src/node/locales.ts | 730 ++++++++++-------- .../src/node/slimsearchPlugin.ts | 8 +- .../tools/plugin-redirect/src/node/locales.ts | 390 +++++----- .../src/node/redirectPlugin.ts | 8 +- tools/helper/src/node/locales/config.ts | 1 + .../src/node/locales/getFullLocaleConfig.ts | 105 +++ tools/helper/src/node/locales/helpers.ts | 22 +- tools/helper/src/node/locales/index.ts | 1 + tools/helper/src/node/locales/types.ts | 15 +- .../helper/tests/node/locales.legacy.spec.ts | 487 ++++++++++++ tools/helper/tests/node/locales.spec.ts | 538 ++++++------- 32 files changed, 3005 insertions(+), 2187 deletions(-) create mode 100644 docs/tools/helper/node/locales.md create mode 100644 docs/zh/tools/helper/node/locales.md create mode 100644 tools/helper/src/node/locales/getFullLocaleConfig.ts create mode 100644 tools/helper/tests/node/locales.legacy.spec.ts diff --git a/docs/tools/helper/node/locales.md b/docs/tools/helper/node/locales.md new file mode 100644 index 0000000000..e9b73a883a --- /dev/null +++ b/docs/tools/helper/node/locales.md @@ -0,0 +1,67 @@ +# Locales Related + +These functions are only available in `@vuepress/helper`. + +## getFullLocaleConfig + +A helper function to get full locale config from built-in locale info and user configuration. + +```ts +export interface GetLocaleConfigOption { + app: App + default: DefaultLocaleInfo + config?: LocaleConfig | undefined + name?: string +} + +export const getFullLocaleConfig: ( + options: GetLocaleConfigOption, +) => ExactLocaleConfig +``` + +- The `app` parameter is the VuePress Node app instance. +- The `default` parameter is the default locale info, where this should be an array of locale info settings. + + Each locale info setting should be an tuple with two elements: + + - The first element are an array of lang code that the locale info setting belongs to. + - The second element are the locale info setting. + + An example of `default` parameter: + + ```ts + const defaultLocaleInfo = [ + [ + ['en'], + { title: 'VuePress', description: 'Vue-powered Static Site Generator' }, + ], + [ + ['zh', 'zh-CN'], + { title: 'VuePress', description: 'Vue 驱动的静态网站生成器' }, + ], + [['zh-TW'], { title: 'VuePress', description: 'Vue 驅動的靜態網站生成器' }], + ] + ``` + +- The `config` parameter is the user locale config, which is optional. + + It should be an object with localePath as key and partial locale info setting as value. + + An example of `config` parameter: + + ```ts + const userLocaleConfig = { + '/zh/': { description: '由 Vue 驱动的静态网站生成器' }, + '/zh-TW/': { description: '由 Vue 驅動的靜態網站生成器' }, + } + ``` + +- The `name` parameter is the plugin name, which is optional, only used for logging. + +The function will automatically merge the default locale info and user locale config, and return the final locale config, where the user locale config will override the default locale info. + +The default locale info will be chosen based on the current language of each locale in site config, and when a locale's lang code is not found in the default locale info, it will fallback to the first one of the following that exists: + +- locale info of `en-US` +- locale info of `en` +- locale info of first element in the default locale info diff --git a/docs/zh/tools/helper/node/locales.md b/docs/zh/tools/helper/node/locales.md new file mode 100644 index 0000000000..545405cf10 --- /dev/null +++ b/docs/zh/tools/helper/node/locales.md @@ -0,0 +1,67 @@ +# 多语言相关 + +这些函数仅在 `@vuepress/helper` 中可用。 + +## getFullLocaleConfig + +一个从内置的 locale 信息和用户配置中获取完整 locale 配置的辅助函数。 + +```ts +export interface GetLocaleConfigOption { + app: App + default: DefaultLocaleInfo + config?: LocaleConfig | undefined + name?: string +} + +export const getFullLocaleConfig: ( + options: GetLocaleConfigOption, +) => ExactLocaleConfig +``` + +- `app` 参数是 VuePress Node app 实例。 +- `default` 参数是默认的 locale 信息,应该是一个 locale 信息设置的数组。 + + 每个 locale 信息设置应该是一个包含两个元素的元组: + + - 第一个元素是 locale 信息设置所属的语言代码数组。 + - 第二个元素是 locale 信息设置。 + + `default` 参数的示例: + + ```ts + const defaultLocaleInfo = [ + [ + ['en'], + { title: 'VuePress', description: 'Vue-powered Static Site Generator' }, + ], + [ + ['zh', 'zh-CN'], + { title: 'VuePress', description: 'Vue 驱动的静态网站生成器' }, + ], + [['zh-TW'], { title: 'VuePress', description: 'Vue 驅動的靜態網站生成器' }], + ] + ``` + +- `config` 参数是用户 locale 配置,是可选的。 + + 它应该是一个以 localePath 为键,以部分 locale 信息设置为值的对象。 + + `config` 参数的示例: + + ```ts + const userLocaleConfig = { + '/zh/': { description: '由 Vue 驱动的静态网站生成器' }, + '/zh-TW/': { description: '由 Vue 驅動的靜態網站生成器' }, + } + ``` + +- `name` 参数是插件名称,是可选的,仅用于日志记录。 + +函数将自动合并默认的 locale 信息和用户 locale 配置,并返回最终的 locale 配置,其中用户 locale 配置将覆盖默认的 locale 信息。 + +默认的 locale 信息将根据站点配置中每个 locale 的当前语言选择,当 locale 的语言代码在默认的 locale 信息中找不到时,它将回退到以下存在的第一个: + +- `en-US` 的 locale 信息 +- `en` 的 locale 信息 +- 默认 locale 信息的第一个元素 diff --git a/plugins/blog/plugin-comment/src/node/commentPlugin.ts b/plugins/blog/plugin-comment/src/node/commentPlugin.ts index a5ad1cd6cc..f6bba2ee57 100644 --- a/plugins/blog/plugin-comment/src/node/commentPlugin.ts +++ b/plugins/blog/plugin-comment/src/node/commentPlugin.ts @@ -4,12 +4,12 @@ import { addViteOptimizeDepsInclude, addViteSsrExternal, addViteSsrNoExternal, - getLocaleConfig, + getFullLocaleConfig, isModuleAvailable, } from '@vuepress/helper' import type { PluginFunction } from 'vuepress/core' import { getAlias, getProviderPackage } from './getProvider.js' -import { walineLocales } from './locales.js' +import { walineLocalesInfo } from './locales.js' import type { CommentPluginOptions } from './options.js' import { CLIENT_FOLDER, PLUGIN_NAME, logger } from './utils.js' @@ -41,10 +41,10 @@ export const commentPlugin = define: () => { const userWalineLocales = options.provider === 'Waline' - ? getLocaleConfig({ + ? getFullLocaleConfig({ app, name: 'waline', - default: walineLocales, + default: walineLocalesInfo, config: options.locales, }) : {} diff --git a/plugins/blog/plugin-comment/src/node/locales.ts b/plugins/blog/plugin-comment/src/node/locales.ts index e73ebde70c..06e69ddbab 100644 --- a/plugins/blog/plugin-comment/src/node/locales.ts +++ b/plugins/blog/plugin-comment/src/node/locales.ts @@ -1,103 +1,142 @@ -import type { WalineLocaleConfig } from '../shared/index.js' +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { WalineLocaleData } from '../shared/index.js' /** - * Default locale config for Waline + * Default locale info for Waline */ -export const walineLocales: WalineLocaleConfig = { - '/en/': { - placeholder: - 'Write a comment here (Fill in the email address to receive an email notification when being replied)', - }, - - '/zh/': { - placeholder: '请留言。(填写邮箱可在被回复时收到邮件提醒)', - }, - - '/zh-tw/': { - placeholder: '請留言。(填寫信箱可在被回覆時收到郵件提醒)', - }, - - '/de/': { - placeholder: - 'Schreibe ein Kommentar (Geben Sie die E-Mail-Adresse ein, um eine E-Mail-Benachrichtigung zu erhalten, wenn Sie eine Antwort erhalten)', - }, - - '/de-at/': { - placeholder: - 'Schreibe ein Kommentar (Geben Sie die E-Mail-Adresse ein, um eine E-Mail-Benachrichtigung zu erhalten, wenn Sie eine Antwort erhalten)', - }, - - '/vi/': { - placeholder: - 'Để lại bình luận (Điền địa chỉ email để nhận email thông báo khi được trả lời)', - }, - - '/uk/': { - placeholder: - 'Напишіть тут коментар (введіть адресу електронної пошти, щоб отримувати сповіщення електронною поштою, коли буде відповідь)', - }, - - '/ru/': { - placeholder: - 'Напишите комментарий здесь (Введите адрес электронной почты, чтобы получить уведомление по электронной почте при ответе)', - }, - - '/br/': { - placeholder: - 'Escreva um comentário aqui (preencha com o endereço de email para receber notificações quando tiver alguma resposta)', - }, - - '/pl/': { - placeholder: - 'Wpisz tutaj komentarz (wpisz adres e-mail, aby otrzymać powiadomienie e-mail, gdy otrzymasz odpowiedź)', - }, - - '/sk/': { - placeholder: - 'Napíš svoj komentár (vlož svoj e-mail taktiež, aby si bol notifikovaný o odpovediach)', - }, - - '/fr/': { - placeholder: - 'Écrivez votre commentaire ici (Inscrivez votre email afin de recevoir une notification en cas de réponse)', - }, - - '/es/': { - placeholder: - 'Escriba un comentario aquí (Ingrese su correo electrónico para recibir una notificación en caso de respuesta)', - }, - - '/ja/': { - placeholder: - '伝言をどうぞ (メールアドレスを入力すると、返信があった際にメールでお知らせします。)', - }, - - '/tr/': { - placeholder: - 'Buraya bir yorum yazın (Yanıtlandığında bir e-posta bildirimi almak için e-posta adresinizi girin)', - }, - - '/ko/': { - placeholder: - '댓글을 남겨주세요 (답글이 달렸을 때 이메일로 알림을 받으려면 이메일 주소를 입력하세요)', - }, - - '/fi/': { - placeholder: - 'Kirjoita kommentti tähän (täytä sähköpostiosoite saadaksesi sähköposti-ilmoituksen vastauksesta)', - }, - '/hu/': { - placeholder: - 'Írj kommentet itt! (Töltsd ki az email címet, hogy értesítést kapj, amikor válaszolnak.)', - }, - - '/id/': { - placeholder: - 'Tulis komentar di sini (Isi alamat email untuk menerima notifikasi jika komentar kamu telah dibalas orang lain)', - }, - - '/nl/': { - placeholder: - 'Schrijf een opmerking hier (Vul je emailadres in om een email-notificatie te ontvangen wanneer er gereageerd wordt.', - }, -} +export const walineLocalesInfo: DefaultLocaleInfo = [ + [ + ['en', 'en-US'], + { + placeholder: + 'Write a comment here (Fill in the email address to receive an email notification when being replied)', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { placeholder: '请留言。(填写邮箱可在被回复时收到邮件提醒)' }, + ], + [ + ['zh-TW', 'zh-Hant'], + { placeholder: '請留言。(填寫信箱可在被回覆時收到郵件提醒)' }, + ], + [ + ['de', 'de-DE'], + { + placeholder: + 'Schreibe ein Kommentar (Geben Sie die E-Mail-Adresse ein, um eine E-Mail-Benachrichtigung zu erhalten, wenn Sie eine Antwort erhalten)', + }, + ], + [ + ['de-AT'], + { + placeholder: + 'Schreibe ein Kommentar (Geben Sie die E-Mail-Adresse ein, um eine E-Mail-Benachrichtigung zu erhalten, wenn Sie eine Antwort erhalten)', + }, + ], + [ + ['vi', 'vi-VN'], + { + placeholder: + 'Để lại bình luận (Điền địa chỉ email để nhận email thông báo khi được trả lời)', + }, + ], + [ + ['uk', 'uk-UA'], + { + placeholder: + 'Напишіть тут коментар (введіть адресу електронної пошти, щоб отримувати сповіщення електронною поштою, коли буде відповідь)', + }, + ], + [ + ['ru', 'ru-RU'], + { + placeholder: + 'Напишите комментарий здесь (Введите адрес электронной почты, чтобы получить уведомление по электронной почте при ответе)', + }, + ], + [ + ['br', 'br-BR'], + { + placeholder: + 'Escreva um comentário aqui (preencha com o endereço de email para receber notificações quando tiver alguma resposta)', + }, + ], + [ + ['pl', 'pl-PL'], + { + placeholder: + 'Wpisz tutaj komentarz (wpisz adres e-mail, aby otrzymać powiadomienie e-mail, gdy otrzymasz odpowiedź)', + }, + ], + [ + ['sk', 'sk-SK'], + { + placeholder: + 'Napíš svoj komentár (vlož svoj e-mail taktiež, aby si bol notifikovaný o odpovediach)', + }, + ], + [ + ['fr', 'fr-FR'], + { + placeholder: + 'Écrivez votre commentaire ici (Inscrivez votre email afin de recevoir une notification en cas de réponse)', + }, + ], + [ + ['es', 'es-ES'], + { + placeholder: + 'Escriba un comentario aquí (Ingrese su correo electrónico para recibir una notificación en caso de respuesta)', + }, + ], + [ + ['ja', 'ja-JP'], + { + placeholder: + '伝言をどうぞ (メールアドレスを入力すると、返信があった際にメールでお知らせします。)', + }, + ], + [ + ['tr', 'tr-TR'], + { + placeholder: + 'Buraya bir yorum yazın (Yanıtlandığında bir e-posta bildirimi almak için e-posta adresinizi girin)', + }, + ], + [ + ['ko', 'ko-KO'], + { + placeholder: + '댓글을 남겨주세요 (답글이 달렸을 때 이메일로 알림을 받으려면 이메일 주소를 입력하세요)', + }, + ], + [ + ['fi', 'fi-FI'], + { + placeholder: + 'Kirjoita kommentti tähän (täytä sähköpostiosoite saadaksesi sähköposti-ilmoituksen vastauksesta)', + }, + ], + [ + ['hu', 'hu-HU'], + { + placeholder: + 'Írj kommentet itt! (Töltsd ki az email címet, hogy értesítést kapj, amikor válaszolnak.)', + }, + ], + [ + ['id', 'id-ID'], + { + placeholder: + 'Tulis komentar di sini (Isi alamat email untuk menerima notifikasi jika komentar kamu telah dibalas orang lain)', + }, + ], + [ + ['nl', 'nl-NL'], + { + placeholder: + 'Schrijf een opmerking hier (Vul je emailadres in om een email-notificatie te ontvangen wanneer er gereageerd wordt.', + }, + ], +] diff --git a/plugins/development/plugin-reading-time/src/node/locales.ts b/plugins/development/plugin-reading-time/src/node/locales.ts index 662fb4397f..71b51db526 100644 --- a/plugins/development/plugin-reading-time/src/node/locales.ts +++ b/plugins/development/plugin-reading-time/src/node/locales.ts @@ -1,126 +1,161 @@ -import type { ReadingTimePluginLocaleConfig } from '../shared/index.js' +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { ReadingTimePluginLocaleData } from '../shared/index.js' /** - * Default locale config for `@vuepress/plugin-reading-time` plugin + * Default locale info for `@vuepress/plugin-reading-time` */ -export const readingTimeLocales: ReadingTimePluginLocaleConfig = { - '/en/': { - word: 'About $word words', - less1Minute: 'Less than 1 minute', - time: 'About $time min', - }, - - '/zh/': { - word: '约 $word 字', - less1Minute: '小于 1 分钟', - time: '大约 $time 分钟', - }, - - '/zh-tw/': { - word: '約 $word 字', - less1Minute: '小於 1 分鐘', - time: '大约 $time 分鐘', - }, - - '/de/': { - word: 'Ungefähr $word Wörter', - less1Minute: 'Weniger als eine Minute', - time: 'Ungefähr $time min', - }, - - '/de-at/': { - word: 'Um die $word Wörter', - less1Minute: 'Weniger als eine Minute', - time: 'Ungefähr $time min', - }, - - '/vi/': { - word: 'Khoảng $word từ', - less1Minute: 'Ít hơn 1 phút', - time: 'Khoảng $time phút', - }, - - '/uk/': { - word: 'Про $word слова', - less1Minute: 'Менше 1 хвилини', - time: 'Приблизно $time хв', - }, - - '/ru/': { - word: 'Около $word слов', - less1Minute: 'Меньше 1 минуты', - time: 'Около $time мин', - }, - - '/br/': { - word: 'Por volta de $word palavras', - less1Minute: 'Menos de 1 minuto', - time: 'Por volta de $time min', - }, - - '/pl/': { - word: 'Około $word słów', - less1Minute: 'Mniej niż 1 minuta', - time: 'Około $time minut', - }, - - '/sk/': { - word: 'Okolo $word slov', - less1Minute: 'Menej ako 1 minúta', - time: 'Okolo $time minút', - }, - - '/fr/': { - word: 'Environ $word mots', - less1Minute: 'Moins de 1 minute', - time: 'Environ $time min', - }, - - '/es/': { - word: 'Alrededor de $word palabras', - less1Minute: 'Menos de 1 minuto', - time: 'Alrededor de $time min', - }, - - '/ja/': { - word: '$word字程度', - less1Minute: '1分以内', - time: '約$time分', - }, - - '/tr/': { - word: 'Yaklaşık $word kelime', - less1Minute: '1 dakikadan az', - time: 'Yaklaşık $time dakika', - }, - - '/ko/': { - word: '약 $word 단어', - less1Minute: '1분 미만', - time: '약 $time 분', - }, - - '/fi/': { - word: 'Noin $word sanaa', - less1Minute: 'Alle minuutti', - time: 'Noin $time minuuttia', - }, - - '/hu/': { - word: 'Körülbelül $word szó', - less1Minute: 'Kevesebb, mint 1 perc', - time: 'Körülbelül $time perc', - }, - - '/id/': { - word: 'Sekitar $word kata', - less1Minute: 'Kurang dari 1 menit', - time: 'Sekitar $time menit', - }, - - '/nl/': { - word: 'Ongeveer $word woorden', - less1Minute: 'Minder dan 1 minuut', - time: 'Ongeveer $time minuten', - }, -} +export const readingTimeLocaleInfo: DefaultLocaleInfo = + [ + [ + ['en', 'en-US'], + { + word: 'About $word words', + less1Minute: 'Less than 1 minute', + time: 'About $time min', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + word: '约 $word 字', + less1Minute: '小于 1 分钟', + time: '大约 $time 分钟', + }, + ], + [ + ['zh', 'zh-TW', 'zh-Hant'], + { + word: '約 $word 字', + less1Minute: '小於 1 分鐘', + time: '大约 $time 分鐘', + }, + ], + [ + ['de', 'de-DE'], + { + word: 'Ungefähr $word Wörter', + less1Minute: 'Weniger als eine Minute', + time: 'Ungefähr $time min', + }, + ], + [ + ['de-AT'], + { + word: 'Um die $word Wörter', + less1Minute: 'Weniger als eine Minute', + time: 'Ungefähr $time min', + }, + ], + [ + ['vi', 'vi-VN'], + { + word: 'Khoảng $word từ', + less1Minute: 'Ít hơn 1 phút', + time: 'Khoảng $time phút', + }, + ], + [ + ['uk'], + { + word: 'Про $word слова', + less1Minute: 'Менше 1 хвилини', + time: 'Приблизно $time хв', + }, + ], + [ + ['ru', 'ru-RU'], + { + word: 'Около $word слов', + less1Minute: 'Меньше 1 минуты', + time: 'Около $time мин', + }, + ], + [ + ['br'], + { + word: 'Por volta de $word palavras', + less1Minute: 'Menos de 1 minuto', + time: 'Por volta de $time min', + }, + ], + [ + ['pl', 'pl-PL'], + { + word: 'Około $word słów', + less1Minute: 'Mniej niż 1 minuta', + time: 'Około $time minut', + }, + ], + [ + ['sk', 'sk-SK'], + { + word: 'Okolo $word slov', + less1Minute: 'Menej ako 1 minúta', + time: 'Okolo $time minút', + }, + ], + [ + ['fr', 'fr-FR'], + { + word: 'Environ $word mots', + less1Minute: 'Moins de 1 minute', + time: 'Environ $time min', + }, + ], + [ + ['es', 'es-ES'], + { + word: 'Alrededor de $word palabras', + less1Minute: 'Menos de 1 minuto', + time: 'Alrededor de $time min', + }, + ], + [ + ['ja', 'ja-JP'], + { word: '$word字程度', less1Minute: '1分以内', time: '約$time分' }, + ], + [ + ['tr', 'tr-TR'], + { + word: 'Yaklaşık $word kelime', + less1Minute: '1 dakikadan az', + time: 'Yaklaşık $time dakika', + }, + ], + [ + ['ko', 'ko-KO'], + { word: '약 $word 단어', less1Minute: '1분 미만', time: '약 $time 분' }, + ], + [ + ['fi', 'fi-FI'], + { + word: 'Noin $word sanaa', + less1Minute: 'Alle minuutti', + time: 'Noin $time minuuttia', + }, + ], + [ + ['hu', 'hu-HU'], + { + word: 'Körülbelül $word szó', + less1Minute: 'Kevesebb, mint 1 perc', + time: 'Körülbelül $time perc', + }, + ], + [ + ['id', 'id-ID'], + { + word: 'Sekitar $word kata', + less1Minute: 'Kurang dari 1 menit', + time: 'Sekitar $time menit', + }, + ], + [ + ['nl', 'nl-NL'], + { + word: 'Ongeveer $word woorden', + less1Minute: 'Minder dan 1 minuut', + time: 'Ongeveer $time minuten', + }, + ], + ] diff --git a/plugins/development/plugin-reading-time/src/node/readingTimePlugin.ts b/plugins/development/plugin-reading-time/src/node/readingTimePlugin.ts index f8910485d6..93509b479a 100644 --- a/plugins/development/plugin-reading-time/src/node/readingTimePlugin.ts +++ b/plugins/development/plugin-reading-time/src/node/readingTimePlugin.ts @@ -1,8 +1,8 @@ -import { addViteSsrNoExternal, getLocaleConfig } from '@vuepress/helper' +import { addViteSsrNoExternal, getFullLocaleConfig } from '@vuepress/helper' import type { Page, PluginFunction } from 'vuepress/core' import type { ReadingTime } from '../shared/index.js' import { getReadingTime } from './getReadingTime.js' -import { readingTimeLocales } from './locales.js' +import { readingTimeLocaleInfo } from './locales.js' import { PLUGIN_NAME, logger } from './logger.js' import type { ReadingTimePluginOptions } from './options.js' @@ -16,10 +16,10 @@ export const readingTimePlugin = name: PLUGIN_NAME, define: (): Record => ({ - __READING_TIME_LOCALES__: getLocaleConfig({ + __READING_TIME_LOCALES__: getFullLocaleConfig({ app, name: PLUGIN_NAME, - default: readingTimeLocales, + default: readingTimeLocaleInfo, config: options.locales, }), }), diff --git a/plugins/features/plugin-back-to-top/src/node/backToTopPlugin.ts b/plugins/features/plugin-back-to-top/src/node/backToTopPlugin.ts index 5f13ebbd77..d41ab859c3 100644 --- a/plugins/features/plugin-back-to-top/src/node/backToTopPlugin.ts +++ b/plugins/features/plugin-back-to-top/src/node/backToTopPlugin.ts @@ -1,7 +1,7 @@ -import { getLocaleConfig } from '@vuepress/helper' +import { getFullLocaleConfig } from '@vuepress/helper' import type { Plugin } from 'vuepress/core' import { getDirname, logger, path } from 'vuepress/utils' -import { backToTopLocales } from './locales.js' +import { backToTopLocaleInfo } from './locales.js' import { PLUGIN_NAME } from './logger.js' import type { BackToTopPluginOptions } from './options.js' @@ -16,10 +16,10 @@ export const backToTopPlugin = name: PLUGIN_NAME, define: () => ({ - __BACK_TO_TOP_LOCALES__: getLocaleConfig({ + __BACK_TO_TOP_LOCALES__: getFullLocaleConfig({ app, name: 'back-to-top', - default: backToTopLocales, + default: backToTopLocaleInfo, config: options.locales, }), __BACK_TO_TOP_PROGRESS__: options.progress ?? true, diff --git a/plugins/features/plugin-back-to-top/src/node/locales.ts b/plugins/features/plugin-back-to-top/src/node/locales.ts index cff5b1605f..40d0f1a0e2 100644 --- a/plugins/features/plugin-back-to-top/src/node/locales.ts +++ b/plugins/features/plugin-back-to-top/src/node/locales.ts @@ -1,82 +1,29 @@ -import type { BackToTopPluginLocaleConfig } from '../shared/index.js' - -export const backToTopLocales: BackToTopPluginLocaleConfig = { - '/en/': { - backToTop: 'Back to top', - }, - - '/zh/': { - backToTop: '返回顶部', - }, - - '/zh-tw/': { - backToTop: '返回頂部', - }, - - '/de/': { - backToTop: 'Zurück nach oben.', - }, - - '/de-at/': { - backToTop: 'Zurück nach oben.', - }, - - '/vi/': { - backToTop: 'Trở lại đầu trang', - }, - - '/uk/': { - backToTop: 'Повернутися до початку', - }, - - '/ru/': { - backToTop: 'Вернуться к началу', - }, - - '/br/': { - backToTop: 'Volta ao topo', - }, - - '/pl/': { - backToTop: 'Wróć na górę', - }, - - '/sk/': { - backToTop: 'Back to top', - }, - - '/fr/': { - backToTop: 'Retour en haut', - }, - - '/es/': { - backToTop: 'Volver arriba', - }, - - '/ja/': { - backToTop: 'このページのトップへ戻る', - }, - - '/tr/': { - backToTop: 'En başa dön', - }, - - '/ko/': { - backToTop: '맨 위로', - }, - - '/fi/': { - backToTop: 'Takaisin ylös', - }, - '/hu/': { - backToTop: 'Vissza a tetejére', - }, - - '/id/': { - backToTop: 'Kembali ke atas', - }, - - '/nl/': { - backToTop: 'Ga terug naar boven', - }, -} +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { BackToTopPluginLocaleData } from '../shared/index.js' + +/** + * Default locale info for `@vuepress/plugin-back-to-top` + */ +export const backToTopLocaleInfo: DefaultLocaleInfo = + [ + [['en', 'en-US'], { backToTop: 'Back to top' }], + [['zh', 'zh-CN', 'zh-Hans'], { backToTop: '返回顶部' }], + [['zh', 'zh-TW', 'zh-Hant'], { backToTop: '返回頂部' }], + [['de', 'de-DE'], { backToTop: 'Zurück nach oben.' }], + [['de-AT'], { backToTop: 'Zurück nach oben.' }], + [['vi', 'vi-VN'], { backToTop: 'Trở lại đầu trang' }], + [['uk'], { backToTop: 'Повернутися до початку' }], + [['ru', 'ru-RU'], { backToTop: 'Вернуться к началу' }], + [['br'], { backToTop: 'Volta ao topo' }], + [['pl', 'pl-PL'], { backToTop: 'Wróć na górę' }], + [['sk', 'sk-SK'], { backToTop: 'Back to top' }], + [['fr', 'fr-FR'], { backToTop: 'Retour en haut' }], + [['es', 'es-ES'], { backToTop: 'Volver arriba' }], + [['ja', 'ja-JP'], { backToTop: 'このページのトップへ戻る' }], + [['tr', 'tr-TR'], { backToTop: 'En başa dön' }], + [['ko', 'ko-KO'], { backToTop: '맨 위로' }], + [['fi', 'fi-FI'], { backToTop: 'Takaisin ylös' }], + [['hu', 'hu-HU'], { backToTop: 'Vissza a tetejére' }], + [['id', 'id-ID'], { backToTop: 'Kembali ke atas' }], + [['nl', 'nl-NL'], { backToTop: 'Ga terug naar boven' }], + ] diff --git a/plugins/features/plugin-catalog/src/node/catalogPlugin.ts b/plugins/features/plugin-catalog/src/node/catalogPlugin.ts index e7129ce6f3..9e4ee20d1c 100644 --- a/plugins/features/plugin-catalog/src/node/catalogPlugin.ts +++ b/plugins/features/plugin-catalog/src/node/catalogPlugin.ts @@ -1,8 +1,8 @@ -import { addViteSsrNoExternal, getLocaleConfig } from '@vuepress/helper' +import { addViteSsrNoExternal, getFullLocaleConfig } from '@vuepress/helper' import type { PluginFunction } from 'vuepress/core' import { getDirname, path } from 'vuepress/utils' import { generateCatalogPage } from './generateCatalogPage.js' -import { catalogLocales as defaultLocales } from './locales.js' +import { catalogLocaleInfo } from './locales.js' import { PLUGIN_NAME, logger } from './logger.js' import type { CatalogPluginOptions } from './options.js' @@ -19,10 +19,10 @@ export const catalogPlugin = name: PLUGIN_NAME, define: (): Record => ({ - __CATALOG_LOCALES__: getLocaleConfig({ + __CATALOG_LOCALES__: getFullLocaleConfig({ app, name: PLUGIN_NAME, - default: defaultLocales, + default: catalogLocaleInfo, config: locales, }), }), diff --git a/plugins/features/plugin-catalog/src/node/locales.ts b/plugins/features/plugin-catalog/src/node/locales.ts index 90fbad9e94..924f24f19b 100644 --- a/plugins/features/plugin-catalog/src/node/locales.ts +++ b/plugins/features/plugin-catalog/src/node/locales.ts @@ -1,103 +1,28 @@ -import type { CatalogPluginLocaleConfig } from '../shared/index.js' - -export const catalogLocales: CatalogPluginLocaleConfig = { - '/en/': { - title: 'Catalog', - empty: 'No catalog', - }, - - '/zh/': { - title: '目录', - empty: '暂无目录', - }, - - '/zh-tw/': { - title: '目錄', - empty: '暫無目錄', - }, - - '/de/': { - title: 'Katalog', - empty: 'Kein Katalog', - }, - - '/de-at/': { - title: 'Katalog', - empty: 'Kein Katalog', - }, - - '/vi/': { - title: 'Danh mục', - empty: 'Không có danh mục', - }, - - '/uk/': { - title: 'Каталог', - empty: 'Немає каталогу', - }, - - '/ru/': { - title: 'Каталог', - empty: 'Нет каталога', - }, - - '/br/': { - title: 'Catálogo', - empty: 'Sem catálogo', - }, - - '/pl/': { - title: 'Katalog', - empty: 'Brak katalogu', - }, - - '/sk/': { - title: 'Katalóg', - empty: 'Žiadny katalóg', - }, - - '/fr/': { - title: 'Catalogue', - empty: 'Pas de catalogue', - }, - - '/es/': { - title: 'Catálogo', - empty: 'Sin catálogo', - }, - - '/ja/': { - title: 'カタログ', - empty: 'カタログなし', - }, - - '/tr/': { - title: 'Katalog', - empty: 'Katalog yok', - }, - - '/ko/': { - title: '목차', - empty: '목차 없음', - }, - - '/fi/': { - title: 'Luettelo', - empty: 'Ei luetteloa', - }, - - '/hu/': { - title: 'Katalógus', - empty: 'Nincs katalógus', - }, - - '/id/': { - title: 'Katalog', - empty: 'Tidak ada katalog', - }, - - '/nl/': { - title: 'Catalogus', - empty: 'Geen catalogus', - }, -} +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { CatalogPluginLocaleData } from '../shared/index.js' + +/** + * Default locale info for `@vuepress/plugin-catalog` + */ +export const catalogLocaleInfo: DefaultLocaleInfo = [ + [['en', 'en-US'], { title: 'Catalog', empty: 'No catalog' }], + [['zh', 'zh-CN', 'zh-Hans'], { title: '目录', empty: '暂无目录' }], + [['zh', 'zh-TW', 'zh-Hant'], { title: '目錄', empty: '暫無目錄' }], + [['de', 'de-DE'], { title: 'Katalog', empty: 'Kein Katalog' }], + [['de-AT'], { title: 'Katalog', empty: 'Kein Katalog' }], + [['vi', 'vi-VN'], { title: 'Danh mục', empty: 'Không có danh mục' }], + [['uk'], { title: 'Каталог', empty: 'Немає каталогу' }], + [['ru', 'ru-RU'], { title: 'Каталог', empty: 'Нет каталога' }], + [['br'], { title: 'Catálogo', empty: 'Sem catálogo' }], + [['pl', 'pl-PL'], { title: 'Katalog', empty: 'Brak katalogu' }], + [['sk', 'sk-SK'], { title: 'Katalóg', empty: 'Žiadny katalóg' }], + [['fr', 'fr-FR'], { title: 'Catalogue', empty: 'Pas de catalogue' }], + [['es', 'es-ES'], { title: 'Catálogo', empty: 'Sin catálogo' }], + [['ja', 'ja-JP'], { title: 'カタログ', empty: 'カタログなし' }], + [['tr', 'tr-TR'], { title: 'Katalog', empty: 'Katalog yok' }], + [['ko', 'ko-KO'], { title: '목차', empty: '목차 없음' }], + [['fi', 'fi-FI'], { title: 'Luettelo', empty: 'Ei luetteloa' }], + [['hu', 'hu-HU'], { title: 'Katalógus', empty: 'Nincs katalógus' }], + [['id', 'id-ID'], { title: 'Katalog', empty: 'Tidak ada katalog' }], + [['nl', 'nl-NL'], { title: 'Catalogus', empty: 'Geen catalogus' }], +] diff --git a/plugins/features/plugin-copy-code/src/node/copyCodePlugin.ts b/plugins/features/plugin-copy-code/src/node/copyCodePlugin.ts index 066153fb75..66051f4a12 100644 --- a/plugins/features/plugin-copy-code/src/node/copyCodePlugin.ts +++ b/plugins/features/plugin-copy-code/src/node/copyCodePlugin.ts @@ -1,12 +1,12 @@ import { addViteSsrNoExternal, - getLocaleConfig, + getFullLocaleConfig, isArray, isString, } from '@vuepress/helper' import type { PluginFunction } from 'vuepress/core' import { getDirname, path } from 'vuepress/utils' -import { copyCodeLocales } from './locales.js' +import { copyCodeLocaleInfo } from './locales.js' import { PLUGIN_NAME, logger } from './logger.js' import type { CopyCodePluginOptions } from './options.js' @@ -24,10 +24,10 @@ export const copyCodePlugin = __CC_DELAY__: options.delay ?? 500, __CC_DURATION__: options.duration ?? 2000, __CC_IGNORE_SELECTOR__: options.ignoreSelector ?? [], - __CC_LOCALES__: getLocaleConfig({ + __CC_LOCALES__: getFullLocaleConfig({ app, name: PLUGIN_NAME, - default: copyCodeLocales, + default: copyCodeLocaleInfo, config: options.locales, }), __CC_SELECTOR__: isArray(options.selector) diff --git a/plugins/features/plugin-copy-code/src/node/locales.ts b/plugins/features/plugin-copy-code/src/node/locales.ts index 574d50c1d4..1ee6486aea 100644 --- a/plugins/features/plugin-copy-code/src/node/locales.ts +++ b/plugins/features/plugin-copy-code/src/node/locales.ts @@ -1,104 +1,28 @@ -import type { CopyCodePluginLocaleConfig } from '../shared/index.js' - -/** Multi language config for copy code */ -export const copyCodeLocales: CopyCodePluginLocaleConfig = { - '/en/': { - copy: 'Copy code', - copied: 'Copied', - }, - - '/zh/': { - copy: '复制代码', - copied: '已复制', - }, - - '/zh-tw/': { - copy: '複製代碼', - copied: '已複製', - }, - - '/de/': { - copy: 'Kopiere den Code.', - copied: 'Kopiert', - }, - - '/de-at/': { - copy: 'Kopiere den Code.', - copied: 'Kopierter', - }, - - '/vi/': { - copy: 'Sao chép code', - copied: 'Đã sao chép', - }, - - '/uk/': { - copy: 'Скопіюйте код', - copied: 'Скопійовано', - }, - - '/ru/': { - copy: 'Скопировать код', - copied: 'Скопировано', - }, - - '/br/': { - copy: 'Copiar o código', - copied: 'Código', - }, - - '/pl/': { - copy: 'Skopiuj kod', - copied: 'Skopiowane', - }, - - '/sk/': { - copy: 'Skopíruj kód', - copied: 'Skopírované', - }, - - '/fr/': { - copy: 'Copier le code', - copied: 'Copié', - }, - - '/es/': { - copy: 'Copiar código', - copied: 'Copiado', - }, - - '/ja/': { - copy: 'コードをコピー', - copied: 'コピーしました', - }, - - '/tr/': { - copy: 'Kodu kopyala', - copied: 'Kopyalandı', - }, - - '/ko/': { - copy: '코드 복사', - copied: '복사됨', - }, - - '/fi/': { - copy: 'Kopioi koodi', - copied: 'Kopioitu', - }, - - '/hu/': { - copy: 'Kód másolása', - copied: 'Másolva', - }, - - '/id/': { - copy: 'Salin kode', - copied: 'Disalin', - }, - - '/nl/': { - copy: 'Kopieer code', - copied: 'Gekopieerd', - }, -} +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { CopyCodePluginLocaleData } from '../shared/index.js' + +/** + * Default locale info for `@vuepress/plugin-copy-code` + */ +export const copyCodeLocaleInfo: DefaultLocaleInfo = [ + [['en', 'en-US'], { copy: 'Copy code', copied: 'Copied' }], + [['zh', 'zh-CN', 'zh-Hans'], { copy: '复制代码', copied: '已复制' }], + [['zh', 'zh-TW', 'zh-Hant'], { copy: '複製代碼', copied: '已複製' }], + [['de', 'de-DE'], { copy: 'Kopiere den Code.', copied: 'Kopiert' }], + [['de-AT'], { copy: 'Kopiere den Code.', copied: 'Kopierter' }], + [['vi', 'vi-VN'], { copy: 'Sao chép code', copied: 'Đã sao chép' }], + [['uk'], { copy: 'Скопіюйте код', copied: 'Скопійовано' }], + [['ru', 'ru-RU'], { copy: 'Скопировать код', copied: 'Скопировано' }], + [['br'], { copy: 'Copiar o código', copied: 'Código' }], + [['pl', 'pl-PL'], { copy: 'Skopiuj kod', copied: 'Skopiowane' }], + [['sk', 'sk-SK'], { copy: 'Skopíruj kód', copied: 'Skopírované' }], + [['fr', 'fr-FR'], { copy: 'Copier le code', copied: 'Copié' }], + [['es', 'es-ES'], { copy: 'Copiar código', copied: 'Copiado' }], + [['ja', 'ja-JP'], { copy: 'コードをコピー', copied: 'コピーしました' }], + [['tr', 'tr-TR'], { copy: 'Kodu kopyala', copied: 'Kopyalandı' }], + [['ko', 'ko-KO'], { copy: '코드 복사', copied: '복사됨' }], + [['fi', 'fi-FI'], { copy: 'Kopioi koodi', copied: 'Kopioitu' }], + [['hu', 'hu-HU'], { copy: 'Kód másolása', copied: 'Másolva' }], + [['id', 'id-ID'], { copy: 'Salin kode', copied: 'Disalin' }], + [['nl', 'nl-NL'], { copy: 'Kopieer code', copied: 'Gekopieerd' }], +] diff --git a/plugins/features/plugin-copyright/src/node/copyrightPlugin.ts b/plugins/features/plugin-copyright/src/node/copyrightPlugin.ts index 840fd26ba7..eb0e90ba09 100644 --- a/plugins/features/plugin-copyright/src/node/copyrightPlugin.ts +++ b/plugins/features/plugin-copyright/src/node/copyrightPlugin.ts @@ -1,11 +1,15 @@ -import { Logger, addViteSsrNoExternal, getLocaleConfig } from '@vuepress/helper' +import { + Logger, + addViteSsrNoExternal, + getFullLocaleConfig, +} from '@vuepress/helper' import type { Page, PluginFunction } from 'vuepress/core' import { getDirname, path } from 'vuepress/utils' import type { CopyrightInfoData, CopyrightPluginPageData, } from '../shared/index.js' -import { copyrightLocales } from './locales.js' +import { copyrightLocaleInfo } from './locales.js' import type { CopyrightPluginOptions } from './options.js' const PLUGIN_NAME = '@vuepress/plugin-copyright' @@ -33,10 +37,10 @@ export const copyrightPlugin = maxLength = 0, } = options - const locales = getLocaleConfig({ + const locales = getFullLocaleConfig({ app, name: PLUGIN_NAME, - default: copyrightLocales, + default: copyrightLocaleInfo, config: options.locales, }) diff --git a/plugins/features/plugin-copyright/src/node/locales.ts b/plugins/features/plugin-copyright/src/node/locales.ts index 7c53ab5429..c50d004377 100644 --- a/plugins/features/plugin-copyright/src/node/locales.ts +++ b/plugins/features/plugin-copyright/src/node/locales.ts @@ -1,106 +1,145 @@ -import type { CopyrightPluginLocaleConfig } from '../shared/index.js' - -/** Multi language config for copyright */ -export const copyrightLocales: CopyrightPluginLocaleConfig = { - '/en/': { - author: 'Copyright by :author', - license: 'License under :license', - link: ':link', - }, - - '/zh/': { - author: '著作权归:author所有', - license: '基于:license协议', - link: '原文链接::link', - }, - - '/zh-tw/': { - author: '著作權歸:author所有', - license: '基於:license協議', - link: '原文鏈接::link', - }, - - '/ru/': { - author: 'Авторские права :author', - license: 'Лицензия :license', - link: ':link', - }, - - '/pl/': { - author: 'Prawa autorskie :author', - license: 'Licencja :license', - link: ':link', - }, - - '/sk/': { - author: 'Autorské práva :author', - license: 'Licencia :license', - link: ':link', - }, - - '/fr/': { - author: 'Copyright par :author', - license: 'Sous licence :license', - link: ':link', - }, - - '/es/': { - author: 'Derechos de autor :author', - license: 'Licencia :license', - link: ':link', - }, - - '/ja/': { - author: '著作権者 :author', - license: ':licenseプロトコルに基づく', - link: ':link', - }, - - '/tr/': { - author: 'Telif hakkı sahibi :author', - license: 'Lisans :license', - link: ':link', - }, - - '/ko/': { - author: '저작권자 :author', - license: ':license 프로토콜에 따라', - link: ':link', - }, - - '/fi/': { - author: 'Tekijänoikeus :author', - license: 'Lisenssi :license', - link: ':link', - }, - - '/de/': { - author: 'Copyright by :author', - license: 'Lizenziert unter :license', - link: ':link', - }, - - '/de-AT/': { - author: 'Copyright by :author', - license: 'Lizenziert unter :license', - link: ':link', - }, - - '/hu/': { - author: 'Szerzői jog :author', - license: 'Licensz: :license', - link: ':link', - }, - - '/id/': { - author: 'Hak cipta oleh :author', - license: 'Dibawah Lisensi :license', - link: ':link', - }, - - '/nl/': { - author: 'Auteursrecht van :author', - license: 'Licentie onder :license', - link: ':link', - }, -} +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { CopyrightPluginLocaleData } from '../shared/index.js' + +/** + * Default locale info for `@vuepress/plugin-copyright` + */ +export const copyrightLocaleInfo: DefaultLocaleInfo = + [ + [ + ['en', 'en-US'], + { + author: 'Copyright by :author', + license: 'License under :license', + link: ':link', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + author: '著作权归:author所有', + license: '基于:license协议', + link: '原文链接::link', + }, + ], + [ + ['zh', 'zh-TW', 'zh-Hant'], + { + author: '著作權歸:author所有', + license: '基於:license協議', + link: '原文鏈接::link', + }, + ], + [ + ['ru', 'ru-RU'], + { + author: 'Авторские права :author', + license: 'Лицензия :license', + link: ':link', + }, + ], + [ + ['pl', 'pl-PL'], + { + author: 'Prawa autorskie :author', + license: 'Licencja :license', + link: ':link', + }, + ], + [ + ['sk', 'sk-SK'], + { + author: 'Autorské práva :author', + license: 'Licencia :license', + link: ':link', + }, + ], + [ + ['fr', 'fr-FR'], + { + author: 'Copyright par :author', + license: 'Sous licence :license', + link: ':link', + }, + ], + [ + ['es', 'es-ES'], + { + author: 'Derechos de autor :author', + license: 'Licencia :license', + link: ':link', + }, + ], + [ + ['ja', 'ja-JP'], + { + author: '著作権者 :author', + license: ':licenseプロトコルに基づく', + link: ':link', + }, + ], + [ + ['tr', 'tr-TR'], + { + author: 'Telif hakkı sahibi :author', + license: 'Lisans :license', + link: ':link', + }, + ], + [ + ['ko', 'ko-KO'], + { + author: '저작권자 :author', + license: ':license 프로토콜에 따라', + link: ':link', + }, + ], + [ + ['fi', 'fi-FI'], + { + author: 'Tekijänoikeus :author', + license: 'Lisenssi :license', + link: ':link', + }, + ], + [ + ['de', 'de-DE'], + { + author: 'Copyright by :author', + license: 'Lizenziert unter :license', + link: ':link', + }, + ], + [ + ['de-AT'], + { + author: 'Copyright by :author', + license: 'Lizenziert unter :license', + link: ':link', + }, + ], + [ + ['hu', 'hu-HU'], + { + author: 'Szerzői jog :author', + license: 'Licensz: :license', + link: ':link', + }, + ], + [ + ['id', 'id-ID'], + { + author: 'Hak cipta oleh :author', + license: 'Dibawah Lisensi :license', + link: ':link', + }, + ], + [ + ['nl', 'nl-NL'], + { + author: 'Auteursrecht van :author', + license: 'Licentie onder :license', + link: ':link', + }, + ], + ] diff --git a/plugins/features/plugin-photo-swipe/src/node/locales.ts b/plugins/features/plugin-photo-swipe/src/node/locales.ts index db1db49d77..7f47e6d9df 100644 --- a/plugins/features/plugin-photo-swipe/src/node/locales.ts +++ b/plugins/features/plugin-photo-swipe/src/node/locales.ts @@ -1,183 +1,229 @@ -import type { PhotoSwipePluginLocaleConfig } from '../shared/index.js' - -export const photoSwipeLocales: PhotoSwipePluginLocaleConfig = { - '/en/': { - close: 'Close', - download: 'Download Image', - fullscreen: 'Switch to fullscreen', - zoom: 'Zoom in/out', - arrowPrev: 'Prev (Arrow Left)', - arrowNext: 'Next (Arrow Right)', - }, - - '/zh/': { - close: '关闭', - download: '下载图片', - fullscreen: '切换全屏', - zoom: '缩放', - arrowPrev: '上一个 (左箭头)', - arrowNext: '下一个 (右箭头)', - }, - - '/zh-tw/': { - close: '關閉', - download: '下載圖片', - fullscreen: '切換全屏', - zoom: '縮放', - arrowPrev: '上一個 (左箭頭)', - arrowNext: '下一個 (右箭頭)', - }, - - '/de/': { - close: 'Schließen', - download: 'Download', - fullscreen: 'Vollbild aktivieren', - zoom: 'Rein / rauszoomen', - arrowPrev: 'Zurück (Pfeil links)', - arrowNext: 'Weiter (Pfeil rechts)', - }, - - '/de-at/': { - close: 'Schließen', - download: 'Download', - fullscreen: 'Toggle fullscreen', - zoom: 'Rein / rauszoomen', - arrowPrev: 'Zurück (Pfeil links)', - arrowNext: 'Weiter (Pfeil rechts)', - }, - - '/vi/': { - close: 'Đóng', - download: 'download', - fullscreen: 'Bật chế độ toàn màn hình', - zoom: 'Phóng to / thu nhỏ', - arrowPrev: 'Trước (Mũi tên trái)', - arrowNext: 'Tiếp theo (Mũi tên Phải)', - }, - - '/uk/': { - close: 'Закрити', - download: 'Завантажити зображення', - fullscreen: 'Перейти на повний екран', - zoom: 'Збільшити/Зменшити', - arrowPrev: 'Попередня (Стрілка вліво)', - arrowNext: 'Далі (стрілка вправо)', - }, - - '/ru/': { - close: 'Закрыть', - download: 'Загрузить изображение', - fullscreen: 'Переключиться на полный экран', - zoom: 'Увеличить/Уменьшить', - arrowPrev: 'Предыдущая (Стрелка влево)', - arrowNext: 'Следующая (Стрелка вправо)', - }, - - '/br/': { - close: 'Fechar', - download: 'Baixar imagem', - fullscreen: 'Alternar para tela cheia', - zoom: 'Aproximar mais/menos', - arrowPrev: 'Anterior (Seta Esquerda)', - arrowNext: 'Próximo (Seta Direita)', - }, - - '/pl/': { - close: 'Zamknij', - download: 'Pobierz obraz', - fullscreen: 'Przełącz na pełny ekran', - zoom: 'Powiększ/pomniejsz', - arrowPrev: 'Poprzedni (strzałka w lewo)', - arrowNext: 'Następny (strzałka w prawo)', - }, - - '/sk/': { - close: 'Zatvor', - download: 'Stiahni obrázok', - fullscreen: 'Prepni na celú obrazovku', - zoom: 'Priblíž/Oddial', - arrowPrev: 'Predošlí (šípka doľava)', - arrowNext: 'Nasledujúci (šípka doprava)', - }, - - '/fr/': { - close: 'Fermer', - download: "Télécharger l'image", - fullscreen: 'Basculer en plein écran', - zoom: 'Zoom avant/arrière', - arrowPrev: 'Précédent (Flèche gauche)', - arrowNext: 'Suivant (Flèche droite)', - }, - - '/es/': { - close: 'Cerrar', - download: 'Descargar imagen', - fullscreen: 'Cambiar a pantalla completa', - zoom: 'Acercar/Alejar', - arrowPrev: 'Anterior (Flecha izquierda)', - arrowNext: 'Siguiente (Flecha derecha)', - }, - - '/ja/': { - close: '閉じる', - download: '画像ダウンロード', - fullscreen: '全画面表示への切り替え', - zoom: '拡大・縮小', - arrowPrev: '前へ(左矢印)', - arrowNext: '次へ(右矢印)', - }, - - '/tr/': { - close: 'Kapat', - download: 'Resmi indir', - fullscreen: 'Tam ekrana geç', - zoom: 'Yakınlaştır/Uzaklaştır', - arrowPrev: 'Önceki (Sol ok)', - arrowNext: 'Sonraki (Sağ ok)', - }, - - '/ko/': { - close: '닫기', - download: '이미지 다운로드', - fullscreen: '전체 화면 전환', - zoom: '확대/축소', - arrowPrev: '이전 (왼쪽 화살표)', - arrowNext: '다음 (오른쪽 화살표)', - }, - - '/fi/': { - close: 'Sulje', - download: 'Lataa kuva', - fullscreen: 'Vaihda kokoruututilaan', - zoom: 'Lähennä/Työnnä', - arrowPrev: 'Edellinen (Vasen nuoli)', - arrowNext: 'Seuraava (Oikea nuoli)', - }, - - '/hu/': { - close: 'Bezárás', - download: 'Kép letöltése', - fullscreen: 'Váltás teljes képernyőre', - zoom: 'Nagyítás/kicsinyítés', - arrowPrev: 'Előző (Balra nyíl)', - arrowNext: 'Következő (Jobbra nyíl)', - }, - - '/id/': { - close: 'Tutup', - download: 'Unduh gambar', - fullscreen: 'Beralih ke layar penuh', - zoom: 'Perbesar/Perkecil', - arrowPrev: 'Sebelumnya (Panah kiri)', - arrowNext: 'Selanjutnya (Panah kanan)', - }, - - '/nl/': { - close: 'Sluiten', - download: 'Download Image', - fullscreen: 'Verander naar fullscreen', - zoom: 'Zoom in/out', - arrowPrev: 'Vorige (Pijl Links)', - arrowNext: 'Volgende (Pijl Rechts)', - }, -} +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { PhotoSwipePluginLocaleData } from '../shared/index.js' + +/** + * Default locale info for `@vuepress/plugin-photo-swipe` + */ +export const photoSwipeLocaleInfo: DefaultLocaleInfo = + [ + [ + ['en', 'en-US'], + { + close: 'Close', + download: 'Download Image', + fullscreen: 'Switch to fullscreen', + zoom: 'Zoom in/out', + arrowPrev: 'Prev (Arrow Left)', + arrowNext: 'Next (Arrow Right)', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + close: '关闭', + download: '下载图片', + fullscreen: '切换全屏', + zoom: '缩放', + arrowPrev: '上一个 (左箭头)', + arrowNext: '下一个 (右箭头)', + }, + ], + [ + ['zh', 'zh-TW', 'zh-Hant'], + { + close: '關閉', + download: '下載圖片', + fullscreen: '切換全屏', + zoom: '縮放', + arrowPrev: '上一個 (左箭頭)', + arrowNext: '下一個 (右箭頭)', + }, + ], + [ + ['de', 'de-DE'], + { + close: 'Schließen', + download: 'Download', + fullscreen: 'Vollbild aktivieren', + zoom: 'Rein / rauszoomen', + arrowPrev: 'Zurück (Pfeil links)', + arrowNext: 'Weiter (Pfeil rechts)', + }, + ], + [ + ['de-AT'], + { + close: 'Schließen', + download: 'Download', + fullscreen: 'Toggle fullscreen', + zoom: 'Rein / rauszoomen', + arrowPrev: 'Zurück (Pfeil links)', + arrowNext: 'Weiter (Pfeil rechts)', + }, + ], + [ + ['vi', 'vi-VN'], + { + close: 'Đóng', + download: 'download', + fullscreen: 'Bật chế độ toàn màn hình', + zoom: 'Phóng to / thu nhỏ', + arrowPrev: 'Trước (Mũi tên trái)', + arrowNext: 'Tiếp theo (Mũi tên Phải)', + }, + ], + [ + ['uk'], + { + close: 'Закрити', + download: 'Завантажити зображення', + fullscreen: 'Перейти на повний екран', + zoom: 'Збільшити/Зменшити', + arrowPrev: 'Попередня (Стрілка вліво)', + arrowNext: 'Далі (стрілка вправо)', + }, + ], + [ + ['ru', 'ru-RU'], + { + close: 'Закрыть', + download: 'Загрузить изображение', + fullscreen: 'Переключиться на полный экран', + zoom: 'Увеличить/Уменьшить', + arrowPrev: 'Предыдущая (Стрелка влево)', + arrowNext: 'Следующая (Стрелка вправо)', + }, + ], + [ + ['br'], + { + close: 'Fechar', + download: 'Baixar imagem', + fullscreen: 'Alternar para tela cheia', + zoom: 'Aproximar mais/menos', + arrowPrev: 'Anterior (Seta Esquerda)', + arrowNext: 'Próximo (Seta Direita)', + }, + ], + [ + ['pl', 'pl-PL'], + { + close: 'Zamknij', + download: 'Pobierz obraz', + fullscreen: 'Przełącz na pełny ekran', + zoom: 'Powiększ/pomniejsz', + arrowPrev: 'Poprzedni (strzałka w lewo)', + arrowNext: 'Następny (strzałka w prawo)', + }, + ], + [ + ['sk', 'sk-SK'], + { + close: 'Zatvor', + download: 'Stiahni obrázok', + fullscreen: 'Prepni na celú obrazovku', + zoom: 'Priblíž/Oddial', + arrowPrev: 'Predošlí (šípka doľava)', + arrowNext: 'Nasledujúci (šípka doprava)', + }, + ], + [ + ['fr', 'fr-FR'], + { + close: 'Fermer', + download: "Télécharger l'image", + fullscreen: 'Basculer en plein écran', + zoom: 'Zoom avant/arrière', + arrowPrev: 'Précédent (Flèche gauche)', + arrowNext: 'Suivant (Flèche droite)', + }, + ], + [ + ['es', 'es-ES'], + { + close: 'Cerrar', + download: 'Descargar imagen', + fullscreen: 'Cambiar a pantalla completa', + zoom: 'Acercar/Alejar', + arrowPrev: 'Anterior (Flecha izquierda)', + arrowNext: 'Siguiente (Flecha derecha)', + }, + ], + [ + ['ja', 'ja-JP'], + { + close: '閉じる', + download: '画像ダウンロード', + fullscreen: '全画面表示への切り替え', + zoom: '拡大・縮小', + arrowPrev: '前へ(左矢印)', + arrowNext: '次へ(右矢印)', + }, + ], + [ + ['tr', 'tr-TR'], + { + close: 'Kapat', + download: 'Resmi indir', + fullscreen: 'Tam ekrana geç', + zoom: 'Yakınlaştır/Uzaklaştır', + arrowPrev: 'Önceki (Sol ok)', + arrowNext: 'Sonraki (Sağ ok)', + }, + ], + [ + ['ko', 'ko-KO'], + { + close: '닫기', + download: '이미지 다운로드', + fullscreen: '전체 화면 전환', + zoom: '확대/축소', + arrowPrev: '이전 (왼쪽 화살표)', + arrowNext: '다음 (오른쪽 화살표)', + }, + ], + [ + ['fi', 'fi-FI'], + { + close: 'Sulje', + download: 'Lataa kuva', + fullscreen: 'Vaihda kokoruututilaan', + zoom: 'Lähennä/Työnnä', + arrowPrev: 'Edellinen (Vasen nuoli)', + arrowNext: 'Seuraava (Oikea nuoli)', + }, + ], + [ + ['hu', 'hu-HU'], + { + close: 'Bezárás', + download: 'Kép letöltése', + fullscreen: 'Váltás teljes képernyőre', + zoom: 'Nagyítás/kicsinyítés', + arrowPrev: 'Előző (Balra nyíl)', + arrowNext: 'Következő (Jobbra nyíl)', + }, + ], + [ + ['id', 'id-ID'], + { + close: 'Tutup', + download: 'Unduh gambar', + fullscreen: 'Beralih ke layar penuh', + zoom: 'Perbesar/Perkecil', + arrowPrev: 'Sebelumnya (Panah kiri)', + arrowNext: 'Selanjutnya (Panah kanan)', + }, + ], + [ + ['nl', 'nl-NL'], + { + close: 'Sluiten', + download: 'Download afbeelding', + fullscreen: 'Schakel naar volledig scherm', + zoom: 'In-/uitzoomen', + arrowPrev: 'Vorige (Pijl Links)', + arrowNext: 'Volgende (Pijl Rechts)', + }, + ], + ] diff --git a/plugins/features/plugin-photo-swipe/src/node/photoSwipePlugin.ts b/plugins/features/plugin-photo-swipe/src/node/photoSwipePlugin.ts index dcf7a862c1..2c56c3faea 100644 --- a/plugins/features/plugin-photo-swipe/src/node/photoSwipePlugin.ts +++ b/plugins/features/plugin-photo-swipe/src/node/photoSwipePlugin.ts @@ -3,11 +3,11 @@ import { addViteSsrNoExternal, entries, fromEntries, - getLocaleConfig, + getFullLocaleConfig, } from '@vuepress/helper' import type { PluginFunction } from 'vuepress/core' import { getDirname, path } from 'vuepress/utils' -import { photoSwipeLocales } from './locales.js' +import { photoSwipeLocaleInfo } from './locales.js' import { PLUGIN_NAME, logger } from './logger.js' import type { PhotoSwipePluginOptions } from './options.js' @@ -29,10 +29,10 @@ export const photoSwipePlugin = __PS_SCROLL_TO_CLOSE__: options.scrollToClose ?? true, __PS_LOCALES__: fromEntries( entries( - getLocaleConfig({ + getFullLocaleConfig({ app, name: PLUGIN_NAME, - default: photoSwipeLocales, + default: photoSwipeLocaleInfo, config: options.locales, }), ).map(([localePath, localeOptions]) => [ diff --git a/plugins/markdown/plugin-markdown-hint/src/node/locales.ts b/plugins/markdown/plugin-markdown-hint/src/node/locales.ts index 1671a02b55..21136c218d 100644 --- a/plugins/markdown/plugin-markdown-hint/src/node/locales.ts +++ b/plugins/markdown/plugin-markdown-hint/src/node/locales.ts @@ -1,203 +1,245 @@ -import type { MarkdownHintPluginLocaleConfig } from './options.js' - -export const markdownHintPluginLocales: MarkdownHintPluginLocaleConfig = { - '/en/': { - important: 'Important', - info: 'Info', - note: 'Note', - tip: 'Tips', - warning: 'Warning', - caution: 'Caution', - details: 'Details', - }, - - '/zh/': { - important: '重要', - info: '相关信息', - note: '注', - tip: '提示', - warning: '注意', - caution: '警告', - details: '详情', - }, - - '/zh-tw/': { - important: '重要', - info: '相關信息', - note: '注', - tip: '提示', - warning: '注意', - caution: '警告', - details: '詳情', - }, - - '/de/': { - important: 'Wichtig', - info: 'Information', - note: 'Notiz', - tip: 'Tips', - warning: 'Warnung', - caution: 'Gefahr', - details: 'Details', - }, - - '/de-at/': { - important: 'Wichtig', - info: 'Information', - note: 'Note', - tip: 'Tips', - warning: 'Notiz', - caution: 'Warnung', - details: 'Details', - }, - - '/vi/': { - important: 'Quan trọng', - info: 'Thông tin', - note: 'Note', - tip: 'Tips', - warning: 'Lưu ý', - caution: 'Cẩn thận', - details: 'Chi tiết', - }, - - '/uk/': { - important: 'Важливо', - info: 'Інформація', - note: 'Note', - tip: 'Поради', - warning: 'Примітка', - caution: 'Увага', - details: 'Деталь', - }, - - '/ru/': { - important: 'Важно', - info: 'Инфо', - note: 'Заметка', - tip: 'Совет', - warning: 'Примечание', - caution: 'Предупреждение', - details: 'Подробности', - }, - - '/br/': { - important: 'Importante', - info: 'Informativo', - note: 'Note', - tip: 'Dicas', - warning: 'Avisos', - caution: 'Cuidado', - details: 'Detalhe', - }, - - '/pl/': { - important: 'Ważne', - info: 'Info', - note: 'Notatka', - tip: 'Porady', - warning: 'Notatka', - caution: 'Ostrzeżenie', - details: 'Dane', - }, - - '/sk/': { - important: 'Dôležité', - info: 'Info', - note: 'Poznámka', - tip: 'Tip', - warning: 'Upozornenie', - caution: 'Pozor', - details: 'Podrobnosti', - }, - - '/fr/': { - important: 'Important', - info: 'Info', - note: 'Note', - tip: 'Conseil', - warning: 'Note', - caution: 'Avertissement', - details: 'Details', - }, - - '/es/': { - important: 'Importante', - info: 'Información', - note: 'Nota', - tip: 'Consejos', - warning: 'Aviso', - caution: 'Advertencia', - details: 'Detalles', - }, - - '/ja/': { - important: '重要', - info: '関連情報', - note: '注', - tip: 'ヒント', - warning: '注意', - caution: '警告', - details: '詳細', - }, - - '/tr/': { - important: 'Önemli', - info: 'Bilgi', - note: 'Not', - tip: 'Tavsiye', - warning: 'Uyarı', - caution: 'Tehlike', - details: 'Detay', - }, - - '/ko/': { - important: '중요', - info: '정보', - note: '노트', - tip: '팁', - warning: '경고', - caution: '위험', - details: '세부사항', - }, - - '/fi/': { - important: 'Tärkeä', - info: 'Tietoa', - note: 'Huomautus', - tip: 'Vinkki', - warning: 'Varoitus', - caution: 'Vaara', - details: 'Yksityiskohdat', - }, - - '/hu/': { - important: 'Fontos', - info: 'Információ', - note: 'Megjegyzés', - tip: 'Tipp', - warning: 'Figyelem', - caution: 'Veszély', - details: 'Részletek', - }, - - '/id/': { - important: 'Penting', - info: 'Pemberitahuan', - note: 'Catatan', - tip: 'Tips', - warning: 'Penting', - caution: 'Peringatan', - details: 'Rincian', - }, - - '/nl/': { - important: 'Belangrijk', - info: 'Info', - note: 'Notitie', - tip: 'Tips', - warning: 'Notitie', - caution: 'Waarschuwing', - details: 'Details', - }, -} +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { MarkdownHintPluginLocaleData } from './options.js' + +export const hintLocaleInfo: DefaultLocaleInfo = [ + [ + ['en', 'en-US'], + { + important: 'Important', + info: 'Info', + note: 'Note', + tip: 'Tips', + warning: 'Warning', + caution: 'Caution', + details: 'Details', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + important: '重要', + info: '相关信息', + note: '注', + tip: '提示', + warning: '注意', + caution: '警告', + details: '详情', + }, + ], + [ + ['zh', 'zh-TW', 'zh-Hant'], + { + important: '重要', + info: '相關信息', + note: '注', + tip: '提示', + warning: '注意', + caution: '警告', + details: '詳情', + }, + ], + [ + ['de', 'de-DE'], + { + important: 'Wichtig', + info: 'Information', + note: 'Notiz', + tip: 'Tips', + warning: 'Warnung', + caution: 'Gefahr', + details: 'Details', + }, + ], + [ + ['de-AT'], + { + important: 'Wichtig', + info: 'Information', + note: 'Note', + tip: 'Tips', + warning: 'Notiz', + caution: 'Warnung', + details: 'Details', + }, + ], + [ + ['vi', 'vi-VN'], + { + important: 'Quan trọng', + info: 'Thông tin', + note: 'Note', + tip: 'Tips', + warning: 'Lưu ý', + caution: 'Cẩn thận', + details: 'Chi tiết', + }, + ], + [ + ['uk'], + { + important: 'Важливо', + info: 'Інформація', + note: 'Note', + tip: 'Поради', + warning: 'Примітка', + caution: 'Увага', + details: 'Деталь', + }, + ], + [ + ['ru', 'ru-RU'], + { + important: 'Важно', + info: 'Инфо', + note: 'Заметка', + tip: 'Совет', + warning: 'Примечание', + caution: 'Предупреждение', + details: 'Подробности', + }, + ], + [ + ['br'], + { + important: 'Importante', + info: 'Informativo', + note: 'Note', + tip: 'Dicas', + warning: 'Avisos', + caution: 'Cuidado', + details: 'Detalhe', + }, + ], + [ + ['pl', 'pl-PL'], + { + important: 'Ważne', + info: 'Info', + note: 'Notatka', + tip: 'Porady', + warning: 'Notatka', + caution: 'Ostrzeżenie', + details: 'Dane', + }, + ], + [ + ['sk', 'sk-SK'], + { + important: 'Dôležité', + info: 'Info', + note: 'Poznámka', + tip: 'Tip', + warning: 'Upozornenie', + caution: 'Pozor', + details: 'Podrobnosti', + }, + ], + [ + ['fr', 'fr-FR'], + { + important: 'Important', + info: 'Info', + note: 'Note', + tip: 'Conseil', + warning: 'Note', + caution: 'Avertissement', + details: 'Details', + }, + ], + [ + ['es', 'es-ES'], + { + important: 'Importante', + info: 'Información', + note: 'Nota', + tip: 'Consejos', + warning: 'Aviso', + caution: 'Advertencia', + details: 'Detalles', + }, + ], + [ + ['ja', 'ja-JP'], + { + important: '重要', + info: '関連情報', + note: '注', + tip: 'ヒント', + warning: '注意', + caution: '警告', + details: '詳細', + }, + ], + [ + ['tr', 'tr-TR'], + { + important: 'Önemli', + info: 'Bilgi', + note: 'Not', + tip: 'Tavsiye', + warning: 'Uyarı', + caution: 'Tehlike', + details: 'Detay', + }, + ], + [ + ['ko', 'ko-KO'], + { + important: '중요', + info: '정보', + note: '노트', + tip: '팁', + warning: '경고', + caution: '위험', + details: '세부사항', + }, + ], + [ + ['fi', 'fi-FI'], + { + important: 'Tärkeä', + info: 'Tietoa', + note: 'Huomautus', + tip: 'Vinkki', + warning: 'Varoitus', + caution: 'Vaara', + details: 'Yksityiskohdat', + }, + ], + [ + ['hu', 'hu-HU'], + { + important: 'Fontos', + info: 'Információ', + note: 'Megjegyzés', + tip: 'Tipp', + warning: 'Figyelem', + caution: 'Veszély', + details: 'Részletek', + }, + ], + [ + ['id', 'id-ID'], + { + important: 'Penting', + info: 'Pemberitahuan', + note: 'Catatan', + tip: 'Tips', + warning: 'Penting', + caution: 'Peringatan', + details: 'Rincian', + }, + ], + [ + ['nl', 'nl-NL'], + { + important: 'Belangrijk', + info: 'Info', + note: 'Notitie', + tip: 'Tips', + warning: 'Notitie', + caution: 'Waarschuwing', + details: 'Details', + }, + ], +] diff --git a/plugins/markdown/plugin-markdown-hint/src/node/markdownHintPlugin.ts b/plugins/markdown/plugin-markdown-hint/src/node/markdownHintPlugin.ts index 9e7e2416bf..9e18c0f392 100644 --- a/plugins/markdown/plugin-markdown-hint/src/node/markdownHintPlugin.ts +++ b/plugins/markdown/plugin-markdown-hint/src/node/markdownHintPlugin.ts @@ -1,10 +1,10 @@ -import { getLocaleConfig } from '@vuepress/helper' +import { getFullLocaleConfig } from '@vuepress/helper' import type { Plugin } from 'vuepress/core' import { getDirname, path } from 'vuepress/utils' import { alert } from './alert.js' import { hint } from './hint.js' -import { markdownHintPluginLocales } from './locales.js' +import { hintLocaleInfo } from './locales.js' import type { MarkdownHintPluginOptions } from './options.js' const PLUGIN_NAME = '@vuepress/plugin-markdown-hint' @@ -23,10 +23,10 @@ export const markdownHintPlugin = ( name: PLUGIN_NAME, extendsMarkdown: (md, app) => { - const locale = getLocaleConfig({ + const locale = getFullLocaleConfig({ app, name: PLUGIN_NAME, - default: markdownHintPluginLocales, + default: hintLocaleInfo, config: options.locales, }) diff --git a/plugins/pwa/plugin-pwa/src/node/getManifest.ts b/plugins/pwa/plugin-pwa/src/node/getManifest.ts index 427cb8d8b7..8379dbcdde 100644 --- a/plugins/pwa/plugin-pwa/src/node/getManifest.ts +++ b/plugins/pwa/plugin-pwa/src/node/getManifest.ts @@ -1,4 +1,3 @@ -import { getRootLang } from '@vuepress/helper' import type { App } from 'vuepress/core' import { fs } from 'vuepress/utils' import type { AppManifest } from '../shared/index.js' @@ -34,7 +33,8 @@ export const getManifest = async ( // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition siteData.locales['/']?.description || 'A site built with vuepress', - lang: getRootLang(app), + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + lang: app.siteData.locales['/']?.lang ?? app.siteData.lang, start_url: base, scope: base, diff --git a/plugins/pwa/plugin-pwa/src/node/locales.ts b/plugins/pwa/plugin-pwa/src/node/locales.ts index 6a7713cbe2..387423bd4e 100644 --- a/plugins/pwa/plugin-pwa/src/node/locales.ts +++ b/plugins/pwa/plugin-pwa/src/node/locales.ts @@ -1,313 +1,357 @@ -import type { PwaPluginLocaleConfig } from '../shared/index.js' +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { PwaPluginLocaleData } from '../shared/index.js' -/** Multi language config for pwa popup */ -export const pwaLocales: PwaPluginLocaleConfig = { - '/en/': { - install: 'Install', - iOSInstall: "Tap the share button and then 'Add to Home Screen'", - cancel: 'Cancel', - close: 'Close', - prevImage: 'Previous Image', - nextImage: 'Next Image', - desc: 'Description', - feature: 'Key Features', - explain: - 'This app can be installed on your PC or mobile device. This will allow this web app to look and behave like any other installed app. You will find it in your app lists and be able to pin it to your home screen, start menus or task bars. This installed web app will also be able to safely interact with other apps and your operating system. ', - hint: 'New content found.', - update: 'New content is available.', - }, - - '/zh/': { - install: '安装', - iOSInstall: '点击分享按钮然后点击“添加到主屏幕”', - cancel: '取消', - close: '关闭', - prevImage: '上一张图片', - nextImage: '下一张图片', - desc: '详情', - feature: '主要特色', - explain: - '该应用可以安装在你的 PC 或移动设备上。这将使该 Web 应用程序外观和行为与其他应用程序相同。它将在出现在应用程序列表中,并可以固定到主屏幕,开始菜单或任务栏。此 Web 应用程序还将能够与其他应用程序和你的操作系统安全地进行交互。', - hint: '发现新内容可用', - update: '新内容已就绪', - }, - - '/zh-tw/': { - install: '安裝', - iOSInstall: '點擊分享按鈕然後點擊“添加到主畫面”', - cancel: '取消', - close: '關閉', - prevImage: '上一張圖片', - nextImage: '下一張圖片', - desc: '詳情', - feature: '主要特色', - explain: - '該應用可以安裝在你的 PC 或行動裝置上。這將使該 Web 應用程式外觀和行為與其他應用程式相同。它將在出現在應用程式列表中,並可以固定到主畫面,開始菜單或任務欄。此 Web 應用程式還將能夠與其他應用程式和你的操作系統安全地進行交互。', - hint: '發現新内容可用', - update: '新内容已就绪', - }, - - '/de/': { - install: 'Installieren', - iOSInstall: "Drucke den Share-Button und dann 'zu Homescreen hinzufügen'", - cancel: 'Abbrechen', - close: 'Schließen', - prevImage: 'Vorheriges Bild', - nextImage: 'Nächstes Bild', - desc: 'Berschreibung', - feature: 'Funktionen', - explain: - 'Diese App kann auf Ihrem PC oder Mobilgerät installiert werden. Dadurch sieht diese Web-App aus und verhält sich wie jede andere installierte App. Sie finden sie in Ihren App-Listen und können sie an den Startbildschirm, die Startmenüs oder die Taskleisten anheften. Diese installierte Web-App kann auch sicher mit anderen Apps und Ihrem Betriebssystem interagieren.', - hint: 'Neuer Inhalt gefunden.', - update: 'Neue Inhalte sind verfügbar.', - }, - - '/de-at/': { - install: 'Installieren', - iOSInstall: "Drucke den Share-Button und dan 'zu Homescreen hinzufügen'", - cancel: 'Abbrechen', - close: 'Schließen', - prevImage: 'Vorheriges Bild', - nextImage: 'Nächstes Bild', - desc: 'Berschreibung', - feature: 'Features', - explain: - 'Diese App kann auf Ihrem PC oder Mobilgerät installiert werden. Dadurch sieht diese Web-App aus und verhält sich wie jede andere installierte App. Sie finden sie in Ihren App-Listen und können sie an den Startbildschirm, die Startmenüs oder die Taskleisten anheften. Diese installierte Web-App kann auch sicher mit anderen Apps und Ihrem Betriebssystem interagieren.', - hint: 'Neue Inhalte sind verfügbar.', - update: 'Neue Inhalte sind verfügbar.', - }, - - '/vi/': { - install: 'Tải về', - iOSInstall: "Nhấn vào nút chia sẻ và sau đó 'Thêm vào Màn hình chính'", - cancel: 'Huỷ bỏ', - close: 'Đóng', - prevImage: 'Hình ảnh trước đó', - nextImage: 'Hình ảnh tiếp theo', - desc: 'Sự miêu tả', - feature: 'Các tính năng chính', - explain: - 'Ứng dụng này có thể được cài đặt trên PC hoặc thiết bị di động của bạn. Điều này sẽ cho phép ứng dụng web này trông và hoạt động giống như bất kỳ ứng dụng đã cài đặt nào khác. Bạn sẽ tìm thấy nó trong danh sách ứng dụng của mình và có thể ghim nó vào màn hình chính, menu bắt đầu hoặc thanh tác vụ. Ứng dụng web đã cài đặt này cũng sẽ có thể tương tác an toàn với các ứng dụng khác và hệ điều hành của bạn.', - hint: 'Nội dung mới được tìm thấy', - update: 'Đã có nội dung mới', - }, - - '/uk/': { - install: 'Встановити', - iOSInstall: - 'Торкніться кнопки «Поділитися», а потім «Додати на головний екран»', - cancel: 'Скасувати', - close: 'Закрити', - prevImage: 'Попереднє зображення', - nextImage: 'Наступне зображення', - desc: 'Опис', - feature: 'Основні характеристики', - explain: - 'Цю програму можна встановити на ПК або мобільний пристрій. Це дозволить цій веб-програмі виглядати та вести себе як будь-яка інша встановлена програма. Ви знайдете її у списках додатків і зможете закріпити на головному екрані, в меню «Пуск» або на панелі завдань. Ця встановлена веб-програма також зможе безпечно взаємодіяти з іншими програмами та вашою операційною системою. ', - hint: 'Знайдено новий вміст', - update: 'Доступний новий контент.', - }, - - '/ru/': { - install: 'Установить', - iOSInstall: - 'Нажмите кнопку «Поделиться», а затем «Добавить на главный экран»', - cancel: 'Отменить', - close: 'Закрыть', - prevImage: 'Предыдущее изображение', - nextImage: 'Следующее изображение', - desc: 'Описание', - feature: 'Основные функции', - explain: - 'Это приложение может быть установлено на вашем компьютере или мобильном устройстве. Это позволит веб-приложению выглядеть и вести себя как любое другое установленное приложение. Вы найдете его в списках приложений и сможете закрепить его на домашнем экране, в меню пуск или на панели задач. Установленное веб-приложение также сможет безопасно взаимодействовать с другими приложениями и операционной системой. ', - hint: 'Найден новый контент', - update: 'Доступен новый контент.', - }, - - '/br/': { - install: 'Instalar', - iOSInstall: "Toque no botão de compartilhar e depois 'Adicionar à Home'", - cancel: 'Cancelar', - close: 'Fechar', - prevImage: 'Imagem anterior', - nextImage: 'Próxima imagem', - desc: 'Descrição', - feature: 'Características Chave', - explain: - 'Esta aplicação web pode ser instalada no seu PC ou dispositivo móvel. Isso fará com que ela se pareça e se comporte como qualquer outra aplicação. Você a encontrará na lista de apps e poderá adicionar seu ícone à tela de entrada, menus ou barras de tarefa. Uma vez instalada, esta aplicação web também poderá interagir com outras aplicações ou com o próprio sistema operacional. ', - hint: 'Novo conteúdo encontrado', - update: 'Novo conteúdo está disponível.', - }, - - '/pl/': { - install: 'Zainstaluj', - iOSInstall: - 'Stuknij przycisk udostępniania, a następnie „Dodaj do ekranu głównego”', - cancel: 'Anuluj', - close: 'Zamknij', - prevImage: 'Poprzedni obrazek', - nextImage: 'Następny obrazek', - desc: 'Opis', - feature: 'Kluczowe cechy', - explain: - 'Tę aplikację można zainstalować na komputerze lub urządzeniu mobilnym. Dzięki temu ta aplikacja internetowa będzie wyglądać i zachowywać się jak każda inna zainstalowana aplikacja. Znajdziesz ją na listach aplikacji i będziesz mógł przypiąć go do ekranu głównego, menu startowego lub pasków zadań. Ta zainstalowana aplikacja internetowa będzie również mogła bezpiecznie komunikować się z innymi aplikacjami i systemem operacyjnym.', - hint: 'Znaleziono nową zawartość.', - update: 'Nowa zawartość jest dostępna.', - }, - - '/sk/': { - install: 'Insštalácia', - iOSInstall: - "Klikni na tlačidlo zdielania a potom 'Daj na domovskú obrazovku'", - cancel: 'Zrušiť', - close: 'Zavrieť', - prevImage: 'Prodošlí obrázok', - nextImage: 'Ďalší obrázok', - desc: 'Poznámka', - feature: 'Kľúčové vlastnosti', - explain: - 'Túto aplikáciu je možné nainštalovať na počítač alebo mobil. Toto umožný sa správať aplikácii ako každej inej nainštalovanej aplikácii. Nájdeš ju vo svojom liste aplikácii a budeš môcť ju pripnúť na domovskú stránku, štartovacieho menu alebo do panelu úloh. Táto nainštalovaná webová aplikácia umžní tiež bezpečne komunikovať s ostatnými nainštalovanými aplikáciami a operačným systémom. ', - hint: 'Nový obsah bol nájdený.', - update: 'Nový obsah je dostupný.', - }, - - '/fr/': { - install: 'Installer', - iOSInstall: - "Appuyez sur le bouton partager puis 'Ajouter à l'écran d'accueil'", - cancel: 'Annuler', - close: 'Fermer', - prevImage: 'Image précédente', - nextImage: 'Image suivante', - desc: 'Description', - feature: 'Composants clés', - explain: - "Cette app peut être installée sur PC ou smartphone. Cela permettra de rendre cette page web comme n'importe quelle autre application. Vous la trouverez dans votre liste d'application et serez capable de la pin sur votre écran principal et divers menus. L'application web installée sera capable d'interagir avec les autres applications et le système d'exploitation.", - hint: 'New content found.', - update: 'New content is available.', - }, - - '/es/': { - install: 'Instalar', - iOSInstall: - "Toque el botón compartir y luego 'Agregar a la pantalla de inicio'", - cancel: 'Cancelar', - close: 'Cerrar', - prevImage: 'Imagen anterior', - nextImage: 'Imagen siguiente', - desc: 'Descripción', - feature: 'Características clave', - explain: - 'Esta aplicación se puede instalar en su PC o dispositivo móvil. Esto permitirá que esta aplicación web se vea y se comporte como cualquier otra aplicación instalada. Lo encontrará en su lista de aplicaciones y podrá fijarlo a su pantalla de inicio, menús de inicio o barras de tareas. Esta aplicación web instalada también podrá interactuar de manera segura con otras aplicaciones y su sistema operativo.', - hint: 'Nuevo contenido encontrado.', - update: 'Hay nuevo contenido disponible.', - }, - - '/ja/': { - install: 'インストール', - iOSInstall: - '共有ボタンをタップし、「ホームスクリーンに追加」をタップします', - cancel: 'キャンセル', - close: '閉じる', - prevImage: '前の画像', - nextImage: '次の画像', - desc: '詳細', - feature: '主な特徴', - explain: - 'このアプリは、PCまたはモバイルデバイスにインストールすることができます。 これにより、このウェブアプリは、インストールされている他のアプリと同様に表示され、動作するようになります。 アプリ一覧で見つけることができ、ホーム画面、スタートメニュー、タスクバーに固定することができます。 このインストールされたウェブアプリケーションは、他のアプリケーションやオペレーティングシステムと安全にやり取りすることもできます。', - hint: '新しいコンテンツが見つかりました。', - update: '新しいコンテンツが登場しました。', - }, - - '/tr/': { - install: 'Yükle', - iOSInstall: - "Paylaş düğmesine ve ardından 'Ana Ekrana Ekle' düğmesine basın", - cancel: 'İptal', - close: 'Kapat', - prevImage: 'Önceki Resim', - nextImage: 'Sonraki Resim', - desc: 'Tanım', - feature: 'Ana Özellikler', - explain: - "Bu uygulama PC'nize veya mobil cihazınıza yüklenebilir. Yüklenmesi bu web uygulamasının diğer yüklü uygulamalar gibi görünmesini ve davranmasını sağlar. Yüklenen web uygulamasını uygulama listenizde bulabilir ve ana ekranınıza, menülere veya görev çubuklarına sabitleyebilirsiniz. Aynı zamanda yüklenen web uygulaması, diğer uygulamalar ve işletim sisteminizle güvenli bir şekilde etkileşime girebilecektir.", - hint: 'Yeni içerik bulundu.', - update: 'Yeni içerik mevcut.', - }, - - '/ko/': { - install: '설치', - iOSInstall: "공유 버튼을 누르고 '홈 화면에 추가'를 누르세요", - cancel: '취소', - close: '닫기', - prevImage: '이전 이미지', - nextImage: '다음 이미지', - desc: '설명', - feature: '주요 기능', - explain: - '이 앱은 PC 또는 모바일 장치에 설치할 수 있습니다. 이렇게 하면 이 웹 앱은 다른 설치된 앱과 마찬가지로 표시되고 작동합니다. 앱 목록에서 찾을 수 있으며 홈 화면, 시작 메뉴, 작업 표시줄에 고정할 수 있습니다. 설치된 웹 앱은 다른 앱과 안전하게 상호 작용할 수 있습니다.', - hint: '새로운 콘텐츠를 찾았습니다.', - update: '새로운 콘텐츠가 있습니다.', - }, - - '/fi/': { - install: 'Asenna', - iOSInstall: "Paina Jaa-painiketta ja sitten 'Lisää kotiin'-painiketta", - cancel: 'Peruuta', - close: 'Sulje', - prevImage: 'Edellinen kuva', - nextImage: 'Seuraava kuva', - desc: 'Kuvaus', - feature: 'Avainominaisuudet', - explain: - 'Tämä sovellus on asennettavissa tietokoneelle tai mobiililaitteelle. Tämä mahdollistaa sovelluksen toiminnan tietokoneohjelmana. Löydät sen sovelluslistasta ja voit kiinnittää sen työpöydälle, kotinäytölle, tehtäväpalkkiin tai muulle listalle. Asennettu sovellus voi turvallisesti olla vuorovaikutuksessa muiden sovellusten ja käyttöjärjestelmäsi kanssa.', - hint: 'Uutta sisältöä.', - update: 'Uutta sisältöä on saatavilla.', - }, - - '/hu/': { - install: 'Telepítés', - iOSInstall: - "Nyomd meg a megosztás gombot, majd a 'Hozzáadás a kezdőképernyőhöz' opciót", - cancel: 'Mégse', - close: 'Bezárás', - prevImage: 'Előző kép', - nextImage: 'Következő kép', - desc: 'Leírás', - feature: 'Főbb jellemzők', - explain: - 'Ez az alkalmazás telepíthető PC-re vagy mobil eszközre. Ez lehetővé teszi, hogy ez a webalkalmazás úgy nézzen ki és viselkedjen, mint bármely más telepített alkalmazás. Az alkalmazáslistában találod majd, és hozzáadhatod a kezdőképernyőhöz, indító menühöz vagy a feladatok sávjához. Az telepített webalkalmazás biztonságosan interakcióba léphet más alkalmazásokkal és az operációs rendszerrel.', - hint: 'Új tartalom érhető el.', - update: 'Új tartalom érhető el.', - }, - - '/id/': { - install: 'Install', - iOSInstall: "Ketuk tombol bagikan, lalu 'Tambahkan ke Layar Utama'", - cancel: 'Batal', - close: 'Tutup', - prevImage: 'Gambar sebelumnya', - nextImage: 'Gambar selanjutnya', - desc: 'Keterangan', - feature: 'Fitur', - explain: - 'Aplikasi ini dapat diinstal di PC atau perangkat seluler Anda. Ini akan memungkinkan aplikasi web ini terlihat seperti aplikasi terpasang lainnya. Anda bisa menemukannya di daftar aplikasi dan dapat menyematkannya ke layar beranda, menu start, atau menu ke taskbar. Aplikasi web yang terinstal ini juga dapat berinteraksi dengan aplikasi lain dan dengan sistem operasi yang Anda gunakan. ', - hint: 'Konten baru ditemukan.', - update: 'Konten baru telah tersedia.', - }, - - '/nl/': { - install: 'Installeren', - iOSInstall: "Druk op de share button en dan op 'Add to Home Screen'", - cancel: 'Annuleren', - close: 'Sluiten', - prevImage: 'Vorige Foto', - nextImage: 'Volgende Foto', - desc: 'Beschrijving', - feature: 'Belangrijkste mogelijkheden', - explain: - 'Deze app kan op uw PC of mobiel toestel geïnstalleerd worden. Dit laat toe om deze webapp er uit te laten alsof het een normale app is. Je kan het terugvinden in jouw applijsten en kan het op je homescreen, start menu of taakbalk vastzetten. Deze geïnstalleerde webapp zal ook veilig samenwerken met andere apps en uw besturingssysteem. ', - hint: 'Nieuwe inhoud gevonden.', - update: 'Nieuwe inhoud is beschikbaar.', - }, -} +/** + * Default locale info for `@vuepress/plugin-pwa` + */ +export const pwaLocaleInfo: DefaultLocaleInfo = [ + [ + ['en', 'en-US'], + { + install: 'Install', + iOSInstall: "Tap the share button and then 'Add to Home Screen'", + cancel: 'Cancel', + close: 'Close', + prevImage: 'Previous Image', + nextImage: 'Next Image', + desc: 'Description', + feature: 'Key Features', + explain: + 'This app can be installed on your PC or mobile device. This will allow this web app to look and behave like any other installed app. You will find it in your app lists and be able to pin it to your home screen, start menus or task bars. This installed web app will also be able to safely interact with other apps and your operating system. ', + hint: 'New content found.', + update: 'New content is available.', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + install: '安装', + iOSInstall: '点击分享按钮然后点击“添加到主屏幕”', + cancel: '取消', + close: '关闭', + prevImage: '上一张图片', + nextImage: '下一张图片', + desc: '详情', + feature: '主要特色', + explain: + '该应用可以安装在你的 PC 或移动设备上。这将使该 Web 应用程序外观和行为与其他应用程序相同。它将在出现在应用程序列表中,并可以固定到主屏幕,开始菜单或任务栏。此 Web 应用程序还将能够与其他应用程序和你的操作系统安全地进行交互。', + hint: '发现新内容可用', + update: '新内容已就绪', + }, + ], + [ + ['zh', 'zh-TW', 'zh-Hant'], + { + install: '安裝', + iOSInstall: '點擊分享按鈕然後點擊“添加到主畫面”', + cancel: '取消', + close: '關閉', + prevImage: '上一張圖片', + nextImage: '下一張圖片', + desc: '詳情', + feature: '主要特色', + explain: + '該應用可以安裝在你的 PC 或行動裝置上。這將使該 Web 應用程式外觀和行為與其他應用程式相同。它將在出現在應用程式列表中,並可以固定到主畫面,開始菜單或任務欄。此 Web 應用程式還將能夠與其他應用程式和你的操作系統安全地進行交互。', + hint: '發現新内容可用', + update: '新内容已就绪', + }, + ], + [ + ['de', 'de-DE'], + { + install: 'Installieren', + iOSInstall: "Drucke den Share-Button und dann 'zu Homescreen hinzufügen'", + cancel: 'Abbrechen', + close: 'Schließen', + prevImage: 'Vorheriges Bild', + nextImage: 'Nächstes Bild', + desc: 'Berschreibung', + feature: 'Funktionen', + explain: + 'Diese App kann auf Ihrem PC oder Mobilgerät installiert werden. Dadurch sieht diese Web-App aus und verhält sich wie jede andere installierte App. Sie finden sie in Ihren App-Listen und können sie an den Startbildschirm, die Startmenüs oder die Taskleisten anheften. Diese installierte Web-App kann auch sicher mit anderen Apps und Ihrem Betriebssystem interagieren.', + hint: 'Neuer Inhalt gefunden.', + update: 'Neue Inhalte sind verfügbar.', + }, + ], + [ + ['de-AT'], + { + install: 'Installieren', + iOSInstall: "Drucke den Share-Button und dan 'zu Homescreen hinzufügen'", + cancel: 'Abbrechen', + close: 'Schließen', + prevImage: 'Vorheriges Bild', + nextImage: 'Nächstes Bild', + desc: 'Berschreibung', + feature: 'Features', + explain: + 'Diese App kann auf Ihrem PC oder Mobilgerät installiert werden. Dadurch sieht diese Web-App aus und verhält sich wie jede andere installierte App. Sie finden sie in Ihren App-Listen und können sie an den Startbildschirm, die Startmenüs oder die Taskleisten anheften. Diese installierte Web-App kann auch sicher mit anderen Apps und Ihrem Betriebssystem interagieren.', + hint: 'Neue Inhalte sind verfügbar.', + update: 'Neue Inhalte sind verfügbar.', + }, + ], + [ + ['vi', 'vi-VN'], + { + install: 'Tải về', + iOSInstall: "Nhấn vào nút chia sẻ và sau đó 'Thêm vào Màn hình chính'", + cancel: 'Huỷ bỏ', + close: 'Đóng', + prevImage: 'Hình ảnh trước đó', + nextImage: 'Hình ảnh tiếp theo', + desc: 'Sự miêu tả', + feature: 'Các tính năng chính', + explain: + 'Ứng dụng này có thể được cài đặt trên PC hoặc thiết bị di động của bạn. Điều này sẽ cho phép ứng dụng web này trông và hoạt động giống như bất kỳ ứng dụng đã cài đặt nào khác. Bạn sẽ tìm thấy nó trong danh sách ứng dụng của mình và có thể ghim nó vào màn hình chính, menu bắt đầu hoặc thanh tác vụ. Ứng dụng web đã cài đặt này cũng sẽ có thể tương tác an toàn với các ứng dụng khác và hệ điều hành của bạn.', + hint: 'Nội dung mới được tìm thấy', + update: 'Đã có nội dung mới', + }, + ], + [ + ['uk'], + { + install: 'Встановити', + iOSInstall: + 'Торкніться кнопки «Поділитися», а потім «Додати на головний екран»', + cancel: 'Скасувати', + close: 'Закрити', + prevImage: 'Попереднє зображення', + nextImage: 'Наступне зображення', + desc: 'Опис', + feature: 'Основні характеристики', + explain: + 'Цю програму можна встановити на ПК або мобільний пристрій. Це дозволить цій веб-програмі виглядати та вести себе як будь-яка інша встановлена програма. Ви знайдете її у списках додатків і зможете закріпити на головному екрані, в меню «Пуск» або на панелі завдань. Ця встановлена веб-програма також зможе безпечно взаємодіяти з іншими програмами та вашою операційною системою. ', + hint: 'Знайдено новий вміст', + update: 'Доступний новий контент.', + }, + ], + [ + ['ru', 'ru-RU'], + { + install: 'Установить', + iOSInstall: + 'Нажмите кнопку «Поделиться», а затем «Добавить на главный экран»', + cancel: 'Отменить', + close: 'Закрыть', + prevImage: 'Предыдущее изображение', + nextImage: 'Следующее изображение', + desc: 'Описание', + feature: 'Основные функции', + explain: + 'Это приложение может быть установлено на вашем компьютере или мобильном устройстве. Это позволит веб-приложению выглядеть и вести себя как любое другое установленное приложение. Вы найдете его в списках приложений и сможете закрепить его на домашнем экране, в меню пуск или на панели задач. Установленное веб-приложение также сможет безопасно взаимодействовать с другими приложениями и операционной системой. ', + hint: 'Найден новый контент', + update: 'Доступен новый контент.', + }, + ], + [ + ['br'], + { + install: 'Instalar', + iOSInstall: "Toque no botão de compartilhar e depois 'Adicionar à Home'", + cancel: 'Cancelar', + close: 'Fechar', + prevImage: 'Imagem anterior', + nextImage: 'Próxima imagem', + desc: 'Descrição', + feature: 'Características Chave', + explain: + 'Esta aplicação web pode ser instalada no seu PC ou dispositivo móvel. Isso fará com que ela se pareça e se comporte como qualquer outra aplicação. Você a encontrará na lista de apps e poderá adicionar seu ícone à tela de entrada, menus ou barras de tarefa. Uma vez instalada, esta aplicação web também poderá interagir com outras aplicações ou com o próprio sistema operacional. ', + hint: 'Novo conteúdo encontrado', + update: 'Novo conteúdo está disponível.', + }, + ], + [ + ['pl', 'pl-PL'], + { + install: 'Zainstaluj', + iOSInstall: + 'Stuknij przycisk udostępniania, a następnie „Dodaj do ekranu głównego”', + cancel: 'Anuluj', + close: 'Zamknij', + prevImage: 'Poprzedni obrazek', + nextImage: 'Następny obrazek', + desc: 'Opis', + feature: 'Kluczowe cechy', + explain: + 'Tę aplikację można zainstalować na komputerze lub urządzeniu mobilnym. Dzięki temu ta aplikacja internetowa będzie wyglądać i zachowywać się jak każda inna zainstalowana aplikacja. Znajdziesz ją na listach aplikacji i będziesz mógł przypiąć go do ekranu głównego, menu startowego lub pasków zadań. Ta zainstalowana aplikacja internetowa będzie również mogła bezpiecznie komunikować się z innymi aplikacjami i systemem operacyjnym.', + hint: 'Znaleziono nową zawartość.', + update: 'Nowa zawartość jest dostępna.', + }, + ], + [ + ['sk', 'sk-SK'], + { + install: 'Insštalácia', + iOSInstall: + "Klikni na tlačidlo zdielania a potom 'Daj na domovskú obrazovku'", + cancel: 'Zrušiť', + close: 'Zavrieť', + prevImage: 'Prodošlí obrázok', + nextImage: 'Ďalší obrázok', + desc: 'Poznámka', + feature: 'Kľúčové vlastnosti', + explain: + 'Túto aplikáciu je možné nainštalovať na počítač alebo mobil. Toto umožný sa správať aplikácii ako každej inej nainštalovanej aplikácii. Nájdeš ju vo svojom liste aplikácii a budeš môcť ju pripnúť na domovskú stránku, štartovacieho menu alebo do panelu úloh. Táto nainštalovaná webová aplikácia umžní tiež bezpečne komunikovať s ostatnými nainštalovanými aplikáciami a operačným systémom. ', + hint: 'Nový obsah bol nájdený.', + update: 'Nový obsah je dostupný.', + }, + ], + [ + ['fr', 'fr-FR'], + { + install: 'Installer', + iOSInstall: + "Appuyez sur le bouton partager puis 'Ajouter à l'écran d'accueil'", + cancel: 'Annuler', + close: 'Fermer', + prevImage: 'Image précédente', + nextImage: 'Image suivante', + desc: 'Description', + feature: 'Composants clés', + explain: + "Cette app peut être installée sur PC ou smartphone. Cela permettra de rendre cette page web comme n'importe quelle autre application. Vous la trouverez dans votre liste d'application et serez capable de la pin sur votre écran principal et divers menus. L'application web installée sera capable d'interagir avec les autres applications et le système d'exploitation.", + hint: 'New content found.', + update: 'New content is available.', + }, + ], + [ + ['es', 'es-ES'], + { + install: 'Instalar', + iOSInstall: + "Toque el botón compartir y luego 'Agregar a la pantalla de inicio'", + cancel: 'Cancelar', + close: 'Cerrar', + prevImage: 'Imagen anterior', + nextImage: 'Imagen siguiente', + desc: 'Descripción', + feature: 'Características clave', + explain: + 'Esta aplicación se puede instalar en su PC o dispositivo móvil. Esto permitirá que esta aplicación web se vea y se comporte como cualquier otra aplicación instalada. Lo encontrará en su lista de aplicaciones y podrá fijarlo a su pantalla de inicio, menús de inicio o barras de tareas. Esta aplicación web instalada también podrá interactuar de manera segura con otras aplicaciones y su sistema operativo.', + hint: 'Nuevo contenido encontrado.', + update: 'Hay nuevo contenido disponible.', + }, + ], + [ + ['ja', 'ja-JP'], + { + install: 'インストール', + iOSInstall: + '共有ボタンをタップし、「ホームスクリーンに追加」をタップします', + cancel: 'キャンセル', + close: '閉じる', + prevImage: '前の画像', + nextImage: '次の画像', + desc: '詳細', + feature: '主な特徴', + explain: + 'このアプリは、PCまたはモバイルデバイスにインストールすることができます。 これにより、このウェブアプリは、インストールされている他のアプリと同様に表示され、動作するようになります。 アプリ一覧で見つけることができ、ホーム画面、スタートメニュー、タスクバーに固定することができます。 このインストールされたウェブアプリケーションは、他のアプリケーションやオペレーティングシステムと安全にやり取りすることもできます。', + hint: '新しいコンテンツが見つかりました。', + update: '新しいコンテンツが登場しました。', + }, + ], + [ + ['tr', 'tr-TR'], + { + install: 'Yükle', + iOSInstall: + "Paylaş düğmesine ve ardından 'Ana Ekrana Ekle' düğmesine basın", + cancel: 'İptal', + close: 'Kapat', + prevImage: 'Önceki Resim', + nextImage: 'Sonraki Resim', + desc: 'Tanım', + feature: 'Ana Özellikler', + explain: + "Bu uygulama PC'nize veya mobil cihazınıza yüklenebilir. Yüklenmesi bu web uygulamasının diğer yüklü uygulamalar gibi görünmesini ve davranmasını sağlar. Yüklenen web uygulamasını uygulama listenizde bulabilir ve ana ekranınıza, menülere veya görev çubuklarına sabitleyebilirsiniz. Aynı zamanda yüklenen web uygulaması, diğer uygulamalar ve işletim sisteminizle güvenli bir şekilde etkileşime girebilecektir.", + hint: 'Yeni içerik bulundu.', + update: 'Yeni içerik mevcut.', + }, + ], + [ + ['ko', 'ko-KO'], + { + install: '설치', + iOSInstall: "공유 버튼을 누르고 '홈 화면에 추가'를 누르세요", + cancel: '취소', + close: '닫기', + prevImage: '이전 이미지', + nextImage: '다음 이미지', + desc: '설명', + feature: '주요 기능', + explain: + '이 앱은 PC 또는 모바일 장치에 설치할 수 있습니다. 이렇게 하면 이 웹 앱은 다른 설치된 앱과 마찬가지로 표시되고 작동합니다. 앱 목록에서 찾을 수 있으며 홈 화면, 시작 메뉴, 작업 표시줄에 고정할 수 있습니다. 설치된 웹 앱은 다른 앱과 안전하게 상호 작용할 수 있습니다.', + hint: '새로운 콘텐츠를 찾았습니다.', + update: '새로운 콘텐츠가 있습니다.', + }, + ], + [ + ['fi', 'fi-FI'], + { + install: 'Asenna', + iOSInstall: "Paina Jaa-painiketta ja sitten 'Lisää kotiin'-painiketta", + cancel: 'Peruuta', + close: 'Sulje', + prevImage: 'Edellinen kuva', + nextImage: 'Seuraava kuva', + desc: 'Kuvaus', + feature: 'Avainominaisuudet', + explain: + 'Tämä sovellus on asennettavissa tietokoneelle tai mobiililaitteelle. Tämä mahdollistaa sovelluksen toiminnan tietokoneohjelmana. Löydät sen sovelluslistasta ja voit kiinnittää sen työpöydälle, kotinäytölle, tehtäväpalkkiin tai muulle listalle. Asennettu sovellus voi turvallisesti olla vuorovaikutuksessa muiden sovellusten ja käyttöjärjestelmäsi kanssa.', + hint: 'Uutta sisältöä.', + update: 'Uutta sisältöä on saatavilla.', + }, + ], + [ + ['hu', 'hu-HU'], + { + install: 'Telepítés', + iOSInstall: + "Nyomd meg a megosztás gombot, majd a 'Hozzáadás a kezdőképernyőhöz' opciót", + cancel: 'Mégse', + close: 'Bezárás', + prevImage: 'Előző kép', + nextImage: 'Következő kép', + desc: 'Leírás', + feature: 'Főbb jellemzők', + explain: + 'Ez az alkalmazás telepíthető PC-re vagy mobil eszközre. Ez lehetővé teszi, hogy ez a webalkalmazás úgy nézzen ki és viselkedjen, mint bármely más telepített alkalmazás. Az alkalmazáslistában találod majd, és hozzáadhatod a kezdőképernyőhöz, indító menühöz vagy a feladatok sávjához. Az telepített webalkalmazás biztonságosan interakcióba léphet más alkalmazásokkal és az operációs rendszerrel.', + hint: 'Új tartalom érhető el.', + update: 'Új tartalom érhető el.', + }, + ], + [ + ['id', 'id-ID'], + { + install: 'Install', + iOSInstall: "Ketuk tombol bagikan, lalu 'Tambahkan ke Layar Utama'", + cancel: 'Batal', + close: 'Tutup', + prevImage: 'Gambar sebelumnya', + nextImage: 'Gambar selanjutnya', + desc: 'Keterangan', + feature: 'Fitur', + explain: + 'Aplikasi ini dapat diinstal di PC atau perangkat seluler Anda. Ini akan memungkinkan aplikasi web ini terlihat seperti aplikasi terpasang lainnya. Anda bisa menemukannya di daftar aplikasi dan dapat menyematkannya ke layar beranda, menu start, atau menu ke taskbar. Aplikasi web yang terinstal ini juga dapat berinteraksi dengan aplikasi lain dan dengan sistem operasi yang Anda gunakan. ', + hint: 'Konten baru ditemukan.', + update: 'Konten baru telah tersedia.', + }, + ], + [ + ['nl', 'nl-NL'], + { + install: 'Installeren', + iOSInstall: "Druk op de share button en dan op 'Add to Home Screen'", + cancel: 'Annuleren', + close: 'Sluiten', + prevImage: 'Vorige Foto', + nextImage: 'Volgende Foto', + desc: 'Beschrijving', + feature: 'Belangrijkste mogelijkheden', + explain: + 'Deze app kan op uw PC of mobiel toestel geïnstalleerd worden. Dit laat toe om deze webapp er uit te laten alsof het een normale app is. Je kan het terugvinden in jouw applijsten en kan het op je homescreen, start menu of taakbalk vastzetten. Deze geïnstalleerde webapp zal ook veilig samenwerken met andere apps en uw besturingssysteem. ', + hint: 'Nieuwe inhoud gevonden.', + update: 'Nieuwe inhoud is beschikbaar.', + }, + ], +] diff --git a/plugins/pwa/plugin-pwa/src/node/prepareClientConfigFile.ts b/plugins/pwa/plugin-pwa/src/node/prepareClientConfigFile.ts index 8d244e498d..577677c45c 100644 --- a/plugins/pwa/plugin-pwa/src/node/prepareClientConfigFile.ts +++ b/plugins/pwa/plugin-pwa/src/node/prepareClientConfigFile.ts @@ -1,7 +1,7 @@ -import { getLocaleConfig, getModulePath } from '@vuepress/helper' +import { getFullLocaleConfig, getModulePath } from '@vuepress/helper' import type { App } from 'vuepress/core' import { getDirname, path } from 'vuepress/utils' -import { pwaLocales } from './locales.js' +import { pwaLocaleInfo } from './locales.js' import { PLUGIN_NAME } from './logger.js' import type { PwaPluginOptions } from './options.js' @@ -52,10 +52,10 @@ ${configImport} import "${getModulePath('@vuepress/plugin-pwa/styles/vars.css', import.meta)}"; const locales = ${JSON.stringify( - getLocaleConfig({ + getFullLocaleConfig({ app, name: PLUGIN_NAME, - default: pwaLocales, + default: pwaLocaleInfo, config: options.locales, }), )}; diff --git a/plugins/search/plugin-slimsearch/src/node/locales.ts b/plugins/search/plugin-slimsearch/src/node/locales.ts index f910ad7616..904b1f1cb3 100644 --- a/plugins/search/plugin-slimsearch/src/node/locales.ts +++ b/plugins/search/plugin-slimsearch/src/node/locales.ts @@ -1,344 +1,388 @@ -import type { SlimSearchLocaleConfig } from '../shared/index.js' +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { SlimSearchLocaleData } from '../shared/index.js' -/** Multi language config for slimsearch popup */ -export const locales: SlimSearchLocaleConfig = { - '/en/': { - cancel: 'Cancel', - placeholder: 'Search', - search: 'Search', - searching: 'Searching', - defaultTitle: 'Documentation', - select: 'to select', - navigate: 'to navigate', - autocomplete: 'to autocomplete', - exit: 'to exit', - queryHistory: 'Search History', - resultHistory: 'Result History', - emptyHistory: 'Empty Search History', - emptyResult: 'No results found', - loading: 'Loading search indexes...', - }, - - '/zh/': { - cancel: '取消', - placeholder: '搜索', - search: '搜索', - searching: '搜索中', - defaultTitle: '文档', - select: '选择', - navigate: '切换', - autocomplete: '自动补全', - exit: '关闭', - queryHistory: '搜索历史', - resultHistory: '历史结果', - emptyHistory: '无搜索历史', - emptyResult: '没有找到结果', - loading: '正在加载搜索索引...', - }, - - '/zh-tw/': { - cancel: '取消', - placeholder: '搜索', - search: '搜索', - searching: '搜索中', - defaultTitle: '文檔', - select: '選擇', - navigate: '切換', - autocomplete: '自動補全', - exit: '關閉', - queryHistory: '搜索歷史', - resultHistory: '歷史結果', - emptyHistory: '無搜索歷史', - emptyResult: '沒有找到結果', - loading: '正在加載搜索索引...', - }, - - '/de/': { - cancel: 'Abbrechen', - placeholder: 'Suche', - search: 'Suche', - searching: 'Suche', - defaultTitle: 'Dokumentation', - select: 'auswählen', - navigate: 'wechseln', - autocomplete: 'automatisch vervollständigen', - exit: 'schließen', - queryHistory: 'Suchverlauf', - resultHistory: 'Ergebnisverlauf', - emptyHistory: 'Suchverlauf leeren', - emptyResult: 'Keine Ergebnisse gefunden', - loading: 'Suchindex wird geladen...', - }, - - '/de-at/': { - cancel: 'Abbrechen', - placeholder: 'Suche', - search: 'Suche', - searching: 'Suche', - defaultTitle: 'Dokumentation', - select: 'auswählen', - navigate: 'wechseln', - autocomplete: 'automatisch vervollständigen', - exit: 'schließen', - queryHistory: 'Suchverlauf', - resultHistory: 'Ergebnisverlauf', - emptyHistory: 'Suchverlauf leeren', - emptyResult: 'Keine Ergebnisse gefunden', - loading: 'Suchindex wird geladen...', - }, - - '/vi/': { - cancel: 'Hủy', - placeholder: 'Tìm kiếm', - search: 'Tìm kiếm', - searching: 'Đang tìm kiếm', - defaultTitle: 'Tài liệu', - select: 'chọn', - navigate: 'chuyển', - autocomplete: 'tự động hoàn thành', - exit: 'đóng', - queryHistory: 'Lịch sử tìm kiếm', - resultHistory: 'Lịch sử kết quả', - emptyHistory: 'Xóa lịch sử tìm kiếm', - emptyResult: 'Không tìm thấy kết quả', - loading: 'Đang tải chỉ mục tìm kiếm...', - }, - - '/uk/': { - cancel: 'Скасувати', - placeholder: 'Пошук', - search: 'Пошук', - searching: 'Пошук', - defaultTitle: 'Документація', - select: 'вибрати', - navigate: 'перейти', - autocomplete: 'автозаповнення', - exit: 'закрити', - queryHistory: 'Історія пошуку', - resultHistory: 'Історія результатів', - emptyHistory: 'Очистити історію пошуку', - emptyResult: 'Нічого не знайдено', - loading: 'Завантаження пошукових індексів...', - }, - - '/ru/': { - cancel: 'Отмена', - placeholder: 'Поиск', - search: 'Поиск', - searching: 'Поиск', - defaultTitle: 'Документация', - select: 'выбрать', - navigate: 'переключить', - autocomplete: 'автозаполнение', - exit: 'закрыть', - queryHistory: 'История поиска', - resultHistory: 'История результатов', - emptyHistory: 'Очистить историю поиска', - emptyResult: 'Ничего не найдено', - loading: 'Загрузка поисковых индексов...', - }, - - '/br/': { - cancel: 'Cancelar', - placeholder: 'Pesquisar', - search: 'Pesquisar', - searching: 'Pesquisando', - defaultTitle: 'Documentação', - select: 'selecionar', - navigate: 'navegar', - autocomplete: 'autocompletar', - exit: 'fechar', - queryHistory: 'Histórico de pesquisa', - resultHistory: 'Histórico de resultados', - emptyHistory: 'Limpar histórico de pesquisa', - emptyResult: 'Nenhum resultado encontrado', - loading: 'Carregando índices de pesquisa...', - }, - - '/pl/': { - cancel: 'Anuluj', - placeholder: 'Szukaj', - search: 'Szukaj', - searching: 'Szukanie', - defaultTitle: 'Dokumentacja', - select: 'wybierz', - navigate: 'przejdź', - autocomplete: 'autouzupełnianie', - exit: 'zamknij', - queryHistory: 'Historia wyszukiwania', - resultHistory: 'Historia wyników', - emptyHistory: 'Wyczyść historię wyszukiwania', - emptyResult: 'Nie znaleziono wyników', - loading: 'Ładowanie indeksów wyszukiwania...', - }, - - '/sk/': { - cancel: 'Zrušiť', - placeholder: 'Hľadať', - search: 'Hľadať', - searching: 'Hľadanie', - defaultTitle: 'Dokumentácia', - select: 'vybrať', - navigate: 'prepnúť', - autocomplete: 'automatické dopĺňanie', - exit: 'zavrieť', - queryHistory: 'História vyhľadávania', - resultHistory: 'História výsledkov', - emptyHistory: 'Vymazať históriu vyhľadávania', - emptyResult: 'Nenašli sa žiadne výsledky', - loading: 'Načítavajú sa vyhľadávacie indexy...', - }, - - '/fr/': { - cancel: 'Annuler', - placeholder: 'Rechercher', - search: 'Rechercher', - searching: 'Recherche', - defaultTitle: 'Documentation', - select: 'sélectionner', - navigate: 'naviguer', - autocomplete: 'auto-complétion', - exit: 'fermer', - queryHistory: 'Historique de recherche', - resultHistory: 'Historique des résultats', - emptyHistory: "Vider l'historique de recherche", - emptyResult: 'Aucun résultat trouvé', - loading: 'Chargement des index de recherche...', - }, - - '/es/': { - cancel: 'Cancelar', - placeholder: 'Buscar', - search: 'Buscar', - searching: 'Buscando', - defaultTitle: 'Documentación', - select: 'seleccionar', - navigate: 'navegar', - autocomplete: 'autocompletar', - exit: 'cerrar', - queryHistory: 'Historial de búsqueda', - resultHistory: 'Historial de resultados', - emptyHistory: 'Vaciar historial de búsqueda', - emptyResult: 'No se encontraron resultados', - loading: 'Cargando índices de búsqueda...', - }, - - '/ja/': { - cancel: 'キャンセル', - placeholder: '検索', - search: '検索', - searching: '検索中', - defaultTitle: 'ドキュメント', - select: '選択', - navigate: '切り替え', - autocomplete: 'オートコンプリート', - exit: '閉じる', - queryHistory: '検索履歴', - resultHistory: '結果履歴', - emptyHistory: '検索履歴をクリア', - emptyResult: '結果が見つかりません', - loading: '検索インデックスを読み込んでいます...', - }, - - '/tr/': { - cancel: 'İptal', - placeholder: 'Ara', - search: 'Ara', - searching: 'Aranıyor', - defaultTitle: 'Dökümantasyon', - select: 'seç', - navigate: 'geç', - autocomplete: 'otomatik tamamlama', - exit: 'kapat', - queryHistory: 'Arama geçmişi', - resultHistory: 'Sonuç geçmişi', - emptyHistory: 'Arama geçmişini temizle', - emptyResult: 'Sonuç bulunamadı', - loading: 'Arama dizinleri yükleniyor...', - }, - - '/ko/': { - cancel: '취소', - placeholder: '검색', - search: '검색', - searching: '검색 중', - defaultTitle: '문서', - select: '선택', - navigate: '이동', - autocomplete: '자동 완성', - exit: '닫기', - queryHistory: '검색 기록', - resultHistory: '결과 기록', - emptyHistory: '검색 기록 지우기', - emptyResult: '결과를 찾을 수 없습니다', - loading: '검색 인덱스를 로드하는 중...', - }, - - '/fi/': { - cancel: 'Peruuta', - placeholder: 'Etsi', - search: 'Etsi', - searching: 'Etsitään', - defaultTitle: 'Dokumentaatio', - select: 'valitaksesi', - navigate: 'navigoidaksesi', - autocomplete: 'automaattinen täydennys', - exit: 'poistuaksesi', - queryHistory: 'Hakuhistoria', - resultHistory: 'Tuloshistoria', - emptyHistory: 'Tyhjennä hakuhistoria', - emptyResult: 'Tuloksia ei löytynyt', - loading: 'Ladataan hakuindeksiä...', - }, - - '/hu/': { - cancel: 'Mégse', - placeholder: 'Keresés', - search: 'Keresés', - searching: 'Keresés', - defaultTitle: 'Dokumentáció', - select: 'kiválasztáshoz', - navigate: 'navigáláshoz', - autocomplete: 'automatikus kiegészítés', - exit: 'kilépéshez', - queryHistory: 'Keresési előzmények', - resultHistory: 'Eredmények előzményei', - emptyHistory: 'Üres keresési előzmények', - emptyResult: 'Nincs találat', - loading: 'A keresési indexek betöltése...', - }, - - '/id/': { - cancel: 'Batal', - placeholder: 'Cari sesuatu 🔎', - search: 'Cari', - searching: 'Sedang mencari', - defaultTitle: 'Dokumentasi', - select: 'pilih', - navigate: 'navigasi', - autocomplete: 'autoselesai', - exit: 'keluar', - queryHistory: 'Riwayat Penelusuran', - resultHistory: 'Riwayat Hasil', - emptyHistory: 'Tidak ada riwayat penelusuran', - emptyResult: 'Hasil penelusuran tidak tersedia', - loading: 'Memuat indeks penelusuran...', - }, - - '/nl/': { - cancel: 'Annuleren', - placeholder: 'Zoeken', - search: 'Zoeken', - searching: 'Zoeken', - defaultTitle: 'Documentatie', - select: 'Selecteren', - navigate: 'to navigate', - autocomplete: 'autocompletion', - exit: 'to exit', - queryHistory: 'Zoekgeschiedenis', - resultHistory: 'Resultaatgeschiedenis', - emptyHistory: 'Zoekgeschiedenis Leegmaken', - emptyResult: 'Geen resultaten gevonden', - loading: 'Laden van zoekindexen...', - }, -} +/** + * Default locale info for `@vuepress/plugin-slimsearch` + */ +export const slimsearchLocaleInfo: DefaultLocaleInfo = [ + [ + ['en', 'en-US'], + { + cancel: 'Cancel', + placeholder: 'Search', + search: 'Search', + searching: 'Searching', + defaultTitle: 'Documentation', + select: 'to select', + navigate: 'to navigate', + autocomplete: 'to autocomplete', + exit: 'to exit', + queryHistory: 'Search History', + resultHistory: 'Result History', + emptyHistory: 'Empty Search History', + emptyResult: 'No results found', + loading: 'Loading search indexes...', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + cancel: '取消', + placeholder: '搜索', + search: '搜索', + searching: '搜索中', + defaultTitle: '文档', + select: '选择', + navigate: '切换', + autocomplete: '自动补全', + exit: '关闭', + queryHistory: '搜索历史', + resultHistory: '历史结果', + emptyHistory: '无搜索历史', + emptyResult: '没有找到结果', + loading: '正在加载搜索索引...', + }, + ], + [ + ['zh', 'zh-TW', 'zh-Hant'], + { + cancel: '取消', + placeholder: '搜索', + search: '搜索', + searching: '搜索中', + defaultTitle: '文檔', + select: '選擇', + navigate: '切換', + autocomplete: '自動補全', + exit: '關閉', + queryHistory: '搜索歷史', + resultHistory: '歷史結果', + emptyHistory: '無搜索歷史', + emptyResult: '沒有找到結果', + loading: '正在加載搜索索引...', + }, + ], + [ + ['de', 'de-DE'], + { + cancel: 'Abbrechen', + placeholder: 'Suche', + search: 'Suche', + searching: 'Suche', + defaultTitle: 'Dokumentation', + select: 'auswählen', + navigate: 'wechseln', + autocomplete: 'automatisch vervollständigen', + exit: 'schließen', + queryHistory: 'Suchverlauf', + resultHistory: 'Ergebnisverlauf', + emptyHistory: 'Suchverlauf leeren', + emptyResult: 'Keine Ergebnisse gefunden', + loading: 'Suchindex wird geladen...', + }, + ], + [ + ['de-AT'], + { + cancel: 'Abbrechen', + placeholder: 'Suche', + search: 'Suche', + searching: 'Suche', + defaultTitle: 'Dokumentation', + select: 'auswählen', + navigate: 'wechseln', + autocomplete: 'automatisch vervollständigen', + exit: 'schließen', + queryHistory: 'Suchverlauf', + resultHistory: 'Ergebnisverlauf', + emptyHistory: 'Suchverlauf leeren', + emptyResult: 'Keine Ergebnisse gefunden', + loading: 'Suchindex wird geladen...', + }, + ], + [ + ['vi', 'vi-VN'], + { + cancel: 'Hủy', + placeholder: 'Tìm kiếm', + search: 'Tìm kiếm', + searching: 'Đang tìm kiếm', + defaultTitle: 'Tài liệu', + select: 'chọn', + navigate: 'chuyển', + autocomplete: 'tự động hoàn thành', + exit: 'đóng', + queryHistory: 'Lịch sử tìm kiếm', + resultHistory: 'Lịch sử kết quả', + emptyHistory: 'Xóa lịch sử tìm kiếm', + emptyResult: 'Không tìm thấy kết quả', + loading: 'Đang tải chỉ mục tìm kiếm...', + }, + ], + [ + ['uk'], + { + cancel: 'Скасувати', + placeholder: 'Пошук', + search: 'Пошук', + searching: 'Пошук', + defaultTitle: 'Документація', + select: 'вибрати', + navigate: 'перейти', + autocomplete: 'автозаповнення', + exit: 'закрити', + queryHistory: 'Історія пошуку', + resultHistory: 'Історія результатів', + emptyHistory: 'Очистити історію пошуку', + emptyResult: 'Нічого не знайдено', + loading: 'Завантаження пошукових індексів...', + }, + ], + [ + ['ru', 'ru-RU'], + { + cancel: 'Отмена', + placeholder: 'Поиск', + search: 'Поиск', + searching: 'Поиск', + defaultTitle: 'Документация', + select: 'выбрать', + navigate: 'переключить', + autocomplete: 'автозаполнение', + exit: 'закрыть', + queryHistory: 'История поиска', + resultHistory: 'История результатов', + emptyHistory: 'Очистить историю поиска', + emptyResult: 'Ничего не найдено', + loading: 'Загрузка поисковых индексов...', + }, + ], + [ + ['br'], + { + cancel: 'Cancelar', + placeholder: 'Pesquisar', + search: 'Pesquisar', + searching: 'Pesquisando', + defaultTitle: 'Documentação', + select: 'selecionar', + navigate: 'navegar', + autocomplete: 'autocompletar', + exit: 'fechar', + queryHistory: 'Histórico de pesquisa', + resultHistory: 'Histórico de resultados', + emptyHistory: 'Limpar histórico de pesquisa', + emptyResult: 'Nenhum resultado encontrado', + loading: 'Carregando índices de pesquisa...', + }, + ], + [ + ['pl', 'pl-PL'], + { + cancel: 'Anuluj', + placeholder: 'Szukaj', + search: 'Szukaj', + searching: 'Szukanie', + defaultTitle: 'Dokumentacja', + select: 'wybierz', + navigate: 'przejdź', + autocomplete: 'autouzupełnianie', + exit: 'zamknij', + queryHistory: 'Historia wyszukiwania', + resultHistory: 'Historia wyników', + emptyHistory: 'Wyczyść historię wyszukiwania', + emptyResult: 'Nie znaleziono wyników', + loading: 'Ładowanie indeksów wyszukiwania...', + }, + ], + [ + ['sk', 'sk-SK'], + { + cancel: 'Zrušiť', + placeholder: 'Hľadať', + search: 'Hľadať', + searching: 'Hľadanie', + defaultTitle: 'Dokumentácia', + select: 'vybrať', + navigate: 'prepnúť', + autocomplete: 'automatické dopĺňanie', + exit: 'zavrieť', + queryHistory: 'História vyhľadávania', + resultHistory: 'História výsledkov', + emptyHistory: 'Vymazať históriu vyhľadávania', + emptyResult: 'Nenašli sa žiadne výsledky', + loading: 'Načítavajú sa vyhľadávacie indexy...', + }, + ], + [ + ['fr', 'fr-FR'], + { + cancel: 'Annuler', + placeholder: 'Rechercher', + search: 'Rechercher', + searching: 'Recherche', + defaultTitle: 'Documentation', + select: 'sélectionner', + navigate: 'naviguer', + autocomplete: 'auto-complétion', + exit: 'fermer', + queryHistory: 'Historique de recherche', + resultHistory: 'Historique des résultats', + emptyHistory: "Vider l'historique de recherche", + emptyResult: 'Aucun résultat trouvé', + loading: 'Chargement des index de recherche...', + }, + ], + [ + ['es', 'es-ES'], + { + cancel: 'Cancelar', + placeholder: 'Buscar', + search: 'Buscar', + searching: 'Buscando', + defaultTitle: 'Documentación', + select: 'seleccionar', + navigate: 'navegar', + autocomplete: 'autocompletar', + exit: 'cerrar', + queryHistory: 'Historial de búsqueda', + resultHistory: 'Historial de resultados', + emptyHistory: 'Vaciar historial de búsqueda', + emptyResult: 'No se encontraron resultados', + loading: 'Cargando índices de búsqueda...', + }, + ], + [ + ['ja', 'ja-JP'], + { + cancel: 'キャンセル', + placeholder: '検索', + search: '検索', + searching: '検索中', + defaultTitle: 'ドキュメント', + select: '選択', + navigate: '切り替え', + autocomplete: 'オートコンプリート', + exit: '閉じる', + queryHistory: '検索履歴', + resultHistory: '結果履歴', + emptyHistory: '検索履歴をクリア', + emptyResult: '結果が見つかりません', + loading: '検索インデックスを読み込んでいます...', + }, + ], + [ + ['tr', 'tr-TR'], + { + cancel: 'İptal', + placeholder: 'Ara', + search: 'Ara', + searching: 'Aranıyor', + defaultTitle: 'Dökümantasyon', + select: 'seç', + navigate: 'geç', + autocomplete: 'otomatik tamamlama', + exit: 'kapat', + queryHistory: 'Arama geçmişi', + resultHistory: 'Sonuç geçmişi', + emptyHistory: 'Arama geçmişini temizle', + emptyResult: 'Sonuç bulunamadı', + loading: 'Arama dizinleri yükleniyor...', + }, + ], + [ + ['ko', 'ko-KO'], + { + cancel: '취소', + placeholder: '검색', + search: '검색', + searching: '검색 중', + defaultTitle: '문서', + select: '선택', + navigate: '이동', + autocomplete: '자동 완성', + exit: '닫기', + queryHistory: '검색 기록', + resultHistory: '결과 기록', + emptyHistory: '검색 기록 지우기', + emptyResult: '결과를 찾을 수 없습니다', + loading: '검색 인덱스를 로드하는 중...', + }, + ], + [ + ['fi', 'fi-FI'], + { + cancel: 'Peruuta', + placeholder: 'Etsi', + search: 'Etsi', + searching: 'Etsitään', + defaultTitle: 'Dokumentaatio', + select: 'valitaksesi', + navigate: 'navigoidaksesi', + autocomplete: 'automaattinen täydennys', + exit: 'poistuaksesi', + queryHistory: 'Hakuhistoria', + resultHistory: 'Tuloshistoria', + emptyHistory: 'Tyhjennä hakuhistoria', + emptyResult: 'Tuloksia ei löytynyt', + loading: 'Ladataan hakuindeksiä...', + }, + ], + [ + ['hu', 'hu-HU'], + { + cancel: 'Mégse', + placeholder: 'Keresés', + search: 'Keresés', + searching: 'Keresés', + defaultTitle: 'Dokumentáció', + select: 'kiválasztáshoz', + navigate: 'navigáláshoz', + autocomplete: 'automatikus kiegészítés', + exit: 'kilépéshez', + queryHistory: 'Keresési előzmények', + resultHistory: 'Eredmények előzményei', + emptyHistory: 'Üres keresési előzmények', + emptyResult: 'Nincs találat', + loading: 'A keresési indexek betöltése...', + }, + ], + [ + ['id', 'id-ID'], + { + cancel: 'Batal', + placeholder: 'Cari sesuatu 🔎', + search: 'Cari', + searching: 'Sedang mencari', + defaultTitle: 'Dokumentasi', + select: 'pilih', + navigate: 'navigasi', + autocomplete: 'autoselesai', + exit: 'keluar', + queryHistory: 'Riwayat Penelusuran', + resultHistory: 'Riwayat Hasil', + emptyHistory: 'Tidak ada riwayat penelusuran', + emptyResult: 'Hasil penelusuran tidak tersedia', + loading: 'Memuat indeks penelusuran...', + }, + ], + [ + ['nl', 'nl-NL'], + { + cancel: 'Annuleren', + placeholder: 'Zoeken', + search: 'Zoeken', + searching: 'Zoeken', + defaultTitle: 'Documentatie', + select: 'Selecteren', + navigate: 'to navigate', + autocomplete: 'autocompletion', + exit: 'to exit', + queryHistory: 'Zoekgeschiedenis', + resultHistory: 'Resultaatgeschiedenis', + emptyHistory: 'Zoekgeschiedenis Leegmaken', + emptyResult: 'Geen resultaten gevonden', + loading: 'Laden van zoekindexen...', + }, + ], +] diff --git a/plugins/search/plugin-slimsearch/src/node/slimsearchPlugin.ts b/plugins/search/plugin-slimsearch/src/node/slimsearchPlugin.ts index a25b625a72..9eee7581dc 100644 --- a/plugins/search/plugin-slimsearch/src/node/slimsearchPlugin.ts +++ b/plugins/search/plugin-slimsearch/src/node/slimsearchPlugin.ts @@ -2,7 +2,7 @@ import { addViteOptimizeDepsInclude, addViteSsrNoExternal, fromEntries, - getLocaleConfig, + getFullLocaleConfig, } from '@vuepress/helper' import { watch } from 'chokidar' import type { PluginFunction } from 'vuepress/core' @@ -10,7 +10,7 @@ import type { PluginFunction } from 'vuepress/core' import type { SearchIndexStore } from '../shared/index.js' import { getSearchIndexStore } from './generateIndex.js' import { generateWorker } from './generateWorker.js' -import { locales } from './locales.js' +import { slimsearchLocaleInfo } from './locales.js' import type { SlimSearchPluginOptions } from './options.js' import { PathStore } from './pathStore.js' import { @@ -42,11 +42,11 @@ export const slimsearchPlugin = ) .filter((item): item is [string, string] => item !== null) ?? [], ), - __SLIMSEARCH_LOCALES__: getLocaleConfig({ + __SLIMSEARCH_LOCALES__: getFullLocaleConfig({ app, name: PLUGIN_NAME, config: options.locales, - default: locales, + default: slimsearchLocaleInfo, }), __SLIMSEARCH_OPTIONS__: { searchDelay: options.searchDelay ?? 150, diff --git a/plugins/tools/plugin-redirect/src/node/locales.ts b/plugins/tools/plugin-redirect/src/node/locales.ts index 3dbdd6eb77..4e323ab6a7 100644 --- a/plugins/tools/plugin-redirect/src/node/locales.ts +++ b/plugins/tools/plugin-redirect/src/node/locales.ts @@ -1,172 +1,218 @@ -import type { RedirectPluginLocaleConfig } from '../shared/index.js' - -/** Multi language config for redirect popup */ -export const redirectLocales: RedirectPluginLocaleConfig = { - '/en/': { - name: 'English', - hint: 'Your primary language is $1, do you want to switch to it?', - switch: 'Switch to $1', - cancel: 'Cancel', - remember: 'Remember my choice', - }, - - '/zh/': { - name: '简体中文', - hint: '您的首选语言是 $1,是否切换到该语言?', - switch: '切换到 $1', - cancel: '取消', - remember: '记住我的选择', - }, - - '/zh-tw/': { - name: '繁體中文', - hint: '您的首選語言是 $1,是否切換到該語言?', - switch: '切換到 $1', - cancel: '取消', - remember: '記住我的選擇', - }, - - '/de/': { - name: 'Deutsch', - hint: 'Ihre bevorzugte Sprache ist $1, möchten Sie zu dieser wechseln?', - switch: 'Zu $1 wechseln', - cancel: 'Abbrechen', - remember: 'Meine Wahl merken', - }, - - '/de-at/': { - name: 'Deutsch (Österreich)', - hint: 'Ihre bevorzugte Sprache ist $1, möchten Sie zu dieser wechseln?', - switch: 'Zu $1 wechseln', - cancel: 'Abbrechen', - remember: 'Meine Wahl merken', - }, - - '/vi/': { - name: 'Tiếng Việt', - hint: 'Ngôn ngữ chính của bạn là $1, bạn có muốn chuyển sang nó?', - switch: 'Chuyển sang $1', - cancel: 'Hủy', - remember: 'Nhớ lựa chọn của tôi', - }, - - '/uk/': { - name: 'Українська', - hint: 'Вашою основною мовою є $1, чи бажаєте ви переключитися на неї?', - switch: 'Переключитися на $1', - cancel: 'Скасувати', - remember: 'Запам’ятати мій вибір', - }, - - '/ru/': { - name: 'Русский', - hint: 'Ваш основной язык - $1, вы хотите переключиться на него?', - switch: 'Переключиться на $1', - cancel: 'Отмена', - remember: 'Запомнить мой выбор', - }, - - '/br/': { - name: 'Português (Brasil)', - hint: 'A língua principal é $1, deseja mudar para ela?', - switch: 'Mudar para $1', - cancel: 'Cancelar', - remember: 'Lembrar minha escolha', - }, - - '/pl/': { - name: 'Polski', - hint: 'Twoim głównym językiem jest $1, czy chcesz przełączyć się na niego?', - switch: 'Przełącz na $1', - cancel: 'Anuluj', - remember: 'Zapamiętaj moje wybory', - }, - - '/sk/': { - name: 'Slovenčina', - hint: 'Vašou hlavnou jazykom je $1, chcete prepnúť naň?', - switch: 'Prepnúť na $1', - cancel: 'Zrušiť', - remember: 'Zapamätať si moju voľbu', - }, - - '/fr/': { - name: 'Français', - hint: 'Votre langue principale est $1, voulez-vous la changer ?', - switch: 'Changer pour $1', - cancel: 'Annuler', - remember: 'Se souvenir de mon choix', - }, - - '/tr/': { - name: 'Türkçe', - hint: 'Ana diliniz $1, ona geçmek ister misiniz?', - switch: "$1'e geç", - cancel: 'İptal', - remember: 'Seçimimi hatırla', - }, - - '/fi/': { - name: 'Suomi', - hint: 'Pääkielenäsi on $1, haluatko vaihtaa siihen?', - switch: 'Vaihda $1:een', - cancel: 'Peruuta', - remember: 'Muista valintani', - }, - - '/hu/': { - name: 'Magyar', - hint: 'A fő nyelvét $1, szeretné váltani?', - switch: 'Váltás $1', - cancel: 'Mégse', - remember: 'Emlékezzen a választásomra', - }, - - '/id/': { - name: 'Bahasa Indonesia', - hint: 'Bahasa utama Anda adalah $1, apakah Anda ingin beralih ke sana?', - switch: 'Beralih ke $1', - cancel: 'Batal', - remember: 'Ingat pilihan saya', - }, - - '/nl/': { - name: 'Nederlands', - hint: 'Uw primaire taal is $1, wilt u overschakelen?', - switch: 'Overschakelen naar $1', - cancel: 'Annuleren', - remember: 'Onthoud mijn keuze', - }, - - '/ja/': { - name: '日本語', - hint: 'あなたの主要な言語は $1 です。それに切り替えますか?', - switch: '$1 に切り替える', - cancel: 'キャンセル', - remember: '選択を記憶する', - }, - - '/ko/': { - name: '한국어', - hint: '당신의 기본 언어는 $1입니다. 그것으로 전환 하시겠습니까?', - switch: '$1로 전환', - cancel: '취소', - remember: '내 선택 기억하기', - }, - - '/es/': { - name: 'Español', - hint: 'Su idioma principal es $1, ¿desea cambiarlo?', - switch: 'Cambiar a $1', - cancel: 'Cancelar', - remember: 'Recordar mi elección', - }, - - '/pt/': { - name: 'Português', - hint: 'Sua língua principal é $1, deseja mudar para ela?', - switch: 'Mudar para $1', - cancel: 'Cancelar', - remember: 'Lembrar minha escolha', - }, -} +import type { DefaultLocaleInfo } from '@vuepress/helper' +import type { RedirectPluginLocaleData } from '../shared/index.js' + +/** + * Default locale info for `@vuepress/plugin-redirect` + */ +export const redirectLocaleInfo: DefaultLocaleInfo = [ + [ + ['en', 'en-US'], + { + name: 'English', + hint: 'Your primary language is $1, do you want to switch to it?', + switch: 'Switch to $1', + cancel: 'Cancel', + remember: 'Remember my choice', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + name: '简体中文', + hint: '您的首选语言是 $1,是否切换到该语言?', + switch: '切换到 $1', + cancel: '取消', + remember: '记住我的选择', + }, + ], + [ + ['zh', 'zh-TW', 'zh-Hant'], + { + name: '繁體中文', + hint: '您的首選語言是 $1,是否切換到該語言?', + switch: '切換到 $1', + cancel: '取消', + remember: '記住我的選擇', + }, + ], + [ + ['de', 'de-DE'], + { + name: 'Deutsch', + hint: 'Ihre bevorzugte Sprache ist $1, möchten Sie zu dieser wechseln?', + switch: 'Zu $1 wechseln', + cancel: 'Abbrechen', + remember: 'Meine Wahl merken', + }, + ], + [ + ['de-AT'], + { + name: 'Deutsch (Österreich)', + hint: 'Ihre bevorzugte Sprache ist $1, möchten Sie zu dieser wechseln?', + switch: 'Zu $1 wechseln', + cancel: 'Abbrechen', + remember: 'Meine Wahl merken', + }, + ], + [ + ['vi', 'vi-VN'], + { + name: 'Tiếng Việt', + hint: 'Ngôn ngữ chính của bạn là $1, bạn có muốn chuyển sang nó?', + switch: 'Chuyển sang $1', + cancel: 'Hủy', + remember: 'Nhớ lựa chọn của tôi', + }, + ], + [ + ['uk'], + { + name: 'Українська', + hint: 'Вашою основною мовою є $1, чи бажаєте ви переключитися на неї?', + switch: 'Переключитися на $1', + cancel: 'Скасувати', + remember: 'Запам’ятати мій вибір', + }, + ], + [ + ['ru', 'ru-RU'], + { + name: 'Русский', + hint: 'Ваш основной язык - $1, вы хотите переключиться на него?', + switch: 'Переключиться на $1', + cancel: 'Отмена', + remember: 'Запомнить мой выбор', + }, + ], + [ + ['br'], + { + name: 'Português (Brasil)', + hint: 'A língua principal é $1, deseja mudar para ela?', + switch: 'Mudar para $1', + cancel: 'Cancelar', + remember: 'Lembrar minha escolha', + }, + ], + [ + ['pl', 'pl-PL'], + { + name: 'Polski', + hint: 'Twoim głównym językiem jest $1, czy chcesz przełączyć się na niego?', + switch: 'Przełącz na $1', + cancel: 'Anuluj', + remember: 'Zapamiętaj moje wybory', + }, + ], + [ + ['sk', 'sk-SK'], + { + name: 'Slovenčina', + hint: 'Vašou hlavnou jazykom je $1, chcete prepnúť naň?', + switch: 'Prepnúť na $1', + cancel: 'Zrušiť', + remember: 'Zapamätať si moju voľbu', + }, + ], + [ + ['fr', 'fr-FR'], + { + name: 'Français', + hint: 'Votre langue principale est $1, voulez-vous la changer ?', + switch: 'Changer pour $1', + cancel: 'Annuler', + remember: 'Se souvenir de mon choix', + }, + ], + [ + ['tr', 'tr-TR'], + { + name: 'Türkçe', + hint: 'Ana diliniz $1, ona geçmek ister misiniz?', + switch: "$1'e geç", + cancel: 'İptal', + remember: 'Seçimimi hatırla', + }, + ], + [ + ['fi', 'fi-FI'], + { + name: 'Suomi', + hint: 'Pääkielenäsi on $1, haluatko vaihtaa siihen?', + switch: 'Vaihda $1:een', + cancel: 'Peruuta', + remember: 'Muista valintani', + }, + ], + [ + ['hu', 'hu-HU'], + { + name: 'Magyar', + hint: 'A fő nyelvét $1, szeretné váltani?', + switch: 'Váltás $1', + cancel: 'Mégse', + remember: 'Emlékezzen a választásomra', + }, + ], + [ + ['id', 'id-ID'], + { + name: 'Bahasa Indonesia', + hint: 'Bahasa utama Anda adalah $1, apakah Anda ingin beralih ke sana?', + switch: 'Beralih ke $1', + cancel: 'Batal', + remember: 'Ingat pilihan saya', + }, + ], + [ + ['nl', 'nl-NL'], + { + name: 'Nederlands', + hint: 'Uw primaire taal is $1, wilt u overschakelen?', + switch: 'Overschakelen naar $1', + cancel: 'Annuleren', + remember: 'Onthoud mijn keuze', + }, + ], + [ + ['ja', 'ja-JP'], + { + name: '日本語', + hint: 'あなたの主要な言語は $1 です。それに切り替えますか?', + switch: '$1 に切り替える', + cancel: 'キャンセル', + remember: '選択を記憶する', + }, + ], + [ + ['ko', 'ko-KO'], + { + name: '한국어', + hint: '당신의 기본 언어는 $1입니다. 그것으로 전환 하시겠습니까?', + switch: '$1로 전환', + cancel: '취소', + remember: '내 선택 기억하기', + }, + ], + [ + ['es', 'es-ES'], + { + name: 'Español', + hint: 'Su idioma principal es $1, ¿desea cambiarlo?', + switch: 'Cambiar a $1', + cancel: 'Cancelar', + remember: 'Recordar mi elección', + }, + ], + [ + ['/pt'], + { + name: 'Português', + hint: 'Sua língua principal é $1, deseja mudar para ela?', + switch: 'Mudar para $1', + cancel: 'Cancelar', + remember: 'Lembrar minha escolha', + }, + ], +] diff --git a/plugins/tools/plugin-redirect/src/node/redirectPlugin.ts b/plugins/tools/plugin-redirect/src/node/redirectPlugin.ts index c14fc64a09..011db312cd 100644 --- a/plugins/tools/plugin-redirect/src/node/redirectPlugin.ts +++ b/plugins/tools/plugin-redirect/src/node/redirectPlugin.ts @@ -1,6 +1,6 @@ import { addViteSsrNoExternal, - getLocaleConfig, + getFullLocaleConfig, getModulePath, } from '@vuepress/helper' import type { PluginFunction } from 'vuepress/core' @@ -13,7 +13,7 @@ import { import { getRedirectBehaviorConfig } from './getRedirectLocaleConfig.js' import { getRedirectMap } from './getRedirectMap.js' import { handleRedirectTo } from './handleRedirectTo.js' -import { redirectLocales } from './locales.js' +import { redirectLocaleInfo } from './locales.js' import { PLUGIN_NAME, logger } from './logger.js' import type { RedirectPluginOptions } from './types/index.js' @@ -42,11 +42,11 @@ export const redirectPlugin = __REDIRECT_CONFIG__: behaviorConfig, __REDIRECT_DIRECT__: options.switchLocale === 'direct', __REDIRECT_MODAL__: options.switchLocale === 'modal', - __REDIRECT_LOCALES__: getLocaleConfig({ + __REDIRECT_LOCALES__: getFullLocaleConfig({ app, name: 'redirect', config: options.locales, - default: redirectLocales, + default: redirectLocaleInfo, }), }, diff --git a/tools/helper/src/node/locales/config.ts b/tools/helper/src/node/locales/config.ts index 861351d82f..ed66368fd3 100644 --- a/tools/helper/src/node/locales/config.ts +++ b/tools/helper/src/node/locales/config.ts @@ -27,6 +27,7 @@ export const lang2PathConfig = { export const SUPPORTED_LANGS = keys(lang2PathConfig) export const path2langConfig = fromEntries( + // eslint-disable-next-line @typescript-eslint/no-deprecated (SUPPORTED_LANGS as KnownLangCode[]).map((lang) => [ lang2PathConfig[lang], lang, diff --git a/tools/helper/src/node/locales/getFullLocaleConfig.ts b/tools/helper/src/node/locales/getFullLocaleConfig.ts new file mode 100644 index 0000000000..c3e757f257 --- /dev/null +++ b/tools/helper/src/node/locales/getFullLocaleConfig.ts @@ -0,0 +1,105 @@ +import type { App } from 'vuepress' +import type { LocaleConfig, LocaleData } from 'vuepress/shared' +import type { ExactLocaleConfig } from '../../shared/index.js' +import { deepAssign, fromEntries } from '../../shared/index.js' +import { Logger } from '../utils/index.js' +import type { DefaultLocaleInfo } from './types.js' + +/** + * Get locale info + * + * @param app VuePress App + * @param logger Logger + */ +export const getLocaleInfo = ( + app: App, + logger?: Logger, +): [localePath: string, lang: string][] => { + const localeEntries = Object.entries(app.options.locales) + + if (!localeEntries.length) return [['/', app.options.lang]] + + return localeEntries.map(([path, { lang }]) => { + if (lang) return [path, lang] + + if (app.options.debug) { + ;(logger ?? console).warn( + `Locale ${path} is missing lang config, fallback to root lang ${app.options.lang}`, + ) + } + + return [path, app.options.lang] + }) +} + +export const getLocaleData = ( + info: DefaultLocaleInfo, + lang: string, + logger?: Logger, +): T => { + const isShortLang = !lang.includes('-') + + // full search + const localeData = info.find(([langs]) => langs.includes(lang)) + + // find exact match + if (localeData) return localeData[1] + + if (!isShortLang) { + // find short lang match + const shortLang = lang.split('-')[0] + + const shortLocaleData = info.find(([langs]) => langs.includes(shortLang)) + + if (shortLocaleData) return shortLocaleData[1] + } + + ;(logger ?? console).warn(`${lang} is missing it's i18n config`) + + return ( + // en-US + (info.find(([langs]) => langs.includes('en-US')) ?? + // en + info.find(([langs]) => langs.some((item) => item.startsWith('en'))) ?? + // first one + info[0])[1] + ) +} + +export interface GetLocaleConfigOption { + /** VuePress Node app */ + app: App + /** Default locale config */ + default: DefaultLocaleInfo + /** user locale config */ + config?: LocaleConfig | undefined + /** plugin name */ + name?: string +} + +/** + * + * Get final locale config for client + * + * @returns final locale config + */ +export const getFullLocaleConfig = ({ + app, + name, + default: defaultLocaleData, + config: userLocalesConfig = {}, +}: GetLocaleConfigOption): ExactLocaleConfig => { + const logger = new Logger(name) + const localeInfo = getLocaleInfo(app, logger) + + return fromEntries( + localeInfo.map<[string, T]>(([localePath, lang]) => [ + localePath, + deepAssign( + {}, + getLocaleData(defaultLocaleData, lang, logger), + (userLocalesConfig[localePath] ?? {}) as T, + ), + ]), + ) +} diff --git a/tools/helper/src/node/locales/helpers.ts b/tools/helper/src/node/locales/helpers.ts index 95b8a46180..6b6d417c02 100644 --- a/tools/helper/src/node/locales/helpers.ts +++ b/tools/helper/src/node/locales/helpers.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ import type { App } from 'vuepress/core' import type { LocaleConfig, LocaleData } from 'vuepress/shared' import type { ExactLocaleConfig } from '../../shared/index.js' @@ -6,7 +7,11 @@ import { Logger } from '../utils/index.js' import { lang2PathConfig, path2langConfig } from './config.js' import type { KnownLangCode } from './types.js' -/** Infer language from locale path */ +/** + * @deprecated + * + * Infer language from locale path + */ export const inferLocaleLang = ( localePath = '', debug = false, @@ -22,7 +27,11 @@ export const inferLocaleLang = ( return 'en-US' } -/** Infer locale path from language */ +/** + * @deprecated + * + * Infer locale path from language + */ export const inferLocalePath = (lang = '', debug = false): string => { if (lang in lang2PathConfig) return lang2PathConfig[lang as KnownLangCode] @@ -34,6 +43,8 @@ export const inferLocalePath = (lang = '', debug = false): string => { } /** + * @deprecated + * * Get language of root directory * * @param app VuePress Node App @@ -50,6 +61,8 @@ export const getRootLang = (app: App): string => { } /** + * @deprecated + * * Infer locale path from root directory language * * @param app VuePress Node App @@ -59,6 +72,8 @@ export const inferRootLocalePath = (app: App): string => inferLocalePath(getRootLang(app), app.env.isDebug) /** + * @deprecated + * * Get locale paths * * @param app VuePress Node app @@ -67,6 +82,7 @@ export const inferRootLocalePath = (app: App): string => export const getLocalePaths = (app: App): string[] => Array.from(new Set(keys(app.siteData.locales))) +/** @deprecated */ export interface LocaleConfigOptions { /** VuePress Node app */ app: App @@ -79,6 +95,8 @@ export interface LocaleConfigOptions { } /** + * @deprecated + * * Get final locale config for client * * @returns final locale config diff --git a/tools/helper/src/node/locales/index.ts b/tools/helper/src/node/locales/index.ts index eec0c2f47f..12bb45af9e 100644 --- a/tools/helper/src/node/locales/index.ts +++ b/tools/helper/src/node/locales/index.ts @@ -1,2 +1,3 @@ +export * from './getFullLocaleConfig.js' export * from './helpers.js' export type * from './types.js' diff --git a/tools/helper/src/node/locales/types.ts b/tools/helper/src/node/locales/types.ts index e41c2f8fb3..29aceafdc2 100644 --- a/tools/helper/src/node/locales/types.ts +++ b/tools/helper/src/node/locales/types.ts @@ -1,4 +1,17 @@ +import type { LocaleData } from 'vuepress/shared' import type { lang2PathConfig } from './config.js' -/** Types for supported lang codes */ +export type DefaultLocaleInfoItem = [ + lang: string[], + data: T, +] + +export type DefaultLocaleInfo = + DefaultLocaleInfoItem[] + +/** + * @deprecated + * + * Types for supported lang codes + */ export type KnownLangCode = keyof typeof lang2PathConfig diff --git a/tools/helper/tests/node/locales.legacy.spec.ts b/tools/helper/tests/node/locales.legacy.spec.ts new file mode 100644 index 0000000000..8acd9785e3 --- /dev/null +++ b/tools/helper/tests/node/locales.legacy.spec.ts @@ -0,0 +1,487 @@ +/* eslint-disable @typescript-eslint/no-deprecated */ +import { describe, expect, it } from 'vitest' +import type { Bundler } from 'vuepress/core' +import { createBuildApp } from 'vuepress/core' +import { path } from 'vuepress/utils' +import { + getLocaleConfig, + getRootLang, + inferLocaleLang, + inferLocalePath, +} from '../../src/node/locales/helpers.js' +import { emptyTheme } from '../__fixtures__/theme/empty.js' + +const defaultLocaleConfig = { + '/en/': { + text: 'English', + fallback: 'English', + }, + '/zh/': { + text: '中文', + fallback: '中文', + }, + '/ja/': { + text: '日本', + fallback: '日本', + }, + '/test/': { + text: 'Test', + fallback: 'Test', + }, + '/id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, +} + +it('lang2Path() should convert lang to path', () => { + expect(inferLocalePath('en-US')).toEqual('/en/') + expect(inferLocalePath('zh-CN')).toEqual('/zh/') + expect(inferLocalePath('ja-JP')).toEqual('/ja/') + expect(inferLocalePath('id-ID')).toEqual('/id/') + expect(inferLocalePath('nl-NL')).toEqual('/nl/') +}) + +it('path2lang() should convert path to lang', () => { + expect(inferLocaleLang('/en/')).toEqual('en-US') + expect(inferLocaleLang('/zh/')).toEqual('zh-CN') + expect(inferLocaleLang('/ja/')).toEqual('ja-JP') + expect(inferLocaleLang('/id/')).toEqual('id-ID') + expect(inferLocaleLang('/nl/')).toEqual('nl-NL') +}) + +describe('getRootLang() should get root locale lang', () => { + it('should get actual root lang', () => { + const app1 = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en/': { lang: 'en-US' }, + '/nl/': { lang: 'nl-NL' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + const app2 = createBuildApp({ + locales: { + '/': { lang: 'en-US' }, + '/zh/': { lang: 'zh-CN' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + expect(getRootLang(app1)).toEqual('zh-CN') + expect(getRootLang(app2)).toEqual('en-US') + }) + + it('Should fallback to en-US if root locale is absent', () => { + const app = createBuildApp({ + locales: { + '/en/': { lang: 'en-US' }, + '/zh/': { lang: 'zh-CN' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + expect(getRootLang(app)).toEqual('en-US') + }) + + it('Should fallback to en-US if root language is absent', () => { + const app = createBuildApp({ + locales: { + '/': {}, + '/zh/': { lang: 'zh-CN' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + expect(getRootLang(app)).toEqual('en-US') + }) +}) + +describe('getLocaleConfig() should generate locale', () => { + it('set default value for known language', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en/': { lang: 'en-US' }, + '/nl/': { lang: 'nl-NL' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + expect(getLocaleConfig({ app, default: defaultLocaleConfig })).toEqual({ + '/': { + text: '中文', + fallback: '中文', + }, + '/en/': { + text: 'English', + fallback: 'English', + }, + '/ja/': { + text: '日本', + fallback: '日本', + }, + '/id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, + }) + }) + + it('Detect known language with different path', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en-us/': { lang: 'en-US' }, + '/ja-jp/': { lang: 'ja-JP' }, + '/id-id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + expect(getLocaleConfig({ app, default: defaultLocaleConfig })).toEqual({ + '/': { + text: '中文', + fallback: '中文', + }, + '/en-us/': { + text: 'English', + fallback: 'English', + }, + '/ja-jp/': { + text: '日本', + fallback: '日本', + }, + '/id-id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, + }) + }) + + it('use user config if exists', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en/': { lang: 'en-US' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + const config = { + '/': { text: '简体中文' }, + '/en/': { text: 'English (US)' }, + '/id/': { text: 'Indonesia' }, + '/nl/': { text: 'Dutch' }, + } + + const locales = getLocaleConfig({ + app, + default: defaultLocaleConfig, + config, + }) + + expect(locales).toEqual({ + '/': { + text: '简体中文', + fallback: '中文', + }, + '/en/': { + text: 'English (US)', + fallback: 'English', + }, + '/ja/': { + text: '日本', + fallback: '日本', + }, + '/id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, + }) + }) + + describe('handle unknown locale', () => { + it('unknown root language should fallback to first language in default config', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'unknown-Language' }, + '/en/': { lang: 'en-US' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + const locales = getLocaleConfig({ app, default: defaultLocaleConfig }) + + expect(locales).toEqual({ + '/': { + text: 'English', + fallback: 'English', + }, + '/en/': { + text: 'English', + fallback: 'English', + }, + '/ja/': { + text: '日本', + fallback: '日本', + }, + '/id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, + }) + }) + + it('fallback to root language if exists', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en/': { lang: 'en-US' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + '/unknown/': { lang: 'unknown-Language' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + const locales = getLocaleConfig({ app, default: defaultLocaleConfig }) + + expect(locales).toEqual({ + '/': { + text: '中文', + fallback: '中文', + }, + '/en/': { + text: 'English', + fallback: 'English', + }, + '/ja/': { + text: '日本', + fallback: '日本', + }, + '/id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, + '/unknown/': { + text: '中文', + fallback: '中文', + }, + }) + }) + + it('fallback to en-US without root language', () => { + const app = createBuildApp({ + locales: { + '/en/': { lang: 'en-US' }, + '/zh/': { lang: 'zh-CN' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + '/unknown/': { lang: 'unknown-Language' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + const locales = getLocaleConfig({ app, default: defaultLocaleConfig }) + + expect(locales).toEqual({ + '/': { + text: 'English', + fallback: 'English', + }, + '/en/': { + text: 'English', + fallback: 'English', + }, + '/zh/': { + text: '中文', + fallback: '中文', + }, + '/ja/': { + text: '日本', + fallback: '日本', + }, + '/id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, + '/unknown/': { + text: 'English', + fallback: 'English', + }, + }) + }) + }) + + describe('handle new locale', () => { + it('with default locale', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en/': { lang: 'en-US' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + '/test/': { lang: 'test-Language' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + const locales = getLocaleConfig({ app, default: defaultLocaleConfig }) + + expect(locales).toEqual({ + '/': { + text: '中文', + fallback: '中文', + }, + '/en/': { + text: 'English', + fallback: 'English', + }, + '/ja/': { + text: '日本', + fallback: '日本', + }, + '/id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, + '/test/': { + text: 'Test', + fallback: 'Test', + }, + }) + }) + + it('without default', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en/': { lang: 'en-US' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + '/unknown/': { lang: 'unknown-Language' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) + + const config = { + '/unknown/': { text: 'Unknown' }, + } + + const locales = getLocaleConfig({ + app, + config, + default: defaultLocaleConfig, + }) + + expect(locales).toEqual({ + '/': { + text: '中文', + fallback: '中文', + }, + '/en/': { + text: 'English', + fallback: 'English', + }, + '/ja/': { + text: '日本', + fallback: '日本', + }, + '/id/': { + text: 'Indonesia', + fallback: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + fallback: 'Dutch', + }, + '/unknown/': { + text: 'Unknown', + fallback: '中文', + }, + }) + }) + }) +}) diff --git a/tools/helper/tests/node/locales.spec.ts b/tools/helper/tests/node/locales.spec.ts index 24d4b1694e..a4d3098aa4 100644 --- a/tools/helper/tests/node/locales.spec.ts +++ b/tools/helper/tests/node/locales.spec.ts @@ -2,125 +2,56 @@ import { describe, expect, it } from 'vitest' import type { Bundler } from 'vuepress/core' import { createBuildApp } from 'vuepress/core' import { path } from 'vuepress/utils' -import { - getLocaleConfig, - getRootLang, - inferLocaleLang, - inferLocalePath, -} from '../../src/node/locales/helpers.js' +import { getFullLocaleConfig } from '../../src/node/locales/getFullLocaleConfig.js' +import type { DefaultLocaleInfo } from '../../src/node/locales/types.js' import { emptyTheme } from '../__fixtures__/theme/empty.js' -const defaultLocaleConfig = { - '/en/': { - text: 'English', - fallback: 'English', - }, - '/zh/': { - text: '中文', - fallback: '中文', - }, - '/ja/': { - text: '日本', - fallback: '日本', - }, - '/test/': { - text: 'Test', - fallback: 'Test', - }, - '/id/': { - text: 'Indonesia', - fallback: 'Indonesia', - }, - '/nl/': { - text: 'Dutch', - fallback: 'Dutch', - }, -} - -it('lang2Path() should convert lang to path', () => { - expect(inferLocalePath('en-US')).toEqual('/en/') - expect(inferLocalePath('zh-CN')).toEqual('/zh/') - expect(inferLocalePath('ja-JP')).toEqual('/ja/') - expect(inferLocalePath('id-ID')).toEqual('/id/') - expect(inferLocalePath('nl-NL')).toEqual('/nl/') -}) - -it('path2lang() should convert path to lang', () => { - expect(inferLocaleLang('/en/')).toEqual('en-US') - expect(inferLocaleLang('/zh/')).toEqual('zh-CN') - expect(inferLocaleLang('/ja/')).toEqual('ja-JP') - expect(inferLocaleLang('/id/')).toEqual('id-ID') - expect(inferLocaleLang('/nl/')).toEqual('nl-NL') -}) - -describe('getRootLang() should get root locale lang', () => { - it('should get actual root lang', () => { - const app1 = createBuildApp({ - locales: { - '/': { lang: 'zh-CN' }, - '/en/': { lang: 'en-US' }, - '/nl/': { lang: 'nl-NL' }, - '/ja/': { lang: 'ja-JP' }, - '/id/': { lang: 'id-ID' }, - }, - source: path.resolve(__dirname, './__fixtures__/src'), - bundler: {} as Bundler, - theme: emptyTheme, - }) - - const app2 = createBuildApp({ - locales: { - '/': { lang: 'en-US' }, - '/zh/': { lang: 'zh-CN' }, - '/ja/': { lang: 'ja-JP' }, - '/id/': { lang: 'id-ID' }, - '/nl/': { lang: 'nl-NL' }, - }, - source: path.resolve(__dirname, './__fixtures__/src'), - bundler: {} as Bundler, - theme: emptyTheme, - }) - - expect(getRootLang(app1)).toEqual('zh-CN') - expect(getRootLang(app2)).toEqual('en-US') - }) - - it('Should fallback to en-US if root locale is absent', () => { - const app = createBuildApp({ - locales: { - '/en/': { lang: 'en-US' }, - '/zh/': { lang: 'zh-CN' }, - '/ja/': { lang: 'ja-JP' }, - '/id/': { lang: 'id-ID' }, - '/nl/': { lang: 'nl-NL' }, - }, - source: path.resolve(__dirname, './__fixtures__/src'), - bundler: {} as Bundler, - theme: emptyTheme, - }) - - expect(getRootLang(app)).toEqual('en-US') - }) - - it('Should fallback to en-US if root language is absent', () => { - const app = createBuildApp({ - locales: { - '/': {}, - '/zh/': { lang: 'zh-CN' }, - '/ja/': { lang: 'ja-JP' }, - '/id/': { lang: 'id-ID' }, - '/nl/': { lang: 'nl-NL' }, - }, - source: path.resolve(__dirname, './__fixtures__/src'), - bundler: {} as Bundler, - theme: emptyTheme, - }) - - expect(getRootLang(app)).toEqual('en-US') - }) -}) - -describe('getLocaleConfig() should generate locale', () => { +const defaultLocaleInfo: DefaultLocaleInfo<{ text: string; label: string }> = [ + [ + ['en', 'en-US'], + { + text: 'English', + label: 'US English', + }, + ], + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + text: '简体中文', + label: '简体中文', + }, + ], + [ + ['zh-TW', 'zh-Hant'], + { + text: '繁體中文', + label: '繁體中文', + }, + ], + [ + ['ja', 'ja-JP'], + { + text: '日本', + label: '日本', + }, + ], + [ + ['id', 'id-ID'], + { + text: 'Indonesia', + label: 'Indonesia', + }, + ], + [ + ['nl', 'nl-NL'], + { + text: 'Dutch', + label: 'Dutch', + }, + ], +] + +describe('getFullLocaleConfig() should generate locale', () => { it('set default value for known language', () => { const app = createBuildApp({ locales: { @@ -135,69 +66,54 @@ describe('getLocaleConfig() should generate locale', () => { theme: emptyTheme, }) - expect(getLocaleConfig({ app, default: defaultLocaleConfig })).toEqual({ + expect(getFullLocaleConfig({ app, default: defaultLocaleInfo })).toEqual({ '/': { - text: '中文', - fallback: '中文', + text: '简体中文', + label: '简体中文', }, '/en/': { text: 'English', - fallback: 'English', + label: 'US English', }, '/ja/': { text: '日本', - fallback: '日本', + label: '日本', }, '/id/': { text: 'Indonesia', - fallback: 'Indonesia', + label: 'Indonesia', }, '/nl/': { text: 'Dutch', - fallback: 'Dutch', + label: 'Dutch', }, }) }) - it('Detect known language with different path', () => { + it("Fallback to short lang if exact lang doesn't exist", () => { const app = createBuildApp({ locales: { '/': { lang: 'zh-CN' }, - '/en-us/': { lang: 'en-US' }, - '/ja-jp/': { lang: 'ja-JP' }, - '/id-id/': { lang: 'id-ID' }, - '/nl/': { lang: 'nl-NL' }, + '/en/': { lang: 'en-CA' }, }, source: path.resolve(__dirname, './__fixtures__/src'), bundler: {} as Bundler, theme: emptyTheme, }) - expect(getLocaleConfig({ app, default: defaultLocaleConfig })).toEqual({ + expect(getFullLocaleConfig({ app, default: defaultLocaleInfo })).toEqual({ '/': { - text: '中文', - fallback: '中文', + text: '简体中文', + label: '简体中文', }, - '/en-us/': { + '/en/': { text: 'English', - fallback: 'English', - }, - '/ja-jp/': { - text: '日本', - fallback: '日本', - }, - '/id-id/': { - text: 'Indonesia', - fallback: 'Indonesia', - }, - '/nl/': { - text: 'Dutch', - fallback: 'Dutch', + label: 'US English', }, }) }) - it('use user config if exists', () => { + it('prefer user config if exists', () => { const app = createBuildApp({ locales: { '/': { lang: 'zh-CN' }, @@ -212,44 +128,44 @@ describe('getLocaleConfig() should generate locale', () => { }) const config = { - '/': { text: '简体中文' }, - '/en/': { text: 'English (US)' }, + '/': { text: '中文' }, + '/en/': { text: 'English' }, '/id/': { text: 'Indonesia' }, '/nl/': { text: 'Dutch' }, } - const locales = getLocaleConfig({ + const locales = getFullLocaleConfig({ app, - default: defaultLocaleConfig, + default: defaultLocaleInfo, config, }) expect(locales).toEqual({ '/': { - text: '简体中文', - fallback: '中文', + text: '中文', + label: '简体中文', }, '/en/': { - text: 'English (US)', - fallback: 'English', + text: 'English', + label: 'US English', }, '/ja/': { text: '日本', - fallback: '日本', + label: '日本', }, '/id/': { text: 'Indonesia', - fallback: 'Indonesia', + label: 'Indonesia', }, '/nl/': { text: 'Dutch', - fallback: 'Dutch', + label: 'Dutch', }, }) }) describe('handle unknown locale', () => { - it('unknown root language should fallback to first language in default config', () => { + it('should fallback to en', () => { const app = createBuildApp({ locales: { '/': { lang: 'unknown-Language' }, @@ -257,230 +173,238 @@ describe('getLocaleConfig() should generate locale', () => { '/ja/': { lang: 'ja-JP' }, '/id/': { lang: 'id-ID' }, '/nl/': { lang: 'nl-NL' }, + '/unknown/': { lang: 'unknown-Language2' }, }, source: path.resolve(__dirname, './__fixtures__/src'), bundler: {} as Bundler, theme: emptyTheme, }) - const locales = getLocaleConfig({ app, default: defaultLocaleConfig }) + const locales = getFullLocaleConfig({ app, default: defaultLocaleInfo }) expect(locales).toEqual({ '/': { text: 'English', - fallback: 'English', - }, - '/en/': { - text: 'English', - fallback: 'English', - }, - '/ja/': { - text: '日本', - fallback: '日本', - }, - '/id/': { - text: 'Indonesia', - fallback: 'Indonesia', - }, - '/nl/': { - text: 'Dutch', - fallback: 'Dutch', - }, - }) - }) - - it('fallback to root language if exists', () => { - const app = createBuildApp({ - locales: { - '/': { lang: 'zh-CN' }, - '/en/': { lang: 'en-US' }, - '/ja/': { lang: 'ja-JP' }, - '/id/': { lang: 'id-ID' }, - '/nl/': { lang: 'nl-NL' }, - '/unknown/': { lang: 'unknown-Language' }, - }, - source: path.resolve(__dirname, './__fixtures__/src'), - bundler: {} as Bundler, - theme: emptyTheme, - }) - - const locales = getLocaleConfig({ app, default: defaultLocaleConfig }) - - expect(locales).toEqual({ - '/': { - text: '中文', - fallback: '中文', + label: 'US English', }, '/en/': { text: 'English', - fallback: 'English', + label: 'US English', }, '/ja/': { text: '日本', - fallback: '日本', + label: '日本', }, '/id/': { text: 'Indonesia', - fallback: 'Indonesia', + label: 'Indonesia', }, '/nl/': { text: 'Dutch', - fallback: 'Dutch', + label: 'Dutch', }, '/unknown/': { - text: '中文', - fallback: '中文', + text: 'English', + label: 'US English', }, }) }) - it('fallback to en-US without root language', () => { + it('should fallback to first language without en', () => { const app = createBuildApp({ locales: { + '/': { lang: 'unknown-Language' }, '/en/': { lang: 'en-US' }, '/zh/': { lang: 'zh-CN' }, '/ja/': { lang: 'ja-JP' }, '/id/': { lang: 'id-ID' }, '/nl/': { lang: 'nl-NL' }, - '/unknown/': { lang: 'unknown-Language' }, + '/unknown/': { lang: 'unknown-Language2' }, }, source: path.resolve(__dirname, './__fixtures__/src'), bundler: {} as Bundler, theme: emptyTheme, }) - const locales = getLocaleConfig({ app, default: defaultLocaleConfig }) + const defaultLocaleInfoWithOutEn: DefaultLocaleInfo<{ + text: string + label: string + }> = [ + [ + ['zh', 'zh-CN', 'zh-Hans'], + { + text: '简体中文', + label: '简体中文', + }, + ], + [ + ['zh-TW', 'zh-Hant'], + { + text: '繁體中文', + label: '繁體中文', + }, + ], + [ + ['ja', 'ja-JP'], + { + text: '日本', + label: '日本', + }, + ], + [ + ['id', 'id-ID'], + { + text: 'Indonesia', + label: 'Indonesia', + }, + ], + [ + ['nl', 'nl-NL'], + { + text: 'Dutch', + label: 'Dutch', + }, + ], + ] + + const locales = getFullLocaleConfig({ + app, + default: defaultLocaleInfoWithOutEn, + }) expect(locales).toEqual({ '/': { - text: 'English', - fallback: 'English', + text: '简体中文', + label: '简体中文', }, '/en/': { - text: 'English', - fallback: 'English', + text: '简体中文', + label: '简体中文', }, '/zh/': { - text: '中文', - fallback: '中文', + text: '简体中文', + label: '简体中文', }, '/ja/': { text: '日本', - fallback: '日本', + label: '日本', }, '/id/': { text: 'Indonesia', - fallback: 'Indonesia', + label: 'Indonesia', }, '/nl/': { text: 'Dutch', - fallback: 'Dutch', + label: 'Dutch', }, '/unknown/': { - text: 'English', - fallback: 'English', + text: '简体中文', + label: '简体中文', }, }) }) }) - describe('handle new locale', () => { - it('with default locale', () => { - const app = createBuildApp({ - locales: { - '/': { lang: 'zh-CN' }, - '/en/': { lang: 'en-US' }, - '/ja/': { lang: 'ja-JP' }, - '/id/': { lang: 'id-ID' }, - '/nl/': { lang: 'nl-NL' }, - '/test/': { lang: 'test-Language' }, - }, - source: path.resolve(__dirname, './__fixtures__/src'), - bundler: {} as Bundler, - theme: emptyTheme, - }) - - const locales = getLocaleConfig({ app, default: defaultLocaleConfig }) + it('drop unused options', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en/': { lang: 'en-US' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) - expect(locales).toEqual({ + const locales = getFullLocaleConfig({ + app, + default: defaultLocaleInfo, + config: { '/': { - text: '中文', - fallback: '中文', - }, - '/en/': { - text: 'English', - fallback: 'English', - }, - '/ja/': { - text: '日本', - fallback: '日本', - }, - '/id/': { - text: 'Indonesia', - fallback: 'Indonesia', - }, - '/nl/': { - text: 'Dutch', - fallback: 'Dutch', + text: '简体中文', + label: '简体中文', }, '/test/': { text: 'Test', - fallback: 'Test', + label: 'Test', }, - }) - }) - - it('without default', () => { - const app = createBuildApp({ - locales: { - '/': { lang: 'zh-CN' }, - '/en/': { lang: 'en-US' }, - '/ja/': { lang: 'ja-JP' }, - '/id/': { lang: 'id-ID' }, - '/nl/': { lang: 'nl-NL' }, - '/unknown/': { lang: 'unknown-Language' }, + '/test2/': { + text: 'Test2', }, - source: path.resolve(__dirname, './__fixtures__/src'), - bundler: {} as Bundler, - theme: emptyTheme, - }) + }, + }) - const config = { - '/unknown/': { text: 'Unknown' }, - } + expect(locales).toEqual({ + '/': { + text: '简体中文', + label: '简体中文', + }, + '/en/': { + text: 'English', + label: 'US English', + }, + }) + }) - const locales = getLocaleConfig({ - app, - config, - default: defaultLocaleConfig, - }) + it('handle new locale', () => { + const app = createBuildApp({ + locales: { + '/': { lang: 'zh-CN' }, + '/en/': { lang: 'en-US' }, + '/ja/': { lang: 'ja-JP' }, + '/id/': { lang: 'id-ID' }, + '/nl/': { lang: 'nl-NL' }, + '/test/': { lang: 'test-Language' }, + '/test2/': { lang: 'test-Language2' }, + }, + source: path.resolve(__dirname, './__fixtures__/src'), + bundler: {} as Bundler, + theme: emptyTheme, + }) - expect(locales).toEqual({ - '/': { - text: '中文', - fallback: '中文', - }, - '/en/': { - text: 'English', - fallback: 'English', - }, - '/ja/': { - text: '日本', - fallback: '日本', - }, - '/id/': { - text: 'Indonesia', - fallback: 'Indonesia', - }, - '/nl/': { - text: 'Dutch', - fallback: 'Dutch', + const locales = getFullLocaleConfig({ + app, + default: defaultLocaleInfo, + config: { + '/test/': { + text: 'Test', + label: 'Test', }, - '/unknown/': { - text: 'Unknown', - fallback: '中文', + '/test2/': { + text: 'Test2', }, - }) + }, + }) + + expect(locales).toEqual({ + '/': { + text: '简体中文', + label: '简体中文', + }, + '/en/': { + text: 'English', + label: 'US English', + }, + '/ja/': { + text: '日本', + label: '日本', + }, + '/id/': { + text: 'Indonesia', + label: 'Indonesia', + }, + '/nl/': { + text: 'Dutch', + label: 'Dutch', + }, + '/test/': { + text: 'Test', + label: 'Test', + }, + '/test2/': { + text: 'Test2', + label: 'US English', + }, }) }) }) From f62a06b003d3d858ac149bc15ed3df297dbcc275 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Sat, 21 Dec 2024 01:02:52 +0800 Subject: [PATCH 05/22] chore: prefer using siteData (#316) --- .../blog/plugin-feed/src/node/addFeedLinks.ts | 23 +++++++------------ .../blog/plugin-feed/src/node/feed/item.ts | 2 +- .../src/node/getFeedChannelOptions.ts | 3 +-- .../plugin-feed/src/node/getFeedFilenames.ts | 2 +- .../blog/plugin-feed/src/node/getFeedLinks.ts | 2 +- .../pwa/plugin-pwa/src/node/getManifest.ts | 19 ++++++--------- .../plugin-pwa/src/node/injectLinksToHead.ts | 8 +++---- plugins/pwa/plugin-pwa/src/node/pwaPlugin.ts | 5 ++-- .../tests/node/injectLinksToHead.spec.ts | 11 ++++++--- .../src/node/docsearchPlugin.ts | 2 +- .../src/node/generateDescription.ts | 2 +- plugins/seo/plugin-seo/src/node/getOGPInfo.ts | 19 ++++----------- .../seo/plugin-seo/src/node/utils/getLinks.ts | 2 +- .../seo/plugin-sitemap/src/node/getInfo.ts | 2 +- .../src/node/googleTagManagerPlugin.ts | 2 +- .../tools/plugin-redirect/src/cli/index.ts | 2 +- .../src/node/getRedirectLocaleConfig.ts | 2 +- .../src/node/handleRedirectTo.ts | 3 +-- .../src/node/bundler/customizeDevServer.ts | 2 +- tools/helper/src/node/locales/helpers.ts | 4 ++-- 20 files changed, 49 insertions(+), 68 deletions(-) diff --git a/plugins/blog/plugin-feed/src/node/addFeedLinks.ts b/plugins/blog/plugin-feed/src/node/addFeedLinks.ts index 9c3f7d7b37..8f4ceb7db4 100644 --- a/plugins/blog/plugin-feed/src/node/addFeedLinks.ts +++ b/plugins/blog/plugin-feed/src/node/addFeedLinks.ts @@ -9,8 +9,7 @@ export const addFeedLinks = ( app: App, options: ResolvedFeedOptionsMap, ): void => { - const { base } = app.options - const { siteData } = app + const { base, title, locales, head } = app.siteData const localePaths = keys(options) // there is only one language, so we append it to siteData @@ -31,28 +30,22 @@ export const addFeedLinks = ( href: getUrl(hostname, base, fileName), title: `${ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - siteData.title || siteData.locales['/']?.title || '' + title || locales['/']?.title || '' } ${name} Feed`, }, ] // add atom link if (atom) - siteData.head.push( - getHeadItem('Atom', atomOutputFilename, 'application/atom+xml'), - ) + head.push(getHeadItem('Atom', atomOutputFilename, 'application/atom+xml')) // add json link if (json) - siteData.head.push( - getHeadItem('JSON', jsonOutputFilename, 'application/json'), - ) + head.push(getHeadItem('JSON', jsonOutputFilename, 'application/json')) // add rss link if (rss) - siteData.head.push( - getHeadItem('RSS', rssOutputFilename, 'application/rss+xml'), - ) + head.push(getHeadItem('RSS', rssOutputFilename, 'application/rss+xml')) } // there are multiple languages, so we should append to page else { @@ -76,10 +69,10 @@ export const addFeedLinks = ( href: getUrl(localeOptions.hostname, base, fileName), title: `${ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - siteData.locales[pathLocale]?.title || - siteData.title || + locales[pathLocale]?.title || + title || // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - siteData.locales['/']?.title || + locales['/']?.title || '' } ${name} Feed`, }, diff --git a/plugins/blog/plugin-feed/src/node/feed/item.ts b/plugins/blog/plugin-feed/src/node/feed/item.ts index 1102c2c5b6..e54d581564 100644 --- a/plugins/blog/plugin-feed/src/node/feed/item.ts +++ b/plugins/blog/plugin-feed/src/node/feed/item.ts @@ -41,7 +41,7 @@ export class FeedItem { private readonly page: FeedPage, private readonly hostname: string, ) { - this.base = this.app.options.base + this.base = this.app.siteData.base this.frontmatter = page.frontmatter this.getter = options.getter ?? {} // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing diff --git a/plugins/blog/plugin-feed/src/node/getFeedChannelOptions.ts b/plugins/blog/plugin-feed/src/node/getFeedChannelOptions.ts index e1a70359e7..ed9e74cc4f 100644 --- a/plugins/blog/plugin-feed/src/node/getFeedChannelOptions.ts +++ b/plugins/blog/plugin-feed/src/node/getFeedChannelOptions.ts @@ -9,8 +9,7 @@ export const getFeedChannelOptions = ( options: FeedPluginOptions, localePath = '', ): FeedChannelOptions => { - const { base } = app.options - const { title, description, lang, locales } = app.siteData + const { base, title, description, lang, locales } = app.siteData const { channel: { icon: channelIcon, image: channelImage, ...channel } = {}, hostname, diff --git a/plugins/blog/plugin-feed/src/node/getFeedFilenames.ts b/plugins/blog/plugin-feed/src/node/getFeedFilenames.ts index 050207310f..bbfcf5d9f4 100644 --- a/plugins/blog/plugin-feed/src/node/getFeedFilenames.ts +++ b/plugins/blog/plugin-feed/src/node/getFeedFilenames.ts @@ -49,7 +49,7 @@ export const getFeedLinks = ( options: ResolvedFeedOptions, localePath: string, ): FeedLinks => { - const { base } = app.options + const { base } = app.siteData const { hostname } = options const { atomOutputFilename, diff --git a/plugins/blog/plugin-feed/src/node/getFeedLinks.ts b/plugins/blog/plugin-feed/src/node/getFeedLinks.ts index 6415f8b139..aeb1e82b61 100644 --- a/plugins/blog/plugin-feed/src/node/getFeedLinks.ts +++ b/plugins/blog/plugin-feed/src/node/getFeedLinks.ts @@ -17,7 +17,7 @@ export const getFeedLinks = ( options: ResolvedFeedOptions, localePath: string, ): FeedLinks => { - const { base } = app.options + const { base } = app.siteData const { hostname } = options const { atomOutputFilename, diff --git a/plugins/pwa/plugin-pwa/src/node/getManifest.ts b/plugins/pwa/plugin-pwa/src/node/getManifest.ts index 8379dbcdde..50178f8d06 100644 --- a/plugins/pwa/plugin-pwa/src/node/getManifest.ts +++ b/plugins/pwa/plugin-pwa/src/node/getManifest.ts @@ -7,8 +7,9 @@ export const getManifest = async ( app: App, options: PwaPluginOptions, ): Promise => { - const { siteData } = app - const { base } = app.options + const { base, title, description, lang, locales } = app.siteData + + const rootLocale = locales['/'] ?? {} const userManifestPath = app.dir.source( '.vuepress/public/manifest.webmanifest', @@ -24,17 +25,11 @@ export const getManifest = async ( ) as AppManifest const manifest: AppManifest = { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - name: siteData.title || siteData.locales['/']?.title || 'Site', - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - short_name: siteData.title || siteData.locales['/']?.title || 'Site', + name: title || rootLocale.title || 'Site', + short_name: title || rootLocale.title || 'Site', description: - siteData.description || - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - siteData.locales['/']?.description || - 'A site built with vuepress', - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - lang: app.siteData.locales['/']?.lang ?? app.siteData.lang, + description || rootLocale.description || 'A site built with vuepress', + lang: rootLocale.lang ?? lang, start_url: base, scope: base, diff --git a/plugins/pwa/plugin-pwa/src/node/injectLinksToHead.ts b/plugins/pwa/plugin-pwa/src/node/injectLinksToHead.ts index 50172b8f4c..2b6bf80f56 100644 --- a/plugins/pwa/plugin-pwa/src/node/injectLinksToHead.ts +++ b/plugins/pwa/plugin-pwa/src/node/injectLinksToHead.ts @@ -1,12 +1,12 @@ -import type { App, HeadConfig } from 'vuepress/core' +import type { App } from 'vuepress/core' import { isPlainObject } from 'vuepress/shared' import type { PwaPluginOptions } from './options.js' export const injectLinksToHead = ( app: App, { favicon, manifest, themeColor = '#46bd87', apple }: PwaPluginOptions, -): HeadConfig[] => { - const { base, head } = app.options +): void => { + const { base, head } = app.siteData const metaKeys: string[] = [] const linkKeys: string[] = [] @@ -75,6 +75,4 @@ export const injectLinksToHead = ( } else if (apple !== false && fallBackIcon) { setLink('apple-touch-icon', fallBackIcon) } - - return head } diff --git a/plugins/pwa/plugin-pwa/src/node/pwaPlugin.ts b/plugins/pwa/plugin-pwa/src/node/pwaPlugin.ts index b5da64f9a4..7ec3623613 100644 --- a/plugins/pwa/plugin-pwa/src/node/pwaPlugin.ts +++ b/plugins/pwa/plugin-pwa/src/node/pwaPlugin.ts @@ -18,7 +18,8 @@ export const pwaPlugin = (app) => { if (app.env.isDebug) logger.info('Options:', options) - const { base, shouldPrefetch = true } = app.options + const { shouldPrefetch = true } = app.options + const { base } = app.siteData if (options.appendBase) appendBase(base, options) @@ -27,7 +28,7 @@ export const pwaPlugin = 'The plugin will register service worker to handle assets, so we recommend you to set "shouldPrefetch: false" in VuePress config file.', ) - app.options.head = injectLinksToHead(app, options) + injectLinksToHead(app, options) return { name: PLUGIN_NAME, diff --git a/plugins/pwa/plugin-pwa/tests/node/injectLinksToHead.spec.ts b/plugins/pwa/plugin-pwa/tests/node/injectLinksToHead.spec.ts index e7bbf25e46..37e7d2e5b2 100644 --- a/plugins/pwa/plugin-pwa/tests/node/injectLinksToHead.spec.ts +++ b/plugins/pwa/plugin-pwa/tests/node/injectLinksToHead.spec.ts @@ -64,7 +64,9 @@ describe('Test head function', () => { }, }) - expect(injectLinksToHead(app, options)).toEqual([ + injectLinksToHead(app, options) + + expect(app.siteData.head).toEqual([ [ 'meta', { @@ -176,7 +178,9 @@ describe('Test head function', () => { }, } - expect(injectLinksToHead(app, optionsWithManifest)).toEqual([ + injectLinksToHead(app, optionsWithManifest) + + expect(app.siteData.head).toEqual([ [ 'meta', { @@ -240,7 +244,8 @@ describe('Test head function', () => { }, }) - expect(injectLinksToHead(app, options)).toEqual([ + injectLinksToHead(app, options) + expect(app.siteData.head).toEqual([ [ 'link', { diff --git a/plugins/search/plugin-docsearch/src/node/docsearchPlugin.ts b/plugins/search/plugin-docsearch/src/node/docsearchPlugin.ts index 01827f9501..7f7d84c206 100644 --- a/plugins/search/plugin-docsearch/src/node/docsearchPlugin.ts +++ b/plugins/search/plugin-docsearch/src/node/docsearchPlugin.ts @@ -26,7 +26,7 @@ export const docsearchPlugin = ({ name: PLUGIN_NAME, define: (app) => ({ - __DOCSEARCH_INDEX_BASE__: indexBase || app.options.base, + __DOCSEARCH_INDEX_BASE__: indexBase || app.siteData.base, __DOCSEARCH_OPTIONS__: options, }), diff --git a/plugins/seo/plugin-seo/src/node/generateDescription.ts b/plugins/seo/plugin-seo/src/node/generateDescription.ts index 7249fccf5a..73c1adf1fb 100644 --- a/plugins/seo/plugin-seo/src/node/generateDescription.ts +++ b/plugins/seo/plugin-seo/src/node/generateDescription.ts @@ -13,7 +13,7 @@ export const generateDescription = ( ? (page.data.excerpt ?? page.contentRendered) : page.contentRendered - const pageText = getText(content, app.options.base, { + const pageText = getText(content, app.siteData.base, { length: 180, singleLine: true, }) diff --git a/plugins/seo/plugin-seo/src/node/getOGPInfo.ts b/plugins/seo/plugin-seo/src/node/getOGPInfo.ts index 21fef202d5..94bafceb98 100644 --- a/plugins/seo/plugin-seo/src/node/getOGPInfo.ts +++ b/plugins/seo/plugin-seo/src/node/getOGPInfo.ts @@ -29,10 +29,7 @@ export const getOGPInfo = ( twitterID?: SeoPluginOptions['twitterID'] }, ): SeoContent => { - const { - options: { base }, - siteData, - } = app + const { base, title: siteTitle, locales } = app.siteData const { frontmatter: { author: pageAuthor, @@ -44,13 +41,6 @@ export const getOGPInfo = ( data: { git = {} }, } = page - const title = - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - siteData.locales[page.pathLocale]?.title || - siteData.title || - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - siteData.locales['/']?.title || - '' const author = getSEOAuthor(pageAuthor || globalAuthor) const modifiedTime = git.updatedTime ? new Date(git.updatedTime).toISOString() @@ -59,20 +49,21 @@ export const getOGPInfo = ( const articleTitle = page.title const cover = getCover(page, app, hostname) const images = getImages(page, app, hostname) - const locales = getAlternatePaths(page, app) + const alternateLocalePaths = getAlternatePaths(page, app) const publishedTime = getDate(date)?.toISOString() const ogImage = cover || images[0] || fallBackImage const defaultOGP: SeoContent = { 'og:url': getUrl(hostname, base, page.path), - 'og:site_name': title, + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + 'og:site_name': locales[page.pathLocale]?.title || siteTitle, 'og:title': articleTitle, 'og:description': page.frontmatter.description || '', 'og:type': isArticle(page) ? 'article' : 'website', 'og:image': ogImage, 'og:locale': page.lang, - 'og:locale:alternate': locales.map(({ lang }) => lang), + 'og:locale:alternate': alternateLocalePaths.map(({ lang }) => lang), ...(modifiedTime ? { 'og:updated_time': modifiedTime } : {}), ...(restrictions ? { 'og:restrictions:age': restrictions } : {}), ...(twitterID ? { 'twitter:creator': twitterID } : {}), diff --git a/plugins/seo/plugin-seo/src/node/utils/getLinks.ts b/plugins/seo/plugin-seo/src/node/utils/getLinks.ts index bbe437d39f..52eab17e5a 100644 --- a/plugins/seo/plugin-seo/src/node/utils/getLinks.ts +++ b/plugins/seo/plugin-seo/src/node/utils/getLinks.ts @@ -23,5 +23,5 @@ export const getAlternateLinks = ( ): { lang: string; path: string }[] => getAlternatePaths(page, app).map(({ lang, path }) => ({ lang, - path: getUrl(hostname, app.options.base, path), + path: getUrl(hostname, app.siteData.base, path), })) diff --git a/plugins/seo/plugin-sitemap/src/node/getInfo.ts b/plugins/seo/plugin-sitemap/src/node/getInfo.ts index ea69916e0b..3e5bdc9696 100644 --- a/plugins/seo/plugin-sitemap/src/node/getInfo.ts +++ b/plugins/seo/plugin-sitemap/src/node/getInfo.ts @@ -51,7 +51,7 @@ export const getSitemapInfos = ( ? new Date(page.data.git.updatedTime).toISOString() : '', } = options - const { base, locales } = app.options + const { base, locales } = app.siteData const pageLocalesMap = getPagesLocaleMap(app) diff --git a/plugins/tools/plugin-google-tag-manager/src/node/googleTagManagerPlugin.ts b/plugins/tools/plugin-google-tag-manager/src/node/googleTagManagerPlugin.ts index baf4631e25..2134a8b9f5 100644 --- a/plugins/tools/plugin-google-tag-manager/src/node/googleTagManagerPlugin.ts +++ b/plugins/tools/plugin-google-tag-manager/src/node/googleTagManagerPlugin.ts @@ -29,7 +29,7 @@ export const googleTagManagerPlugin = ...plugin, onInitialized: () => { - app.options.head.push([ + app.siteData.head.push([ 'script', {}, `\ diff --git a/plugins/tools/plugin-redirect/src/cli/index.ts b/plugins/tools/plugin-redirect/src/cli/index.ts index 2890f82580..6fdb122e0a 100644 --- a/plugins/tools/plugin-redirect/src/cli/index.ts +++ b/plugins/tools/plugin-redirect/src/cli/index.ts @@ -108,7 +108,7 @@ cli await Promise.all( app.pages.map((page) => { const redirectUrl = `${removeEndingSlash(commandOptions.hostname)}${ - app.options.base + app.siteData.base }${removeLeadingSlash(page.path)}` const destLocation = path.join( outputFolder, diff --git a/plugins/tools/plugin-redirect/src/node/getRedirectLocaleConfig.ts b/plugins/tools/plugin-redirect/src/node/getRedirectLocaleConfig.ts index aaebc32807..93cfdbffe0 100644 --- a/plugins/tools/plugin-redirect/src/node/getRedirectLocaleConfig.ts +++ b/plugins/tools/plugin-redirect/src/node/getRedirectLocaleConfig.ts @@ -18,7 +18,7 @@ export const getRedirectBehaviorConfig = ( app: App, options: RedirectPluginOptions, ): RedirectBehaviorConfig => { - const { locales } = app.options + const { locales } = app.siteData const config = deepAssign( fromEntries( diff --git a/plugins/tools/plugin-redirect/src/node/handleRedirectTo.ts b/plugins/tools/plugin-redirect/src/node/handleRedirectTo.ts index e89247cba2..a056447cf8 100644 --- a/plugins/tools/plugin-redirect/src/node/handleRedirectTo.ts +++ b/plugins/tools/plugin-redirect/src/node/handleRedirectTo.ts @@ -4,8 +4,7 @@ import { normalizePath } from '../shared/normalizePath.js' import type { RedirectPluginFrontmatter } from './types/index.js' export const handleRedirectTo = ({ frontmatter }: Page, app: App): void => { - const { base } = app.options - + const { base } = app.siteData const { redirectTo } = frontmatter as RedirectPluginFrontmatter if (redirectTo) { diff --git a/tools/helper/src/node/bundler/customizeDevServer.ts b/tools/helper/src/node/bundler/customizeDevServer.ts index 2d14e72e94..8b7e7a2f1e 100644 --- a/tools/helper/src/node/bundler/customizeDevServer.ts +++ b/tools/helper/src/node/bundler/customizeDevServer.ts @@ -51,7 +51,7 @@ export const customizeDevServer = ( path, }: DevServerOptions, ): void => { - const { base } = app.options + const { base } = app.siteData const bundlerName = getBundlerName(app) // in dev diff --git a/tools/helper/src/node/locales/helpers.ts b/tools/helper/src/node/locales/helpers.ts index 6b6d417c02..91a514099f 100644 --- a/tools/helper/src/node/locales/helpers.ts +++ b/tools/helper/src/node/locales/helpers.ts @@ -122,10 +122,10 @@ export const getLocaleConfig = ({ .map<[string, T]>((localePath) => { const defaultLocaleData = (defaultLocalesConfig[localePath] as T | undefined) ?? - (inferLocalePath(app.options.locales[localePath].lang) === '/' + (inferLocalePath(app.siteData.locales[localePath].lang) === '/' ? null : defaultLocalesConfig[ - inferLocalePath(app.options.locales[localePath].lang) + inferLocalePath(app.siteData.locales[localePath].lang) ]) if (!defaultLocaleData) From dae01ac99d5804b74158cc0ca69e6cec9686654b Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Sat, 21 Dec 2024 14:52:06 +0800 Subject: [PATCH 06/22] fix(plugin-photo-swipe): avoid loading multiple instances at startup (#317) --- .../src/client/composables/usePhotoSwipe.ts | 114 ++++++++++-------- 1 file changed, 64 insertions(+), 50 deletions(-) diff --git a/plugins/features/plugin-photo-swipe/src/client/composables/usePhotoSwipe.ts b/plugins/features/plugin-photo-swipe/src/client/composables/usePhotoSwipe.ts index 6f7cc1b277..5a9529285b 100644 --- a/plugins/features/plugin-photo-swipe/src/client/composables/usePhotoSwipe.ts +++ b/plugins/features/plugin-photo-swipe/src/client/composables/usePhotoSwipe.ts @@ -55,71 +55,85 @@ export const usePhotoSwipe = ({ scrollToClose, })) + let photoSwipeLoader: Promise | null = null let photoSwipeId = 0 let photoSwipe: PhotoSwipe | null = null - const handlePhotoSwipe = async (event: MouseEvent): Promise => { + const initPhotoSwipe = async (event: MouseEvent): Promise => { const el = event.target as HTMLImageElement - if (imageSelector.value && el.matches(imageSelector.value)) { - photoSwipe?.destroy() - - const { default: PhotoSwipe } = await import( - /* webpackChunkName: "photo-swipe" */ 'photoswipe' - ) - - const images = Array.from( - document.querySelectorAll(imageSelector.value), - ) - const currentIndex = images.findIndex((image) => image === el) - - const dataSource = images.map((image) => ({ - html: LOADING_ICON, - element: image, - msrc: image.src, - })) - - dataSource.splice(currentIndex, 1, await resolveImageInfoFromElement(el)) - - const id = Date.now() - - photoSwipeId = id - photoSwipe = new PhotoSwipe({ - preloaderDelay: 0, - showHideAnimationType: 'zoom', - ...options, - dataSource, - index: currentIndex, - ...(scrollToClose - ? { closeOnVerticalDrag: true, wheelToZoom: false } - : {}), - }) - - setupPhotoSwipe(photoSwipe, { download, fullscreen }) + if ( + // not enabled + !imageSelector.value || + // Photoswipe is not being loaded + !photoSwipeLoader || + // not an matched element + !el.matches(imageSelector.value) + ) + return + + // there is an active instance + if (photoSwipeId !== 0) photoSwipe!.destroy() + + const id = Date.now() + const PhotoSwipeConstructor = await photoSwipeLoader + + const images = Array.from( + document.querySelectorAll(imageSelector.value), + ) + const dataSource = images.map((image) => ({ + html: LOADING_ICON, + element: image, + msrc: image.src, + })) + + const index = images.findIndex((image) => image === el) + + photoSwipe = new PhotoSwipeConstructor({ + preloaderDelay: 0, + showHideAnimationType: 'zoom', + ...options, + dataSource, + index, + ...(scrollToClose + ? { closeOnVerticalDrag: true, wheelToZoom: false } + : {}), + }) + photoSwipeId = id - photoSwipe.init() + setupPhotoSwipe(photoSwipe, { download, fullscreen }) - photoSwipe.on('destroy', () => { - photoSwipe = null - photoSwipeId = 0 - }) + photoSwipe.init() - images.forEach((image, index) => { - if (index === currentIndex || photoSwipeId !== id) return + photoSwipe.on('destroy', () => { + photoSwipe = null + photoSwipeId = 0 + }) - void resolveImageInfoFromElement(image).then((data) => { - dataSource.splice(index, 1, data) - photoSwipe?.refreshSlideContent(index) - }) - }) - } + void images.map((image, imageIndex) => + resolveImageInfoFromElement(image).then((data) => { + if (photoSwipeId !== id) return + dataSource.splice(imageIndex, 1, data) + photoSwipe?.refreshSlideContent(imageIndex) + }), + ) } onMounted(() => { - useEventListener('click', handlePhotoSwipe) + const rIC = + 'requestIdleCallback' in window ? window.requestIdleCallback : setTimeout + + useEventListener('click', initPhotoSwipe) useEventListener('wheel', () => { if (options.value.scrollToClose) photoSwipe?.close() }) + rIC(() => { + photoSwipeLoader = import( + /* webpackChunkName: "photo-swipe" */ 'photoswipe' + ).then(({ default: _PhotoSwipe }) => { + return _PhotoSwipe + }) + }) }) onUnmounted(() => { From 60ad03bccb2afbe25b810c5b98649c905831c740 Mon Sep 17 00:00:00 2001 From: Mister-Hope Date: Thu, 26 Dec 2024 00:41:38 +0800 Subject: [PATCH 07/22] feat(theme-default)!: avoid using theme-default-content and remove this class --- themes/theme-default/src/client/components/VPHome.vue | 4 ++-- themes/theme-default/src/client/components/VPPage.vue | 4 ++-- themes/theme-default/src/client/layouts/Layout.vue | 2 +- themes/theme-default/src/client/layouts/NotFound.vue | 2 +- themes/theme-default/src/client/styles/content/normalize.scss | 2 +- .../theme-default/src/client/styles/external-link-icon.scss | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/themes/theme-default/src/client/components/VPHome.vue b/themes/theme-default/src/client/components/VPHome.vue index 7bf2c3f9a0..2c8ca1acc7 100644 --- a/themes/theme-default/src/client/components/VPHome.vue +++ b/themes/theme-default/src/client/components/VPHome.vue @@ -9,7 +9,7 @@ import { Content } from 'vuepress/client'
-
+
@@ -30,7 +30,7 @@ import { Content } from 'vuepress/client' padding-left: 1.5rem; } - .theme-default-content { + [vp-content] { margin: 0; padding: 0; } diff --git a/themes/theme-default/src/client/components/VPPage.vue b/themes/theme-default/src/client/components/VPPage.vue index 63fcd2bbed..2180e772b4 100644 --- a/themes/theme-default/src/client/components/VPPage.vue +++ b/themes/theme-default/src/client/components/VPPage.vue @@ -19,7 +19,7 @@ setupHeaders()
-
+
@@ -61,7 +61,7 @@ setupHeaders() padding-left: 0; } - .theme-default-content { + [vp-content] { @include mixins.content-wrapper; & { diff --git a/themes/theme-default/src/client/layouts/Layout.vue b/themes/theme-default/src/client/layouts/Layout.vue index b7bc7c78d2..e97fe9f1e5 100644 --- a/themes/theme-default/src/client/layouts/Layout.vue +++ b/themes/theme-default/src/client/layouts/Layout.vue @@ -189,7 +189,7 @@ const onBeforeLeave = scrollPromise.pending } // adjust heading margin and padding; - .theme-default-content { + [vp-content] { h1, h2, h3, diff --git a/themes/theme-default/src/client/layouts/NotFound.vue b/themes/theme-default/src/client/layouts/NotFound.vue index 86da222b5c..6dc83b308c 100644 --- a/themes/theme-default/src/client/layouts/NotFound.vue +++ b/themes/theme-default/src/client/layouts/NotFound.vue @@ -15,7 +15,7 @@ const homeText = themeLocale.value.backToHome ?? 'Back to home'