feat: 增强多语言支持
This commit is contained in:
parent
530797d61a
commit
5ff9570018
@ -3,6 +3,7 @@ import { computed } from 'vue'
|
||||
import type { PlumeThemePageData } from '../../shared/index.js'
|
||||
import { ensureStartingSlash } from '../utils/index.js'
|
||||
import { useThemeData } from './themeData.js'
|
||||
import { normalizePath } from './sidebar.js'
|
||||
|
||||
export function useLangs({
|
||||
removeCurrent = true,
|
||||
@ -20,18 +21,34 @@ export function useLangs({
|
||||
}
|
||||
})
|
||||
|
||||
const addPath = computed(() => {
|
||||
if (page.value.frontmatter.home || (page.value.type && page.value.type !== 'friends'))
|
||||
return true
|
||||
|
||||
return correspondingLink
|
||||
})
|
||||
|
||||
const getBlogLink = (locale: string) => {
|
||||
const blog = theme.value.locales?.[`/${locale}/`]?.blog
|
||||
const defaultBlog = theme.value.locales?.['/']?.blog ?? theme.value.blog
|
||||
const link = blog?.link ? blog.link : normalizePath(`${locale}${defaultBlog?.link || 'blog/'}`)
|
||||
return link
|
||||
}
|
||||
|
||||
const localeLinks = computed(() =>
|
||||
Object.entries(theme.value.locales || {}).flatMap(([key, value]) =>
|
||||
removeCurrent && currentLang.value.label === value.selectLanguageName
|
||||
? []
|
||||
: {
|
||||
text: value.selectLanguageName,
|
||||
link: normalizeLink(
|
||||
key,
|
||||
correspondingLink,
|
||||
page.value.path.slice(currentLang.value.link.length - 1),
|
||||
true,
|
||||
),
|
||||
link: page.value.isBlogPost
|
||||
? getBlogLink(key)
|
||||
: normalizeLink(
|
||||
key,
|
||||
addPath.value,
|
||||
page.value.path.slice(currentLang.value.link.length - 1),
|
||||
true,
|
||||
),
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
@ -13,6 +13,8 @@ import type {
|
||||
PlumeThemePluginOptions,
|
||||
} from '../shared/index.js'
|
||||
import { getCurrentDirname, getPackage, nanoid, pathJoin } from './utils.js'
|
||||
import { resolveNotesList } from './resolveNotesList.js'
|
||||
import { resolveLocaleOptions } from './resolveLocaleOptions.js'
|
||||
|
||||
export default function autoFrontmatter(
|
||||
app: App,
|
||||
@ -21,18 +23,12 @@ export default function autoFrontmatter(
|
||||
): AutoFrontmatterOptions {
|
||||
const sourceDir = app.dir.source()
|
||||
const pkg = getPackage()
|
||||
const { locales = {}, avatar, article: articlePrefix = '/article/' } = localeOption
|
||||
const { locales = {}, article: articlePrefix = '/article/' } = localeOption
|
||||
const { frontmatter } = options
|
||||
|
||||
const localesNotesDirs = Object.keys(app.siteData.locales || {})
|
||||
.map((locale) => {
|
||||
// fixed: #15
|
||||
const notes = locales[locale]?.notes
|
||||
if (!notes)
|
||||
return ''
|
||||
|
||||
return notes.dir ? pathJoin(locale, notes.dir).replace(/^\//, '') : ''
|
||||
})
|
||||
const avatar = resolveLocaleOptions(localeOption, 'avatar')
|
||||
const notesList = resolveNotesList(localeOption)
|
||||
const localesNotesDirs = notesList
|
||||
.map(notes => notes.dir?.replace(/^\//, ''))
|
||||
.filter(Boolean)
|
||||
|
||||
const baseFrontmatter: FrontmatterObject = {
|
||||
@ -58,7 +54,7 @@ export default function autoFrontmatter(
|
||||
return resolveLocalePath(localeOption.locales!, file)
|
||||
}
|
||||
const notesByLocale = (locale: string) => {
|
||||
const notes = locales[locale]?.notes || localeOption.notes
|
||||
const notes = resolveLocaleOptions(localeOption, 'notes', locale)
|
||||
if (notes === false)
|
||||
return undefined
|
||||
return notes
|
||||
@ -162,7 +158,13 @@ export default function autoFrontmatter(
|
||||
if (permalink)
|
||||
return permalink
|
||||
const locale = resolveLocale(filepath)
|
||||
return pathJoin(locale, articlePrefix, nanoid(), '/')
|
||||
const prefix = resolveLocaleOptions(localeOption, 'article', locale, false)
|
||||
const args: string[] = []
|
||||
prefix
|
||||
? args.push(prefix)
|
||||
: args.push(locale, articlePrefix)
|
||||
|
||||
return pathJoin(...args, nanoid(), '/')
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import path from 'node:path'
|
||||
import type { App, PluginConfig } from '@vuepress/core'
|
||||
import { activeHeaderLinksPlugin } from '@vuepress/plugin-active-header-links'
|
||||
import { docsearchPlugin } from '@vuepress/plugin-docsearch'
|
||||
@ -28,62 +27,56 @@ import type {
|
||||
PlumeThemePluginOptions,
|
||||
} from '../shared/index.js'
|
||||
import autoFrontmatter from './autoFrontmatter.js'
|
||||
import { resolveLocaleOptions } from './resolveLocaleOptions.js'
|
||||
import { pathJoin } from './utils.js'
|
||||
import { resolveNotesList } from './resolveNotesList.js'
|
||||
|
||||
export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeOptions: PlumeThemeLocaleOptions): PluginConfig {
|
||||
export function setupPlugins(
|
||||
app: App,
|
||||
options: PlumeThemePluginOptions,
|
||||
localeOptions: PlumeThemeLocaleOptions,
|
||||
): PluginConfig {
|
||||
const isProd = !app.env.isDev
|
||||
|
||||
const locales = (localeOptions.locales || {}) as PlumeThemeLocaleOptions
|
||||
const localeNotesDirs = Object.keys(locales)
|
||||
.map((locale) => {
|
||||
const dir = locales[locale].notes?.dir || ''
|
||||
return dir
|
||||
? path.join(locale, dir, '**').replace(/\\+/g, '/').replace(/^\//, '')
|
||||
: ''
|
||||
})
|
||||
const notesList = resolveNotesList(localeOptions)
|
||||
const notesDirList = notesList
|
||||
.map(notes => notes.dir && pathJoin(notes.dir, '**').replace(/^\//, ''))
|
||||
.filter(Boolean)
|
||||
|
||||
const blog = resolveLocaleOptions(localeOptions, 'blog')
|
||||
|
||||
const plugins: PluginConfig = [
|
||||
palettePlugin({ preset: 'sass' }),
|
||||
|
||||
themeDataPlugin({
|
||||
themeData: {
|
||||
...localeOptions,
|
||||
notes: localeOptions.notes
|
||||
? { dir: localeOptions.notes.dir, link: localeOptions.notes.link }
|
||||
: undefined,
|
||||
} as any,
|
||||
}),
|
||||
themeDataPlugin({ themeData: localeOptions }),
|
||||
|
||||
autoFrontmatterPlugin(autoFrontmatter(app, options, localeOptions)),
|
||||
|
||||
blogDataPlugin({
|
||||
include: localeOptions.blog?.include ?? ['**/*.md'],
|
||||
include: blog?.include ?? ['**/*.md'],
|
||||
exclude: [
|
||||
'**/{README,readme,index}.md',
|
||||
'.vuepress/',
|
||||
'node_modules/',
|
||||
...(localeOptions.blog?.exclude ?? []),
|
||||
...localeNotesDirs,
|
||||
...(blog?.exclude ?? []),
|
||||
...notesDirList,
|
||||
].filter(Boolean),
|
||||
sortBy: 'createTime',
|
||||
excerpt: true,
|
||||
pageFilter(page: any) {
|
||||
if (page.frontmatter.article !== undefined)
|
||||
return !!page.frontmatter.article
|
||||
|
||||
return true
|
||||
},
|
||||
extendBlogData(page: any) {
|
||||
return {
|
||||
categoryList: page.data.categoryList,
|
||||
tags: page.frontmatter.tags,
|
||||
sticky: page.frontmatter.sticky,
|
||||
createTime: page.data.frontmatter.createTime,
|
||||
lang: page.lang,
|
||||
}
|
||||
},
|
||||
pageFilter: (page: any) => page.frontmatter.article !== undefined
|
||||
? !!page.frontmatter.article
|
||||
: true,
|
||||
extendBlogData: (page: any) => ({
|
||||
categoryList: page.data.categoryList,
|
||||
tags: page.frontmatter.tags,
|
||||
sticky: page.frontmatter.sticky,
|
||||
createTime: page.data.frontmatter.createTime,
|
||||
lang: page.lang,
|
||||
}),
|
||||
}),
|
||||
|
||||
notesDataPlugin(notesList),
|
||||
|
||||
iconifyPlugin(),
|
||||
|
||||
contentUpdatePlugin(),
|
||||
@ -99,37 +92,27 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
if (options.readingTime !== false)
|
||||
plugins.push(readingTimePlugin(options.readingTime || {}))
|
||||
|
||||
if (localeOptions.notes)
|
||||
plugins.push(notesDataPlugin(localeOptions.notes))
|
||||
|
||||
if (options.nprogress !== false)
|
||||
plugins.push(nprogressPlugin())
|
||||
|
||||
if (options.git !== false) {
|
||||
plugins.push(gitPlugin({
|
||||
createdTime: false,
|
||||
updatedTime: localeOptions.lastUpdated !== false,
|
||||
contributors: localeOptions.contributors !== false,
|
||||
updatedTime: resolveLocaleOptions(localeOptions, 'lastUpdated') !== false,
|
||||
contributors: resolveLocaleOptions(localeOptions, 'contributors') !== false,
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.mediumZoom !== false) {
|
||||
plugins.push(mediumZoomPlugin({
|
||||
selector: '.plume-content > img, .plume-content :not(a) > img',
|
||||
zoomOptions: {
|
||||
background: 'var(--vp-c-bg)',
|
||||
},
|
||||
zoomOptions: { background: 'var(--vp-c-bg)' },
|
||||
delay: 300,
|
||||
}))
|
||||
}
|
||||
|
||||
if (options.caniuse !== false) {
|
||||
plugins.push(caniusePlugin(
|
||||
options.caniuse || {
|
||||
mode: 'embed',
|
||||
},
|
||||
))
|
||||
}
|
||||
if (options.caniuse !== false)
|
||||
plugins.push(caniusePlugin(options.caniuse || { mode: 'embed' }))
|
||||
|
||||
if (options.externalLinkIcon !== false) {
|
||||
plugins.push(externalLinkIconPlugin({
|
||||
@ -150,14 +133,11 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
plugins.push(searchPlugin(options.search))
|
||||
|
||||
if (options.docsearch !== false && !options.search) {
|
||||
if (options.docsearch?.appId && options.docsearch?.apiKey) {
|
||||
if (options.docsearch?.appId && options.docsearch?.apiKey)
|
||||
plugins.push(docsearchPlugin(options.docsearch))
|
||||
}
|
||||
else {
|
||||
console.error(
|
||||
'docsearch plugin: appId and apiKey are both required',
|
||||
)
|
||||
}
|
||||
|
||||
else
|
||||
console.error('docsearch plugin: appId and apiKey are both required')
|
||||
}
|
||||
|
||||
if (options.shikiji !== false) {
|
||||
@ -180,7 +160,6 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
{
|
||||
hint: true, // info note tip warning danger details
|
||||
codetabs: true,
|
||||
tabs: true,
|
||||
align: true,
|
||||
mark: true,
|
||||
tasklist: true,
|
||||
@ -188,6 +167,7 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
attrs: true,
|
||||
sup: true,
|
||||
sub: true,
|
||||
katex: true,
|
||||
} as MarkdownEnhanceOptions,
|
||||
options.markdownEnhance || {},
|
||||
),
|
||||
@ -200,16 +180,15 @@ export function setupPlugins(app: App, options: PlumeThemePluginOptions, localeO
|
||||
if (options.baiduTongji !== false && options.baiduTongji?.key)
|
||||
plugins.push(baiduTongjiPlugin(options.baiduTongji))
|
||||
|
||||
if (options.sitemap !== false && localeOptions.hostname && isProd) {
|
||||
plugins.push(sitemapPlugin({
|
||||
hostname: localeOptions.hostname,
|
||||
}))
|
||||
}
|
||||
const hostname = resolveLocaleOptions(localeOptions, 'hostname')
|
||||
|
||||
if (options.seo !== false && localeOptions.hostname && isProd) {
|
||||
if (options.sitemap !== false && hostname && isProd)
|
||||
plugins.push(sitemapPlugin({ hostname }))
|
||||
|
||||
if (options.seo !== false && hostname && isProd) {
|
||||
plugins.push(seoPlugin({
|
||||
hostname: localeOptions.hostname || '',
|
||||
author: localeOptions.avatar?.name,
|
||||
hostname,
|
||||
author: resolveLocaleOptions(localeOptions, 'avatar')?.name,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
26
theme/src/node/resolveLocaleOptions.ts
Normal file
26
theme/src/node/resolveLocaleOptions.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import type { PlumeThemeLocaleOptions } from '../shared/index.js'
|
||||
import { normalizePath } from './utils.js'
|
||||
|
||||
export function resolveLocaleOptions<
|
||||
T extends PlumeThemeLocaleOptions = PlumeThemeLocaleOptions,
|
||||
K extends Exclude<keyof T, 'locales'> = Exclude<keyof T, 'locales'>,
|
||||
>(options: T, key: K, locale = '', fallback = true): T[K] | undefined {
|
||||
const locales = options.locales
|
||||
|
||||
if (!locales)
|
||||
return options[key]
|
||||
|
||||
locale = !locale || locale === '/' ? '/' : normalizePath(`/${locale}/`)
|
||||
|
||||
const localeOptions = locales[locale]
|
||||
const fallbackLocaleOptions = locales['/']
|
||||
if (!localeOptions)
|
||||
return fallback ? options[key] : undefined
|
||||
|
||||
const _key = key as keyof typeof localeOptions
|
||||
const fallbackData = (fallbackLocaleOptions[_key] ?? options[key]) as T[K]
|
||||
|
||||
const value = localeOptions[_key] as T[K]
|
||||
|
||||
return value ?? (fallback ? fallbackData : undefined)
|
||||
}
|
||||
15
theme/src/node/resolveNotesList.ts
Normal file
15
theme/src/node/resolveNotesList.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import type { NotesDataOptions } from '@vuepress-plume/plugin-notes-data'
|
||||
import type { PlumeThemeLocaleOptions } from '../shared/index.js'
|
||||
import { resolveLocaleOptions } from './resolveLocaleOptions.js'
|
||||
|
||||
export function resolveNotesList(options: PlumeThemeLocaleOptions) {
|
||||
const locales = options.locales || {}
|
||||
const notesList: NotesDataOptions[] = []
|
||||
|
||||
for (const locale of Object.keys(locales)) {
|
||||
const notes = resolveLocaleOptions(options, 'notes', locale, false)
|
||||
notes && notesList.push(notes)
|
||||
}
|
||||
|
||||
return notesList
|
||||
}
|
||||
@ -7,15 +7,16 @@ import type {
|
||||
PlumeThemePageData,
|
||||
} from '../shared/index.js'
|
||||
import { pathJoin } from './utils.js'
|
||||
import { resolveLocaleOptions } from './resolveLocaleOptions.js'
|
||||
|
||||
export async function setupPage(
|
||||
app: App,
|
||||
localeOption: PlumeThemeLocaleOptions,
|
||||
) {
|
||||
const locales = Object.keys(app.siteData.locales || {})
|
||||
const defaultBlog = resolveLocaleOptions(localeOption, 'blog')
|
||||
for (const [, locale] of locales.entries()) {
|
||||
const blog = localeOption.locales?.[locale]?.blog
|
||||
const defaultBlog = localeOption.blog
|
||||
const blog = resolveLocaleOptions(localeOption, 'blog', locale, false)
|
||||
const link = blog?.link
|
||||
? blog.link
|
||||
: pathJoin('/', locale, defaultBlog?.link || '/blog/')
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user