@astrojs/starlight 0.41.11 → 0.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/components/MobileMenuToggle.astro +65 -0
- package/{components → dist/components}/PageFrame.astro +32 -8
- package/dist/components-internals/Icons.d.ts +415 -0
- package/dist/components-internals/Icons.js +140 -0
- package/dist/components-internals/SidebarPersistState.d.ts +1 -0
- package/dist/components-internals/SidebarPersistState.js +53 -0
- package/dist/components-internals/TableOfContents/starlight-toc.d.ts +18 -0
- package/dist/components-internals/TableOfContents/starlight-toc.js +88 -0
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +4 -0
- package/{expressive-code.d.ts → dist/expressive-code.d.ts} +6 -13
- package/dist/expressive-code.js +31 -0
- package/dist/global.d.ts +62 -0
- package/dist/global.js +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +109 -0
- package/dist/integrations/aside-utils.d.ts +9 -0
- package/dist/integrations/aside-utils.js +35 -0
- package/dist/integrations/expressive-code/hast.d.ts +1 -0
- package/dist/integrations/expressive-code/hast.js +2 -0
- package/dist/integrations/expressive-code/index.d.ts +60 -0
- package/dist/integrations/expressive-code/index.js +48 -0
- package/dist/integrations/expressive-code/preprocessor.d.ts +17 -0
- package/dist/integrations/expressive-code/preprocessor.js +76 -0
- package/dist/integrations/expressive-code/themes/night-owl-dark.js +4 -0
- package/dist/integrations/expressive-code/themes/night-owl-light.js +4 -0
- package/dist/integrations/expressive-code/theming.d.ts +16 -0
- package/dist/integrations/expressive-code/theming.js +71 -0
- package/dist/integrations/expressive-code/translations.d.ts +8 -0
- package/dist/integrations/expressive-code/translations.js +26 -0
- package/dist/integrations/markdown-icon.d.ts +8 -0
- package/dist/integrations/markdown-icon.js +14 -0
- package/dist/integrations/markdown-plugins.d.ts +18 -0
- package/dist/integrations/markdown-plugins.js +36 -0
- package/dist/integrations/markdown-processor.d.ts +29 -0
- package/dist/integrations/markdown-processor.js +44 -0
- package/dist/integrations/pagefind.d.ts +7 -0
- package/dist/integrations/pagefind.js +34 -0
- package/dist/integrations/rehype-code-rtl-support.d.ts +21 -0
- package/dist/integrations/rehype-code-rtl-support.js +36 -0
- package/dist/integrations/rehype-heading-links.d.ts +10 -0
- package/dist/integrations/rehype-heading-links.js +57 -0
- package/dist/integrations/remark-asides.d.ts +32 -0
- package/dist/integrations/remark-asides.js +166 -0
- package/dist/integrations/remark-rehype.d.ts +17 -0
- package/dist/integrations/remark-rehype.js +51 -0
- package/dist/integrations/satteri.d.ts +13 -0
- package/dist/integrations/satteri.js +209 -0
- package/dist/integrations/shared/absolutePathToLang.d.ts +10 -0
- package/dist/integrations/shared/absolutePathToLang.js +13 -0
- package/dist/integrations/shared/localeToLang.d.ts +10 -0
- package/dist/integrations/shared/localeToLang.js +13 -0
- package/dist/integrations/shared/slugToLocale.d.ts +12 -0
- package/dist/integrations/shared/slugToLocale.js +15 -0
- package/dist/integrations/sitemap.d.ts +12 -0
- package/dist/integrations/sitemap.js +19 -0
- package/dist/integrations/vite-layer-order.d.ts +15 -0
- package/dist/integrations/vite-layer-order.js +56 -0
- package/dist/integrations/vite-lazy-barrel-optimization.d.ts +12 -0
- package/dist/integrations/vite-lazy-barrel-optimization.js +33 -0
- package/dist/integrations/vite-virtual-modules.d.ts +14 -0
- package/dist/integrations/vite-virtual-modules.js +108 -0
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +3 -0
- package/dist/loaders.d.ts +20 -0
- package/dist/loaders.js +49 -0
- package/dist/locals.d.ts +15 -0
- package/dist/locals.js +33 -0
- package/dist/package.js +4 -0
- package/{props.ts → dist/props.d.ts} +6 -4
- package/dist/props.js +1 -0
- package/dist/route-data.d.ts +7 -0
- package/dist/route-data.js +6 -0
- package/dist/schema.d.ts +426 -0
- package/dist/schema.js +103 -0
- package/dist/schemas/badge.d.ts +86 -0
- package/dist/schemas/badge.js +39 -0
- package/dist/schemas/components.d.ts +236 -0
- package/dist/schemas/components.js +36 -0
- package/dist/schemas/expressiveCode.d.ts +7 -0
- package/dist/schemas/expressiveCode.js +5 -0
- package/dist/schemas/favicon.d.ts +9 -0
- package/dist/schemas/favicon.js +32 -0
- package/dist/schemas/head.d.ts +33 -0
- package/dist/schemas/head.js +41 -0
- package/dist/schemas/hero.d.ts +319 -0
- package/dist/schemas/hero.js +73 -0
- package/dist/schemas/i18n.d.ts +125 -0
- package/dist/schemas/i18n.js +76 -0
- package/dist/schemas/icon.d.ts +284 -0
- package/dist/schemas/icon.js +7 -0
- package/dist/schemas/locale.d.ts +20 -0
- package/dist/schemas/locale.js +11 -0
- package/dist/schemas/logo.d.ts +32 -0
- package/dist/schemas/logo.js +14 -0
- package/dist/schemas/pagefind.d.ts +166 -0
- package/dist/schemas/pagefind.js +31 -0
- package/dist/schemas/prevNextLink.d.ts +10 -0
- package/dist/schemas/prevNextLink.js +14 -0
- package/dist/schemas/sidebar.d.ts +205 -0
- package/dist/schemas/sidebar.js +71 -0
- package/dist/schemas/site-title.d.ts +7 -0
- package/dist/schemas/site-title.js +17 -0
- package/dist/schemas/social.d.ts +292 -0
- package/dist/schemas/social.js +18 -0
- package/dist/schemas/tableOfContents.d.ts +24 -0
- package/dist/schemas/tableOfContents.js +16 -0
- package/dist/translations/ar.js +36 -0
- package/dist/translations/ca.js +46 -0
- package/dist/translations/cs.js +46 -0
- package/dist/translations/da.js +33 -0
- package/dist/translations/de.js +33 -0
- package/dist/translations/el.js +33 -0
- package/dist/translations/en.js +33 -0
- package/dist/translations/es.js +46 -0
- package/dist/translations/fa.js +33 -0
- package/dist/translations/fi.js +33 -0
- package/dist/translations/fr.js +36 -0
- package/dist/translations/gl.js +46 -0
- package/dist/translations/he.js +33 -0
- package/dist/translations/hi.js +36 -0
- package/dist/translations/hu.js +46 -0
- package/dist/translations/id.js +33 -0
- package/dist/translations/index.d.ts +48 -0
- package/dist/translations/index.js +75 -0
- package/dist/translations/it.js +36 -0
- package/dist/translations/ja.js +36 -0
- package/dist/translations/ko.js +36 -0
- package/dist/translations/lv.js +33 -0
- package/dist/translations/nb.js +33 -0
- package/dist/translations/nl.js +33 -0
- package/dist/translations/pl.js +36 -0
- package/dist/translations/pt.js +36 -0
- package/dist/translations/ro.js +33 -0
- package/dist/translations/ru.js +36 -0
- package/dist/translations/sk.js +33 -0
- package/dist/translations/sv.js +33 -0
- package/dist/translations/th.js +33 -0
- package/dist/translations/tr.js +33 -0
- package/dist/translations/uk.js +33 -0
- package/dist/translations/vi.js +33 -0
- package/dist/translations/zh-CN.js +36 -0
- package/dist/translations/zh-TW.js +36 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +1 -0
- package/{user-components → dist/user-components}/FileTree.astro +1 -1
- package/{user-components → dist/user-components}/Steps.astro +1 -1
- package/{user-components → dist/user-components}/TabItem.astro +1 -1
- package/{user-components → dist/user-components}/Tabs.astro +1 -1
- package/dist/user-components/file-tree-icons.d.ts +178 -0
- package/dist/user-components/file-tree-icons.js +632 -0
- package/dist/user-components/file-tree-processor.d.ts +16 -0
- package/dist/user-components/file-tree-processor.js +132 -0
- package/dist/user-components/steps-processor.d.ts +10 -0
- package/dist/user-components/steps-processor.js +39 -0
- package/dist/user-components/tabs-processor.d.ts +23 -0
- package/dist/user-components/tabs-processor.js +70 -0
- package/dist/utils/base.d.ts +7 -0
- package/dist/utils/base.js +15 -0
- package/dist/utils/canonical.d.ts +10 -0
- package/dist/utils/canonical.js +14 -0
- package/dist/utils/collection-fs.d.ts +13 -0
- package/dist/utils/collection-fs.js +19 -0
- package/{utils/collection.ts → dist/utils/collection.d.ts} +9 -20
- package/dist/utils/collection.js +26 -0
- package/dist/utils/createPathFormatter.d.ts +9 -0
- package/dist/utils/createPathFormatter.js +35 -0
- package/dist/utils/createTranslationSystem.d.ts +23 -0
- package/dist/utils/createTranslationSystem.js +84 -0
- package/dist/utils/error-map.d.ts +23 -0
- package/dist/utils/error-map.js +125 -0
- package/dist/utils/format-path.d.ts +4 -0
- package/dist/utils/format-path.js +9 -0
- package/dist/utils/generateToC.d.ts +14 -0
- package/dist/utils/generateToC.js +25 -0
- package/dist/utils/git.d.ts +12 -0
- package/dist/utils/git.js +71 -0
- package/dist/utils/gitInlined.d.ts +6 -0
- package/dist/utils/gitInlined.js +11 -0
- package/dist/utils/head.d.ts +7 -0
- package/dist/utils/head.js +233 -0
- package/dist/utils/i18n.d.ts +50 -0
- package/dist/utils/i18n.js +141 -0
- package/dist/utils/localizedUrl.d.ts +8 -0
- package/dist/utils/localizedUrl.js +28 -0
- package/dist/utils/navigation.d.ts +19 -0
- package/dist/utils/navigation.js +353 -0
- package/dist/utils/path.d.ts +21 -0
- package/dist/utils/path.js +51 -0
- package/dist/utils/plugins.d.ts +721 -0
- package/dist/utils/plugins.js +174 -0
- package/dist/utils/routing/data.d.ts +20 -0
- package/dist/utils/routing/data.js +127 -0
- package/dist/utils/routing/index.d.ts +21 -0
- package/dist/utils/routing/index.js +106 -0
- package/dist/utils/routing/middleware.d.ts +11 -0
- package/dist/utils/routing/middleware.js +65 -0
- package/dist/utils/routing/types.d.ts +93 -0
- package/dist/utils/routing/types.js +1 -0
- package/dist/utils/slugs.d.ts +45 -0
- package/dist/utils/slugs.js +104 -0
- package/dist/utils/starlight-page.d.ts +36 -0
- package/dist/utils/starlight-page.js +120 -0
- package/dist/utils/translations-fs.d.ts +15 -0
- package/dist/utils/translations-fs.js +39 -0
- package/dist/utils/translations.d.ts +20 -0
- package/dist/utils/translations.js +29 -0
- package/dist/utils/types.d.ts +5 -0
- package/dist/utils/types.js +1 -0
- package/dist/utils/url.d.ts +7 -0
- package/{utils/url.ts → dist/utils/url.js} +5 -4
- package/dist/utils/user-config.d.ts +2055 -0
- package/dist/utils/user-config.js +136 -0
- package/dist/utils/validateLogoImports.d.ts +5 -0
- package/dist/utils/validateLogoImports.js +16 -0
- package/dist/utils/zodDeepMerge.d.ts +16 -0
- package/dist/utils/zodDeepMerge.js +53 -0
- package/package.json +60 -34
- package/CHANGELOG.md +0 -3051
- package/components/MobileMenuToggle.astro +0 -114
- package/components-internals/Icons.ts +0 -248
- package/components-internals/SidebarPersistState.ts +0 -71
- package/components-internals/TableOfContents/starlight-toc.ts +0 -127
- package/constants.ts +0 -4
- package/expressive-code.mjs +0 -23
- package/global.d.ts +0 -11
- package/i18n.d.ts +0 -18
- package/index.ts +0 -200
- package/integrations/aside-utils.ts +0 -41
- package/integrations/expressive-code/hast.d.ts +0 -5
- package/integrations/expressive-code/hast.mjs +0 -9
- package/integrations/expressive-code/index.ts +0 -125
- package/integrations/expressive-code/preprocessor.ts +0 -126
- package/integrations/expressive-code/themes/night-owl-dark.jsonc +0 -1796
- package/integrations/expressive-code/themes/night-owl-light.jsonc +0 -1695
- package/integrations/expressive-code/theming.ts +0 -105
- package/integrations/expressive-code/translations.ts +0 -36
- package/integrations/markdown-icon.ts +0 -13
- package/integrations/markdown-plugins.ts +0 -71
- package/integrations/markdown-processor.ts +0 -64
- package/integrations/pagefind.ts +0 -60
- package/integrations/rehype-code-rtl-support.ts +0 -37
- package/integrations/rehype-heading-links.ts +0 -79
- package/integrations/remark-asides.ts +0 -219
- package/integrations/remark-rehype.ts +0 -87
- package/integrations/satteri.ts +0 -265
- package/integrations/shared/absolutePathToLang.ts +0 -26
- package/integrations/shared/localeToLang.ts +0 -15
- package/integrations/shared/slugToLocale.ts +0 -18
- package/integrations/sitemap.ts +0 -23
- package/integrations/vite-layer-order.ts +0 -69
- package/integrations/vite-lazy-barrel-optimization.ts +0 -40
- package/integrations/vite-virtual-modules.ts +0 -175
- package/internal.ts +0 -6
- package/loaders.ts +0 -63
- package/locals.d.ts +0 -43
- package/locals.ts +0 -43
- package/route-data.ts +0 -11
- package/schema.ts +0 -167
- package/schemas/badge.ts +0 -40
- package/schemas/components.ts +0 -265
- package/schemas/expressiveCode.ts +0 -12
- package/schemas/favicon.ts +0 -40
- package/schemas/head.ts +0 -50
- package/schemas/hero.ts +0 -69
- package/schemas/i18n.ts +0 -244
- package/schemas/icon.ts +0 -7
- package/schemas/logo.ts +0 -28
- package/schemas/pagefind.ts +0 -128
- package/schemas/prevNextLink.ts +0 -18
- package/schemas/sidebar.ts +0 -163
- package/schemas/site-title.ts +0 -20
- package/schemas/social.ts +0 -23
- package/schemas/tableOfContents.ts +0 -21
- package/translations/README.md +0 -14
- package/translations/ar.json +0 -33
- package/translations/ca.json +0 -43
- package/translations/cs.json +0 -43
- package/translations/da.json +0 -30
- package/translations/de.json +0 -30
- package/translations/el.json +0 -30
- package/translations/en.json +0 -30
- package/translations/es.json +0 -43
- package/translations/fa.json +0 -30
- package/translations/fi.json +0 -30
- package/translations/fr.json +0 -33
- package/translations/gl.json +0 -43
- package/translations/he.json +0 -30
- package/translations/hi.json +0 -33
- package/translations/hu.json +0 -43
- package/translations/id.json +0 -30
- package/translations/index.ts +0 -76
- package/translations/it.json +0 -33
- package/translations/ja.json +0 -33
- package/translations/ko.json +0 -33
- package/translations/lv.json +0 -30
- package/translations/nb.json +0 -30
- package/translations/nl.json +0 -30
- package/translations/pl.json +0 -33
- package/translations/pt.json +0 -33
- package/translations/ro.json +0 -30
- package/translations/ru.json +0 -33
- package/translations/sk.json +0 -30
- package/translations/sv.json +0 -30
- package/translations/th.json +0 -30
- package/translations/tr.json +0 -30
- package/translations/uk.json +0 -30
- package/translations/vi.json +0 -30
- package/translations/zh-CN.json +0 -33
- package/translations/zh-TW.json +0 -33
- package/types.ts +0 -7
- package/user-components/file-tree-icons.ts +0 -782
- package/user-components/rehype-file-tree.ts +0 -251
- package/user-components/rehype-steps.ts +0 -85
- package/user-components/rehype-tabs.ts +0 -121
- package/utils/base.ts +0 -15
- package/utils/canonical.ts +0 -19
- package/utils/collection-fs.ts +0 -20
- package/utils/createPathFormatter.ts +0 -60
- package/utils/createTranslationSystem.ts +0 -137
- package/utils/error-map.ts +0 -222
- package/utils/format-path.ts +0 -7
- package/utils/generateToC.ts +0 -33
- package/utils/git.ts +0 -121
- package/utils/gitInlined.ts +0 -20
- package/utils/head.ts +0 -235
- package/utils/i18n.ts +0 -221
- package/utils/localizedUrl.ts +0 -51
- package/utils/navigation.ts +0 -574
- package/utils/path.ts +0 -58
- package/utils/plugins.ts +0 -498
- package/utils/routing/data.ts +0 -154
- package/utils/routing/index.ts +0 -139
- package/utils/routing/middleware.ts +0 -81
- package/utils/routing/types.ts +0 -101
- package/utils/slugs.ts +0 -119
- package/utils/starlight-page.ts +0 -205
- package/utils/translations-fs.ts +0 -54
- package/utils/translations.ts +0 -57
- package/utils/types.ts +0 -15
- package/utils/user-config.ts +0 -348
- package/utils/validateLogoImports.ts +0 -21
- package/utils/zodDeepMerge.ts +0 -144
- package/virtual-internal.d.ts +0 -149
- package/virtual.d.ts +0 -27
- /package/{components → dist/components}/AnchorHeading.astro +0 -0
- /package/{components → dist/components}/Banner.astro +0 -0
- /package/{components → dist/components}/ContentNotice.astro +0 -0
- /package/{components → dist/components}/ContentPanel.astro +0 -0
- /package/{components → dist/components}/DraftContentNotice.astro +0 -0
- /package/{components → dist/components}/EditLink.astro +0 -0
- /package/{components → dist/components}/FallbackContentNotice.astro +0 -0
- /package/{components → dist/components}/Footer.astro +0 -0
- /package/{components → dist/components}/Head.astro +0 -0
- /package/{components → dist/components}/Header.astro +0 -0
- /package/{components → dist/components}/Hero.astro +0 -0
- /package/{components → dist/components}/LanguageSelect.astro +0 -0
- /package/{components → dist/components}/LastUpdated.astro +0 -0
- /package/{components → dist/components}/MarkdownContent.astro +0 -0
- /package/{components → dist/components}/MobileMenuFooter.astro +0 -0
- /package/{components → dist/components}/MobileTableOfContents.astro +0 -0
- /package/{components → dist/components}/Page.astro +0 -0
- /package/{components → dist/components}/PageSidebar.astro +0 -0
- /package/{components → dist/components}/PageTitle.astro +0 -0
- /package/{components → dist/components}/Pagination.astro +0 -0
- /package/{components → dist/components}/Search.astro +0 -0
- /package/{components → dist/components}/Select.astro +0 -0
- /package/{components → dist/components}/Sidebar.astro +0 -0
- /package/{components → dist/components}/SidebarPersister.astro +0 -0
- /package/{components → dist/components}/SidebarRestorePoint.astro +0 -0
- /package/{components → dist/components}/SidebarSublist.astro +0 -0
- /package/{components → dist/components}/SiteTitle.astro +0 -0
- /package/{components → dist/components}/SkipLink.astro +0 -0
- /package/{components → dist/components}/SocialIcons.astro +0 -0
- /package/{components → dist/components}/StarlightPage.astro +0 -0
- /package/{components → dist/components}/TableOfContents.astro +0 -0
- /package/{components → dist/components}/ThemeProvider.astro +0 -0
- /package/{components → dist/components}/ThemeSelect.astro +0 -0
- /package/{components → dist/components}/TwoColumnContent.astro +0 -0
- /package/{components-internals → dist/components-internals}/TableOfContents/TableOfContentsList.astro +0 -0
- /package/{components.ts → dist/components.ts} +0 -0
- /package/{routes → dist/routes}/common.astro +0 -0
- /package/{routes → dist/routes}/ssr/404.astro +0 -0
- /package/{routes → dist/routes}/ssr/index.astro +0 -0
- /package/{routes → dist/routes}/static/404.astro +0 -0
- /package/{routes → dist/routes}/static/index.astro +0 -0
- /package/{style → dist/style}/anchor-links.css +0 -0
- /package/{style → dist/style}/asides.css +0 -0
- /package/{style → dist/style}/layers.css +0 -0
- /package/{style → dist/style}/markdown.css +0 -0
- /package/{style → dist/style}/print.css +0 -0
- /package/{style → dist/style}/props.css +0 -0
- /package/{style → dist/style}/reset.css +0 -0
- /package/{style → dist/style}/util.css +0 -0
- /package/{user-components → dist/user-components}/Aside.astro +0 -0
- /package/{user-components → dist/user-components}/Badge.astro +0 -0
- /package/{user-components → dist/user-components}/Card.astro +0 -0
- /package/{user-components → dist/user-components}/CardGrid.astro +0 -0
- /package/{user-components → dist/user-components}/Icon.astro +0 -0
- /package/{user-components → dist/user-components}/LinkButton.astro +0 -0
- /package/{user-components → dist/user-components}/LinkCard.astro +0 -0
package/utils/head.ts
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
import config from 'virtual:starlight/user-config';
|
|
2
|
-
import project from 'virtual:starlight/project-context';
|
|
3
|
-
import { version } from '../package.json';
|
|
4
|
-
import { type HeadConfig, HeadConfigSchema, type HeadUserConfig } from '../schemas/head';
|
|
5
|
-
import type { PageProps, RouteDataContext } from './routing/data';
|
|
6
|
-
import { fileWithBase } from './base';
|
|
7
|
-
import { formatCanonical } from './canonical';
|
|
8
|
-
import { localizedUrl } from './localizedUrl';
|
|
9
|
-
import { isAbsoluteUrl } from './url';
|
|
10
|
-
|
|
11
|
-
const HeadSchema = HeadConfigSchema({ source: 'content' });
|
|
12
|
-
|
|
13
|
-
/** Get the head for the current page. */
|
|
14
|
-
export function getHead(
|
|
15
|
-
{ entry, lang }: PageProps,
|
|
16
|
-
context: RouteDataContext,
|
|
17
|
-
siteTitle: string
|
|
18
|
-
): HeadConfig {
|
|
19
|
-
const { data } = entry;
|
|
20
|
-
|
|
21
|
-
const canonical = context.site ? new URL(context.url.pathname, context.site) : undefined;
|
|
22
|
-
const canonicalHref = canonical?.href
|
|
23
|
-
? formatCanonical(canonical.href, {
|
|
24
|
-
format: project.build.format,
|
|
25
|
-
trailingSlash: project.trailingSlash,
|
|
26
|
-
})
|
|
27
|
-
: undefined;
|
|
28
|
-
const description = data.description || config.description;
|
|
29
|
-
|
|
30
|
-
const headDefaults: HeadUserConfig = [
|
|
31
|
-
{ tag: 'meta', attrs: { charset: 'utf-8' } },
|
|
32
|
-
{
|
|
33
|
-
tag: 'meta',
|
|
34
|
-
attrs: { name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
|
35
|
-
},
|
|
36
|
-
{ tag: 'title', content: `${data.title} ${config.titleDelimiter} ${siteTitle}` },
|
|
37
|
-
...(canonicalHref !== undefined
|
|
38
|
-
? ([{ tag: 'link', attrs: { rel: 'canonical', href: canonicalHref } }] as const)
|
|
39
|
-
: []),
|
|
40
|
-
{ tag: 'meta', attrs: { name: 'generator', content: context.generator } },
|
|
41
|
-
{
|
|
42
|
-
tag: 'meta',
|
|
43
|
-
attrs: { name: 'generator', content: `Starlight v${version}` },
|
|
44
|
-
},
|
|
45
|
-
// Favicon
|
|
46
|
-
{
|
|
47
|
-
tag: 'link',
|
|
48
|
-
attrs: {
|
|
49
|
-
rel: 'shortcut icon',
|
|
50
|
-
href: isAbsoluteUrl(config.favicon.href)
|
|
51
|
-
? config.favicon.href
|
|
52
|
-
: fileWithBase(config.favicon.href),
|
|
53
|
-
type: config.favicon.type,
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
// OpenGraph Tags
|
|
57
|
-
{ tag: 'meta', attrs: { property: 'og:title', content: data.title } },
|
|
58
|
-
{ tag: 'meta', attrs: { property: 'og:type', content: 'article' } },
|
|
59
|
-
...(canonicalHref !== undefined
|
|
60
|
-
? ([{ tag: 'meta', attrs: { property: 'og:url', content: canonicalHref } }] as const)
|
|
61
|
-
: []),
|
|
62
|
-
{ tag: 'meta', attrs: { property: 'og:locale', content: lang } },
|
|
63
|
-
...(description !== undefined
|
|
64
|
-
? ([{ tag: 'meta', attrs: { property: 'og:description', content: description } }] as const)
|
|
65
|
-
: []),
|
|
66
|
-
{ tag: 'meta', attrs: { property: 'og:site_name', content: siteTitle } },
|
|
67
|
-
// Twitter Tags
|
|
68
|
-
{
|
|
69
|
-
tag: 'meta',
|
|
70
|
-
attrs: { name: 'twitter:card', content: 'summary_large_image' },
|
|
71
|
-
},
|
|
72
|
-
];
|
|
73
|
-
|
|
74
|
-
if (description)
|
|
75
|
-
headDefaults.push({
|
|
76
|
-
tag: 'meta',
|
|
77
|
-
attrs: { name: 'description', content: description },
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
// Link to language alternates.
|
|
81
|
-
if (canonical && config.isMultilingual) {
|
|
82
|
-
for (const locale in config.locales) {
|
|
83
|
-
const localeOpts = config.locales[locale];
|
|
84
|
-
if (!localeOpts) continue;
|
|
85
|
-
headDefaults.push({
|
|
86
|
-
tag: 'link',
|
|
87
|
-
attrs: {
|
|
88
|
-
rel: 'alternate',
|
|
89
|
-
hreflang: localeOpts.lang,
|
|
90
|
-
href: localizedUrl(canonical, locale, project.trailingSlash).href,
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
headDefaults.push({
|
|
95
|
-
tag: 'link',
|
|
96
|
-
attrs: {
|
|
97
|
-
rel: 'alternate',
|
|
98
|
-
hreflang: 'x-default',
|
|
99
|
-
href: localizedUrl(canonical, config.defaultLocale.locale, project.trailingSlash).href,
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Link to sitemap, but only when `site` is set.
|
|
105
|
-
if (context.site) {
|
|
106
|
-
headDefaults.push({
|
|
107
|
-
tag: 'link',
|
|
108
|
-
attrs: {
|
|
109
|
-
rel: 'sitemap',
|
|
110
|
-
href: fileWithBase('/sitemap-index.xml'),
|
|
111
|
-
},
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Link to Twitter account if set in Starlight config.
|
|
116
|
-
const twitterLink = config.social?.find(({ icon }) => icon === 'twitter' || icon === 'x.com');
|
|
117
|
-
if (twitterLink) {
|
|
118
|
-
headDefaults.push({
|
|
119
|
-
tag: 'meta',
|
|
120
|
-
attrs: {
|
|
121
|
-
name: 'twitter:site',
|
|
122
|
-
content: new URL(twitterLink.href).pathname.replace('/', '@'),
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
return createHead(headDefaults, config.head, data.head);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/** Create a fully parsed, merged, and sorted head entry array from multiple sources. */
|
|
131
|
-
function createHead(defaults: HeadUserConfig, ...heads: HeadConfig[]) {
|
|
132
|
-
let head = HeadSchema.parse(defaults);
|
|
133
|
-
for (const next of heads) {
|
|
134
|
-
head = mergeHead(head, next);
|
|
135
|
-
}
|
|
136
|
-
return sortHead(head);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Test if a head config object contains a matching `<title>`, `<meta>`, `<link rel="canonical">`
|
|
141
|
-
* or `<link rel="sitemap">` tag.
|
|
142
|
-
*
|
|
143
|
-
* For example, will return true if `head` already contains
|
|
144
|
-
* `<meta name="description" content="A">` and the passed `tag`
|
|
145
|
-
* is `<meta name="description" content="B">`. Tests against `name`,
|
|
146
|
-
* `property`, and `http-equiv` attributes for `<meta>` tags.
|
|
147
|
-
*/
|
|
148
|
-
function hasTag(head: HeadConfig, entry: HeadConfig[number]): boolean {
|
|
149
|
-
switch (entry.tag) {
|
|
150
|
-
case 'title':
|
|
151
|
-
return head.some(({ tag }) => tag === 'title');
|
|
152
|
-
case 'meta':
|
|
153
|
-
return hasOneOf(head, entry, ['name', 'property', 'http-equiv']);
|
|
154
|
-
case 'link':
|
|
155
|
-
return head.some(
|
|
156
|
-
({ attrs }) =>
|
|
157
|
-
(entry.attrs?.rel === 'canonical' && attrs?.rel === 'canonical') ||
|
|
158
|
-
(entry.attrs?.rel === 'sitemap' && attrs?.rel === 'sitemap')
|
|
159
|
-
);
|
|
160
|
-
default:
|
|
161
|
-
return false;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Test if a head config object contains a tag of the same type
|
|
167
|
-
* as `entry` and a matching attribute for one of the passed `keys`.
|
|
168
|
-
*/
|
|
169
|
-
function hasOneOf(head: HeadConfig, entry: HeadConfig[number], keys: string[]): boolean {
|
|
170
|
-
const attr = getAttr(keys, entry);
|
|
171
|
-
if (!attr) return false;
|
|
172
|
-
const [key, val] = attr;
|
|
173
|
-
return head.some(({ tag, attrs }) => tag === entry.tag && attrs?.[key] === val);
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/** Find the first matching key–value pair in a head entry’s attributes. */
|
|
177
|
-
function getAttr(
|
|
178
|
-
keys: string[],
|
|
179
|
-
entry: HeadConfig[number]
|
|
180
|
-
): [key: string, value: string | boolean] | undefined {
|
|
181
|
-
let attr: [string, string | boolean] | undefined;
|
|
182
|
-
for (const key of keys) {
|
|
183
|
-
const val = entry.attrs?.[key];
|
|
184
|
-
if (val) {
|
|
185
|
-
attr = [key, val];
|
|
186
|
-
break;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
return attr;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/** Merge two heads, overwriting entries in the first head that exist in the second. */
|
|
193
|
-
function mergeHead(oldHead: HeadConfig, newHead: HeadConfig) {
|
|
194
|
-
return [...oldHead.filter((tag) => !hasTag(newHead, tag)), ...newHead];
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/** Sort head tags to place important tags first and relegate “SEO” meta tags. */
|
|
198
|
-
function sortHead(head: HeadConfig) {
|
|
199
|
-
return head.sort((a, b) => {
|
|
200
|
-
const aImportance = getImportance(a);
|
|
201
|
-
const bImportance = getImportance(b);
|
|
202
|
-
return aImportance > bImportance ? -1 : bImportance > aImportance ? 1 : 0;
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/** Get the relative importance of a specific head tag. */
|
|
207
|
-
function getImportance(entry: HeadConfig[number]) {
|
|
208
|
-
// 1. Important meta tags.
|
|
209
|
-
if (
|
|
210
|
-
entry.tag === 'meta' &&
|
|
211
|
-
entry.attrs &&
|
|
212
|
-
('charset' in entry.attrs || 'http-equiv' in entry.attrs || entry.attrs.name === 'viewport')
|
|
213
|
-
) {
|
|
214
|
-
return 100;
|
|
215
|
-
}
|
|
216
|
-
// 2. Page title
|
|
217
|
-
if (entry.tag === 'title') return 90;
|
|
218
|
-
// 3. Anything that isn’t an SEO meta tag.
|
|
219
|
-
if (entry.tag !== 'meta') {
|
|
220
|
-
// The default favicon should be below any extra icons that the user may have set
|
|
221
|
-
// because if several icons are equally appropriate, the last one is used and we
|
|
222
|
-
// want to use the SVG icon when supported.
|
|
223
|
-
if (
|
|
224
|
-
entry.tag === 'link' &&
|
|
225
|
-
entry.attrs &&
|
|
226
|
-
'rel' in entry.attrs &&
|
|
227
|
-
entry.attrs.rel === 'shortcut icon'
|
|
228
|
-
) {
|
|
229
|
-
return 70;
|
|
230
|
-
}
|
|
231
|
-
return 80;
|
|
232
|
-
}
|
|
233
|
-
// 4. SEO meta tags.
|
|
234
|
-
return 0;
|
|
235
|
-
}
|
package/utils/i18n.ts
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import type { AstroConfig } from 'astro';
|
|
2
|
-
import { AstroError } from 'astro/errors';
|
|
3
|
-
import type { StarlightConfig } from './user-config';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* A list of well-known right-to-left languages used as a fallback when determining the text
|
|
7
|
-
* direction of a locale is not supported by the `Intl.Locale` API in the current environment.
|
|
8
|
-
*
|
|
9
|
-
* @see getLocaleDir()
|
|
10
|
-
* @see https://en.wikipedia.org/wiki/IETF_language_tag#List_of_common_primary_language_subtags
|
|
11
|
-
*/
|
|
12
|
-
const wellKnownRTL = ['ar', 'fa', 'he', 'prs', 'ps', 'syc', 'ug', 'ur'];
|
|
13
|
-
|
|
14
|
-
/** Information about the built-in default locale used as a fallback when no locales are defined. */
|
|
15
|
-
export const BuiltInDefaultLocale = { ...getLocaleInfo('en'), lang: 'en' };
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Processes the Astro and Starlight i18n configurations to generate/update them accordingly:
|
|
19
|
-
*
|
|
20
|
-
* - If no Astro and Starlight i18n configurations are provided, the built-in default locale is
|
|
21
|
-
* used in Starlight and the generated Astro i18n configuration will match it.
|
|
22
|
-
* - If only a Starlight i18n configuration is provided, an equivalent Astro i18n configuration is
|
|
23
|
-
* generated.
|
|
24
|
-
* - If only an Astro i18n configuration is provided, an equivalent Starlight i18n configuration is
|
|
25
|
-
* used.
|
|
26
|
-
* - If both an Astro and Starlight i18n configurations are provided, an error is thrown.
|
|
27
|
-
*/
|
|
28
|
-
export function processI18nConfig(
|
|
29
|
-
starlightConfig: StarlightConfig,
|
|
30
|
-
astroI18nConfig: AstroConfig['i18n']
|
|
31
|
-
) {
|
|
32
|
-
// We don't know what to do if both an Astro and Starlight i18n configuration are provided.
|
|
33
|
-
if (astroI18nConfig && !starlightConfig.isUsingBuiltInDefaultLocale) {
|
|
34
|
-
throw new AstroError(
|
|
35
|
-
'Cannot provide both an Astro `i18n` configuration and a Starlight `locales` configuration.',
|
|
36
|
-
'Remove one of the two configurations.\nSee more at https://starlight.astro.build/guides/i18n/'
|
|
37
|
-
);
|
|
38
|
-
} else if (astroI18nConfig) {
|
|
39
|
-
// If a Starlight compatible Astro i18n configuration is provided, we generate the matching
|
|
40
|
-
// Starlight configuration.
|
|
41
|
-
return {
|
|
42
|
-
astroI18nConfig,
|
|
43
|
-
starlightConfig: {
|
|
44
|
-
...starlightConfig,
|
|
45
|
-
...getStarlightI18nConfig(astroI18nConfig),
|
|
46
|
-
} as StarlightConfig,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
// Otherwise, we generate the Astro i18n configuration based on the Starlight configuration.
|
|
50
|
-
return { astroI18nConfig: getAstroI18nConfig(starlightConfig), starlightConfig: starlightConfig };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Generate an Astro i18n configuration based on a Starlight configuration. */
|
|
54
|
-
function getAstroI18nConfig(config: StarlightConfig): NonNullable<AstroConfig['i18n']> {
|
|
55
|
-
return {
|
|
56
|
-
// When using custom locale `path`s, the default locale must match one of these paths.
|
|
57
|
-
// In Starlight, this matches the `locale` property if defined, and we fallback to the `lang`
|
|
58
|
-
// property if not (which would be set to the language’s directory name by default).
|
|
59
|
-
defaultLocale:
|
|
60
|
-
// If the default locale is explicitly set to `root`, we use the `lang` property instead.
|
|
61
|
-
(config.defaultLocale.locale === 'root'
|
|
62
|
-
? config.defaultLocale.lang
|
|
63
|
-
: (config.defaultLocale.locale ?? config.defaultLocale.lang)) ?? BuiltInDefaultLocale.lang,
|
|
64
|
-
locales: config.locales
|
|
65
|
-
? Object.entries(config.locales).map(([locale, localeConfig]) => {
|
|
66
|
-
return {
|
|
67
|
-
codes: [localeConfig?.lang ?? locale],
|
|
68
|
-
path: locale === 'root' ? (localeConfig?.lang ?? BuiltInDefaultLocale.lang) : locale,
|
|
69
|
-
};
|
|
70
|
-
})
|
|
71
|
-
: [config.defaultLocale.lang],
|
|
72
|
-
routing: {
|
|
73
|
-
prefixDefaultLocale:
|
|
74
|
-
// Sites with multiple languages without a root locale.
|
|
75
|
-
(config.isMultilingual && config.locales?.root === undefined) ||
|
|
76
|
-
// Sites with a single non-root language different from the built-in default locale.
|
|
77
|
-
(!config.isMultilingual && config.locales !== undefined),
|
|
78
|
-
redirectToDefaultLocale: false,
|
|
79
|
-
fallbackType: 'redirect',
|
|
80
|
-
},
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/** Generate a Starlight i18n configuration based on an Astro configuration. */
|
|
85
|
-
function getStarlightI18nConfig(
|
|
86
|
-
astroI18nConfig: NonNullable<AstroConfig['i18n']>
|
|
87
|
-
): Pick<StarlightConfig, 'isMultilingual' | 'locales' | 'defaultLocale'> {
|
|
88
|
-
if (astroI18nConfig.routing === 'manual') {
|
|
89
|
-
throw new AstroError(
|
|
90
|
-
'Starlight is not compatible with the `manual` routing option in the Astro i18n configuration.'
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const prefixDefaultLocale = astroI18nConfig.routing.prefixDefaultLocale;
|
|
95
|
-
const isMultilingual = astroI18nConfig.locales.length > 1;
|
|
96
|
-
const isMonolingualWithRootLocale = !isMultilingual && !prefixDefaultLocale;
|
|
97
|
-
|
|
98
|
-
const locales = isMonolingualWithRootLocale
|
|
99
|
-
? undefined
|
|
100
|
-
: Object.fromEntries(
|
|
101
|
-
astroI18nConfig.locales.map((locale) => [
|
|
102
|
-
isDefaultAstroLocale(astroI18nConfig, locale) && !prefixDefaultLocale
|
|
103
|
-
? 'root'
|
|
104
|
-
: isAstroLocaleExtendedConfig(locale)
|
|
105
|
-
? locale.path
|
|
106
|
-
: locale,
|
|
107
|
-
inferStarlightLocaleFromAstroLocale(locale),
|
|
108
|
-
])
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
const defaultAstroLocale = astroI18nConfig.locales.find((locale) =>
|
|
112
|
-
isDefaultAstroLocale(astroI18nConfig, locale)
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
// This should never happen as Astro validation should prevent this case.
|
|
116
|
-
if (!defaultAstroLocale) {
|
|
117
|
-
throw new AstroError(
|
|
118
|
-
'Astro default locale not found.',
|
|
119
|
-
'This should never happen. Please open a new issue: https://github.com/withastro/starlight/issues/new?template=---01-bug-report.yml'
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
return {
|
|
124
|
-
isMultilingual,
|
|
125
|
-
locales,
|
|
126
|
-
defaultLocale: {
|
|
127
|
-
...inferStarlightLocaleFromAstroLocale(defaultAstroLocale),
|
|
128
|
-
locale:
|
|
129
|
-
isMonolingualWithRootLocale || (isMultilingual && !prefixDefaultLocale)
|
|
130
|
-
? undefined
|
|
131
|
-
: isAstroLocaleExtendedConfig(defaultAstroLocale)
|
|
132
|
-
? defaultAstroLocale.codes[0]
|
|
133
|
-
: defaultAstroLocale,
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
/** Infer Starlight locale information based on a locale from an Astro i18n configuration. */
|
|
139
|
-
function inferStarlightLocaleFromAstroLocale(astroLocale: AstroLocale) {
|
|
140
|
-
const lang = isAstroLocaleExtendedConfig(astroLocale) ? astroLocale.codes[0] : astroLocale;
|
|
141
|
-
return { ...getLocaleInfo(lang), lang };
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** Check if the passed locale is the default locale in an Astro i18n configuration. */
|
|
145
|
-
function isDefaultAstroLocale(
|
|
146
|
-
astroI18nConfig: NonNullable<AstroConfig['i18n']>,
|
|
147
|
-
locale: AstroLocale
|
|
148
|
-
) {
|
|
149
|
-
return (
|
|
150
|
-
(isAstroLocaleExtendedConfig(locale) ? locale.path : locale) === astroI18nConfig.defaultLocale
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Check if the passed Astro locale is using the object variant.
|
|
156
|
-
* @see AstroLocaleExtendedConfig
|
|
157
|
-
*/
|
|
158
|
-
function isAstroLocaleExtendedConfig(locale: AstroLocale): locale is AstroLocaleExtendedConfig {
|
|
159
|
-
return typeof locale !== 'string';
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/** Returns the locale information such as a label and a direction based on a BCP-47 tag. */
|
|
163
|
-
function getLocaleInfo(lang: string) {
|
|
164
|
-
try {
|
|
165
|
-
const locale = new Intl.Locale(lang);
|
|
166
|
-
const label = new Intl.DisplayNames(locale, { type: 'language' }).of(lang);
|
|
167
|
-
if (!label || lang === label) throw new Error('Label not found.');
|
|
168
|
-
return {
|
|
169
|
-
label: label[0]?.toLocaleUpperCase(locale) + label.slice(1),
|
|
170
|
-
dir: getLocaleDir(locale),
|
|
171
|
-
};
|
|
172
|
-
} catch {
|
|
173
|
-
throw new AstroError(
|
|
174
|
-
`Failed to get locale information for the '${lang}' locale.`,
|
|
175
|
-
'Make sure to provide a valid BCP-47 tags (e.g. en, ar, or zh-CN).'
|
|
176
|
-
);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Returns the direction of the passed locale.
|
|
182
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTextInfo
|
|
183
|
-
*/
|
|
184
|
-
function getLocaleDir(locale: Intl.Locale): 'ltr' | 'rtl' {
|
|
185
|
-
if ('textInfo' in locale) {
|
|
186
|
-
// @ts-expect-error - `textInfo` is not typed but is available in v8 based environments.
|
|
187
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
188
|
-
return locale.textInfo.direction;
|
|
189
|
-
} else if ('getTextInfo' in locale) {
|
|
190
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
191
|
-
// @ts-ignore - `getTextInfo` is not typed in older versions of TypeScript but is available in some browsers and newer versions of Node.
|
|
192
|
-
// TODO: remove or switch to @ts-expect-error in #3572
|
|
193
|
-
return locale.getTextInfo().direction;
|
|
194
|
-
}
|
|
195
|
-
// Firefox does not support `textInfo` or `getTextInfo` yet so we fallback to a well-known list
|
|
196
|
-
// of right-to-left languages.
|
|
197
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
198
|
-
// @ts-ignore — This is a type error with newer versions of TypeScript’s DOM types.
|
|
199
|
-
// TODO: remove or switch to @ts-expect-error in #3572
|
|
200
|
-
return wellKnownRTL.includes((locale as Intl.Locale).language) ? 'rtl' : 'ltr';
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Get the string for the passed language from a dictionary object.
|
|
205
|
-
*
|
|
206
|
-
* TODO: Make this clever. Currently a simple key look-up, but should use
|
|
207
|
-
* BCP-47 mapping so that e.g. `en-US` returns `en` strings, and use the
|
|
208
|
-
* site’s default locale as a last resort.
|
|
209
|
-
*
|
|
210
|
-
* @example
|
|
211
|
-
* pickLang({ en: 'Hello', fr: 'Bonjour' }, 'en'); // => 'Hello'
|
|
212
|
-
*/
|
|
213
|
-
export function pickLang<T extends Record<string, string>>(
|
|
214
|
-
dictionary: T,
|
|
215
|
-
lang: keyof T
|
|
216
|
-
): string | undefined {
|
|
217
|
-
return dictionary[lang];
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
type AstroLocale = NonNullable<AstroConfig['i18n']>['locales'][number];
|
|
221
|
-
type AstroLocaleExtendedConfig = Exclude<AstroLocale, string>;
|
package/utils/localizedUrl.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import config from 'virtual:starlight/user-config';
|
|
2
|
-
import { stripTrailingSlash } from './path';
|
|
3
|
-
import type { AstroConfig } from 'astro';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Get the equivalent of the passed URL for the passed locale.
|
|
7
|
-
*/
|
|
8
|
-
export function localizedUrl(
|
|
9
|
-
url: URL,
|
|
10
|
-
locale: string | undefined,
|
|
11
|
-
trailingSlash: AstroConfig['trailingSlash']
|
|
12
|
-
): URL {
|
|
13
|
-
// Create a new URL object to void mutating the global.
|
|
14
|
-
url = new URL(url);
|
|
15
|
-
if (!config.locales) {
|
|
16
|
-
// i18n is not configured on this site, no localization required.
|
|
17
|
-
return url;
|
|
18
|
-
}
|
|
19
|
-
if (locale === 'root') locale = '';
|
|
20
|
-
/** Base URL with trailing `/` stripped. */
|
|
21
|
-
const base = stripTrailingSlash(import.meta.env.BASE_URL);
|
|
22
|
-
const hasBase = url.pathname.startsWith(base);
|
|
23
|
-
// Temporarily remove base to simplify
|
|
24
|
-
if (hasBase) url.pathname = url.pathname.replace(base, '');
|
|
25
|
-
const [_leadingSlash, baseSegment] = url.pathname.split('/');
|
|
26
|
-
// Strip .html extension to handle file output builds where URL might be e.g. `/en.html`
|
|
27
|
-
const htmlExt = '.html';
|
|
28
|
-
const isRootHtml = baseSegment?.endsWith(htmlExt);
|
|
29
|
-
const baseSlug = isRootHtml ? baseSegment?.slice(0, -1 * htmlExt.length) : baseSegment;
|
|
30
|
-
if (baseSlug && baseSlug in config.locales) {
|
|
31
|
-
// We’re in a localized route, substitute the new locale (or strip for root lang).
|
|
32
|
-
if (locale) {
|
|
33
|
-
url.pathname = url.pathname.replace(baseSlug, locale);
|
|
34
|
-
} else if (isRootHtml) {
|
|
35
|
-
url.pathname = '/index.html';
|
|
36
|
-
} else {
|
|
37
|
-
url.pathname = url.pathname.replace('/' + baseSlug, '');
|
|
38
|
-
}
|
|
39
|
-
} else if (locale) {
|
|
40
|
-
// We’re in the root language. Inject the new locale if we have one.
|
|
41
|
-
if (baseSegment === 'index.html') {
|
|
42
|
-
url.pathname = '/' + locale + '.html';
|
|
43
|
-
} else {
|
|
44
|
-
url.pathname = '/' + locale + url.pathname;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
// Restore base
|
|
48
|
-
if (hasBase) url.pathname = base + url.pathname;
|
|
49
|
-
if (trailingSlash === 'never') url.pathname = stripTrailingSlash(url.pathname);
|
|
50
|
-
return url;
|
|
51
|
-
}
|