Skip to content

Commit

Permalink
merge feat-i18n
Browse files Browse the repository at this point in the history
fix: don't break when locales are not used
fix: make navbar title link to current locale
feat: allow customizing locale link in navbar
feat: allow overriding theme config
feat: support overriding head based on current locale
feat: support customizing title and description
feat: add lang attribute to html based on route
feat: show current and available langs on navbar
fix: refactor types to support locales
fix: group label customization to theme.translations
  • Loading branch information
brc-dd committed Sep 9, 2022
1 parent 530d7b4 commit a0daafe
Show file tree
Hide file tree
Showing 29 changed files with 263 additions and 339 deletions.
18 changes: 6 additions & 12 deletions src/client/app/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import {
PageData,
SiteData,
resolveSiteDataByRoute,
createTitle
createTitle,
DefaultTheme
} from '../shared.js'
import { withBase } from './utils.js'

export const dataSymbol: InjectionKey<VitePressData> = Symbol()

Expand All @@ -19,7 +19,7 @@ export interface VitePressData<T = any> {
title: Ref<string>
description: Ref<string>
lang: Ref<string>
localePath: Ref<string>
localeIndex: Ref<string>
}

// site data is a singleton
Expand All @@ -39,7 +39,7 @@ if (import.meta.hot) {
// per-app data
export function initData(route: Route): VitePressData {
const site = computed(() =>
resolveSiteDataByRoute(siteDataRef.value, route.path)
resolveSiteDataByRoute(siteDataRef.value, route.data.relativePath)
)

return {
Expand All @@ -48,13 +48,7 @@ export function initData(route: Route): VitePressData {
page: computed(() => route.data),
frontmatter: computed(() => route.data.frontmatter),
lang: computed(() => site.value.lang),
localePath: computed(() => {
const { langs, lang } = site.value
const path = Object.keys(langs).find(
(langPath) => langs[langPath].lang === lang
)
return withBase(path || '/')
}),
localeIndex: computed(() => site.value.localeIndex || 'root'),
title: computed(() => {
return createTitle(site.value, route.data)
}),
Expand All @@ -64,7 +58,7 @@ export function initData(route: Route): VitePressData {
}
}

export function useData<T = any>(): VitePressData<T> {
export function useData<T = DefaultTheme.Config>(): VitePressData<T> {
const data = inject(dataSymbol)
if (!data) {
throw new Error('vitepress data not properly injected in app')
Expand Down
2 changes: 1 addition & 1 deletion src/client/app/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { siteDataRef } from './data.js'
import { inBrowser, EXTERNAL_URL_RE } from '../shared.js'

export { inBrowser }
export { inBrowser } from '../shared.js'

/**
* Join two paths by resolving the slash collision.
Expand Down
3 changes: 1 addition & 2 deletions src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ export type {
PageData,
SiteData,
HeadConfig,
Header,
LocaleConfig
Header
} from '../../types/shared.js'

// composables
Expand Down
8 changes: 6 additions & 2 deletions src/client/theme-default/components/VPAlgoliaSearchBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import { default as docsearch } from '@docsearch/js'
import { onMounted } from 'vue'
import { useRouter, useRoute, useData } from 'vitepress'
const props = defineProps<{
algolia: DefaultTheme.AlgoliaSearchOptions
}>()
const router = useRouter()
const route = useRoute()
const { theme, site } = useData()
const { site } = useData()
onMounted(() => {
initialize(theme.value.algolia)
initialize(props.algolia)
setTimeout(poll, 16)
})
Expand Down
9 changes: 6 additions & 3 deletions src/client/theme-default/components/VPCarbonAds.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import { ref, watch, onMounted } from 'vue'
import { useData } from 'vitepress'
import { useAside } from '../composables/aside.js'
const { theme } = useData()
const carbonOptions = theme.value.carbonAds
const props = defineProps<{
carbonAds: DefaultTheme.CarbonAdsOptions
}>()
const carbonOptions = props.carbonAds
const { isAsideEnabled } = useAside()
const container = ref()
Expand Down
2 changes: 1 addition & 1 deletion src/client/theme-default/components/VPDocAside.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const { theme } = useData()
<div class="spacer" />

<slot name="aside-ads-before" />
<VPDocAsideCarbonAds v-if="theme.carbonAds" />
<VPDocAsideCarbonAds v-if="theme.carbonAds" :carbonAds="theme.carbonAds" />
<slot name="aside-ads-after" />

<slot name="aside-bottom" />
Expand Down
7 changes: 6 additions & 1 deletion src/client/theme-default/components/VPDocAsideCarbonAds.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
<script setup lang="ts">
import type { DefaultTheme } from 'vitepress/theme'
import { defineAsyncComponent } from 'vue'
const props = defineProps<{
carbonAds: DefaultTheme.CarbonAdsOptions
}>()
const VPCarbonAds = __CARBON__
? defineAsyncComponent(() => import('./VPCarbonAds.vue'))
: () => null
</script>

<template>
<div class="VPDocAsideCarbonAds">
<VPCarbonAds />
<VPCarbonAds :carbonAds="props" />
</div>
</template>
2 changes: 1 addition & 1 deletion src/client/theme-default/components/VPDocAsideOutline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function handleClick({ target: el }: Event) {
<div class="outline-marker" ref="marker" />

<div class="outline-title">
{{ theme.outlineTitle || 'On this page' }}
{{ theme.translations?.outlineTitle || 'On this page' }}
</div>

<nav aria-labelledby="doc-outline-aria-label">
Expand Down
4 changes: 2 additions & 2 deletions src/client/theme-default/components/VPDocFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ const showFooter = computed(() => {
<div v-if="control.prev || control.next" class="prev-next">
<div class="pager">
<a v-if="control.prev" class="pager-link prev" :href="normalizeLink(control.prev.link)">
<span class="desc">{{ theme.docFooter?.prev ?? 'Previous page' }}</span>
<span class="desc">{{ theme.translations?.docFooter?.prev || 'Previous page' }}</span>
<span class="title">{{ control.prev.text }} </span>
</a>
</div>
<div class="pager" :class="{ 'has-prev': control.prev }">
<a v-if="control.next" class="pager-link next" :href="normalizeLink(control.next.link)">
<span class="desc">{{ theme.docFooter?.next ?? 'Next page' }}</span>
<span class="desc">{{ theme.translations?.docFooter?.next || 'Next page' }}</span>
<span class="title">{{ control.next.text }}</span>
</a>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ onMounted(() => {

<template>
<p class="VPLastUpdated">
{{ theme.lastUpdatedText ?? 'Last updated' }}:
{{ theme.translations?.lastUpdatedText || 'Last updated' }}:
<time :datatime="isoDatetime">{{ datetime }}</time>
</p>
</template>
Expand Down
8 changes: 6 additions & 2 deletions src/client/theme-default/components/VPLocalNav.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts" setup>
import { useData } from 'vitepress'
import { useSidebar } from '../composables/sidebar.js'
import VPIconAlignLeft from './icons/VPIconAlignLeft.vue'
Expand All @@ -10,6 +11,7 @@ defineEmits<{
(e: 'open-menu'): void
}>()
const { theme } = useData()
const { hasSidebar } = useSidebar()
function scrollToTop() {
Expand All @@ -26,11 +28,13 @@ function scrollToTop() {
@click="$emit('open-menu')"
>
<VPIconAlignLeft class="menu-icon" />
<span class="menu-text">Menu</span>
<span class="menu-text">
{{ theme.translations?.sidebarMenuLabel || 'Menu' }}
</span>
</button>

<a class="top-link" href="#" @click="scrollToTop">
Return to top
{{ theme.translations?.returnToTopLabel || 'Return to top' }}
</a>
</div>
</template>
Expand Down
12 changes: 8 additions & 4 deletions src/client/theme-default/components/VPNavBarExtra.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,27 @@ import VPFlyout from './VPFlyout.vue'
import VPMenuLink from './VPMenuLink.vue'
import VPSwitchAppearance from './VPSwitchAppearance.vue'
import VPSocialLinks from './VPSocialLinks.vue'
import { useLangs } from '../composables/langs.js'
const { site, theme } = useData()
const { localeLinks, currentLang } = useLangs()
</script>

<template>
<VPFlyout class="VPNavBarExtra" label="extra navigation">
<div v-if="theme.localeLinks" class="group">
<p class="trans-title">{{ theme.localeLinks.text }}</p>
<div v-if="localeLinks.length && currentLang.label" class="group">
<p class="trans-title">{{ currentLang.label }}</p>

<template v-for="locale in theme.localeLinks.items" :key="locale.link">
<template v-for="locale in localeLinks" :key="locale.link">
<VPMenuLink :item="locale" />
</template>
</div>

<div v-if="site.appearance" class="group">
<div class="item appearance">
<p class="label">Appearance</p>
<p class="label">
{{ theme.translations?.darkModeSwitchLabel || 'Appearance' }}
</p>
<div class="appearance-action">
<VPSwitchAppearance />
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/client/theme-default/components/VPNavBarSearch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function load() {

<template>
<div v-if="theme.algolia" class="VPNavBarSearch">
<VPAlgoliaSearchBox v-if="loaded" />
<VPAlgoliaSearchBox v-if="loaded" :algolia="theme.algolia" />

<div v-else id="docsearch" @click="load">
<button
Expand Down
7 changes: 5 additions & 2 deletions src/client/theme-default/components/VPNavBarTitle.vue
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
<script setup lang="ts">
import { useData } from 'vitepress'
import { useSidebar } from '../composables/sidebar.js'
import { useLangs } from '../composables/langs.js'
import { normalizeLink } from '../support/utils.js'
import VPImage from './VPImage.vue'
const { site, theme } = useData()
const { hasSidebar } = useSidebar()
const { currentLang } = useLangs()
</script>

<template>
<div class="VPNavBarTitle" :class="{ 'has-sidebar': hasSidebar }">
<a class="title" :href="site.base">
<a class="title" :href="normalizeLink(currentLang.link)">
<slot name="nav-bar-title-before" />
<VPImage class="logo" :image="theme.logo" />
<VPImage v-if="theme.logo" class="logo" :image="theme.logo" />
<template v-if="theme.siteTitle">{{ theme.siteTitle }}</template>
<template v-else-if="theme.siteTitle === undefined">{{ site.title }}</template>
<slot name="nav-bar-title-after" />
Expand Down
10 changes: 5 additions & 5 deletions src/client/theme-default/components/VPNavBarTranslations.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
<script lang="ts" setup>
import { useData } from 'vitepress'
import VPIconLanguages from './icons/VPIconLanguages.vue'
import VPFlyout from './VPFlyout.vue'
import VPMenuLink from './VPMenuLink.vue'
import { useLangs } from '../composables/langs.js'
const { theme } = useData()
const { localeLinks, currentLang } = useLangs()
</script>

<template>
<VPFlyout
v-if="theme.localeLinks"
v-if="localeLinks.length && currentLang.label"
class="VPNavBarTranslations"
:icon="VPIconLanguages"
>
<div class="items">
<p class="title">{{ theme.localeLinks.text }}</p>
<p class="title">{{ currentLang.label }}</p>

<template v-for="locale in theme.localeLinks.items" :key="locale.link">
<template v-for="locale in localeLinks" :key="locale.link">
<VPMenuLink :item="locale" />
</template>
</div>
Expand Down
6 changes: 4 additions & 2 deletions src/client/theme-default/components/VPNavScreenAppearance.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
import { useData } from 'vitepress'
import VPSwitchAppearance from './VPSwitchAppearance.vue'
const { site } = useData()
const { site, theme } = useData()
</script>

<template>
<div v-if="site.appearance" class="VPNavScreenAppearance">
<p class="text">Appearance</p>
<p class="text">
{{ theme.translations?.darkModeSwitchLabel || 'Appearance' }}
</p>
<VPSwitchAppearance />
</div>
</template>
Expand Down
15 changes: 9 additions & 6 deletions src/client/theme-default/components/VPNavScreenTranslations.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useData } from 'vitepress'
import VPIconChevronDown from './icons/VPIconChevronDown.vue'
import VPIconLanguages from './icons/VPIconLanguages.vue'
import { useLangs } from '../composables/langs.js'
const { theme } = useData()
const { localeLinks, currentLang } = useLangs()
const isOpen = ref(false)
function toggle() {
Expand All @@ -14,15 +13,19 @@ function toggle() {
</script>

<template>
<div v-if="theme.localeLinks" class="VPNavScreenTranslations" :class="{ open: isOpen }">
<div
v-if="localeLinks.length && currentLang.label"
class="VPNavScreenTranslations"
:class="{ open: isOpen }"
>
<button class="title" @click="toggle">
<VPIconLanguages class="icon lang" />
{{ theme.localeLinks.text }}
{{ currentLang.label }}
<VPIconChevronDown class="icon chevron" />
</button>

<ul class="list">
<li v-for="locale in theme.localeLinks.items" :key="locale.link" class="item">
<li v-for="locale in localeLinks" :key="locale.link" class="item">
<a class="link" :href="locale.link">{{ locale.text }}</a>
</li>
</ul>
Expand Down
2 changes: 1 addition & 1 deletion src/client/theme-default/composables/edit-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export function useEditLink() {
const { theme, page } = useData()

return computed(() => {
const { text = 'Edit this page', pattern } = theme.value.editLink || {}
const { text = 'Edit this page', pattern = '' } = theme.value.editLink || {}
const { relativePath } = page.value
const url = pattern.replace(/:path/g, relativePath)

Expand Down
32 changes: 32 additions & 0 deletions src/client/theme-default/composables/langs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { computed } from 'vue'
import { useData } from 'vitepress'
import { isExternal } from '../support/utils.js'

export function useLangs() {
const { site, localeIndex } = useData()
const currentLang = computed(() => ({
label: site.value.locales[localeIndex.value]?.label,
link:
localeIndex.value === 'root'
? '/'
: site.value.locales[localeIndex.value].link || `/${localeIndex.value}/`
}))

const localeLinks = computed(() =>
Object.entries(site.value.locales).flatMap(([key, value]) =>
currentLang.value.label === value.label
? []
: {
text: value.label,
link:
key === 'root'
? '/'
: isExternal(key)
? key
: value.link || `/${key}/`
}
)
)

return { localeLinks, currentLang }
}
Loading

0 comments on commit a0daafe

Please sign in to comment.