@astrojs/starlight 0.2.0 → 0.3.1

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/404.astro CHANGED
@@ -1,58 +1,39 @@
1
1
  ---
2
+ import { getEntry } from 'astro:content';
2
3
  import config from 'virtual:starlight/user-config';
3
- import { pathWithBase } from './utils/base';
4
+ import EmptyContent from './components/EmptyMarkdown.md';
5
+ import Page from './layout/Page.astro';
6
+ import type { StarlightDocsEntry } from './utils/routing';
7
+ import { useTranslations } from './utils/translations';
4
8
 
5
- // Built-in CSS styles.
6
- import './style/props.css';
7
- import './style/reset.css';
8
- import './style/shiki.css';
9
- import './style/util.css';
10
-
11
- // Layout
12
- import PageFrame from './layout/PageFrame.astro';
13
-
14
- // Components
15
- import Header from './components/Header.astro';
16
- import MarkdownContent from './components/MarkdownContent.astro';
17
- import ThemeProvider from './components/ThemeProvider.astro';
18
- import SkipLink from './components/SkipLink.astro';
9
+ const { lang = 'en', dir = 'ltr', locale } = config.defaultLocale || {};
10
+ const entryMeta = { dir, lang, locale };
11
+ const t = useTranslations(locale);
19
12
 
20
- // Important that this is the last import so it can override built-in styles.
21
- import 'virtual:starlight/user-css';
13
+ const fallbackEntry: StarlightDocsEntry = {
14
+ slug: '404',
15
+ id: '404.md' as StarlightDocsEntry['id'],
16
+ body: '',
17
+ collection: 'docs',
18
+ data: {
19
+ title: '404',
20
+ template: 'splash',
21
+ editUrl: false,
22
+ head: [],
23
+ hero: { tagline: t('404.text'), actions: [] },
24
+ },
25
+ render: async () => ({
26
+ Content: EmptyContent,
27
+ headings: [],
28
+ remarkPluginFrontmatter: {},
29
+ }),
30
+ };
22
31
 
23
- const { lang = 'en', dir = 'ltr', locale } = config.defaultLocale || {};
32
+ const userEntry = await getEntry('docs', '404');
33
+ const entry = userEntry || fallbackEntry;
34
+ const { Content, headings } = await entry.render();
24
35
  ---
25
36
 
26
- <html lang={lang} dir={dir}>
27
- <head>
28
- <meta charset="utf-8" />
29
- <meta name="viewport" content="width=device-width" />
30
- <title>Not found</title>
31
- </head>
32
- <body>
33
- <ThemeProvider />
34
- <SkipLink {locale} />
35
- <PageFrame {locale} hasSidebar={false}>
36
- <Header slot="header" {locale} />
37
- <main>
38
- <MarkdownContent>
39
- <h1 id="_top" data-page-title>404</h1>
40
- <p>Houston, we have a problem.</p>
41
- <p>
42
- We couldn’t find that link. Check the address or
43
- <a href={pathWithBase('/')}>head back home</a>.
44
- </p>
45
- </MarkdownContent>
46
- </main>
47
- </PageFrame>
48
-
49
- <style>
50
- main {
51
- margin: auto;
52
- padding: clamp(2rem, 10vmin, 6rem) var(--sl-nav-pad-x);
53
- max-width: var(--sl-content-width);
54
- max-width: max-content;
55
- }
56
- </style>
57
- </body>
58
- </html>
37
+ <Page {headings} entry={entry} slug={entry.slug} {...entryMeta} {entryMeta}>
38
+ <Content />
39
+ </Page>
package/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # @astrojs/starlight
2
2
 
3
+ ## 0.3.1
4
+
5
+ ### Patch Changes
6
+
7
+ - [#257](https://github.com/withastro/starlight/pull/257) [`0502327`](https://github.com/withastro/starlight/commit/050232770c8a2d22f317def8e734e4abb36387c6) Thanks [@JosefJezek](https://github.com/JosefJezek)! - Add Czech language support
8
+
9
+ - [#261](https://github.com/withastro/starlight/pull/261) [`2062b9e`](https://github.com/withastro/starlight/commit/2062b9e21695b5dc3f116731dbfdf609e495018c) Thanks [@delucis](https://github.com/delucis)! - Fix autogenerated navigation for pages using fallback content
10
+
11
+ ## 0.3.0
12
+
13
+ ### Minor Changes
14
+
15
+ - [#237](https://github.com/withastro/starlight/pull/237) [`4279d75`](https://github.com/withastro/starlight/commit/4279d7512a8261b576056471f5aa1ede1e6aae4a) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Use path instead of slugified path for auto-generated sidebar item configuration
16
+
17
+ ⚠️ Potentially breaking change. If your docs directory names don’t match their URLs, for example they contain whitespace like `docs/my docs/`, and you were referencing these in an `autogenerate` sidebar group as `my-docs`, update your config to reference these with the directory name instead of the slugified version:
18
+
19
+ ```diff
20
+ autogenerate: {
21
+ - directory: 'my-docs',
22
+ + directory: 'my docs',
23
+ }
24
+ ```
25
+
26
+ - [#226](https://github.com/withastro/starlight/pull/226) [`1aa2187`](https://github.com/withastro/starlight/commit/1aa2187944dde4419e523f0087139f5a21efd826) Thanks [@delucis](https://github.com/delucis)! - Add support for custom 404 pages.
27
+
28
+ ### Patch Changes
29
+
30
+ - [#234](https://github.com/withastro/starlight/pull/234) [`91309ae`](https://github.com/withastro/starlight/commit/91309ae13250c5fd9f91a8e1843f16430773ff15) Thanks [@morinokami](https://github.com/morinokami)! - Add Japanese translation for `search.devWarning`
31
+
32
+ - [#227](https://github.com/withastro/starlight/pull/227) [`fbdecfa`](https://github.com/withastro/starlight/commit/fbdecfab47effb0cba7cbc9233a7b6bffdded320) Thanks [@Yan-Thomas](https://github.com/Yan-Thomas)! - Add missing i18n support to the Search component's dev warning.
33
+
34
+ - [#244](https://github.com/withastro/starlight/pull/244) [`f1bcbeb`](https://github.com/withastro/starlight/commit/f1bcbebeb441b6bb9ed6a1ab2414791e9d5de6ef) Thanks [@Waxer59](https://github.com/Waxer59)! - Add Spanish translation for `search.devWarning`
35
+
3
36
  ## 0.2.0
4
37
 
5
38
  ### Minor Changes
File without changes
@@ -43,9 +43,8 @@ const pagefindTranslations = {
43
43
  </button>
44
44
  {
45
45
  import.meta.env.DEV ? (
46
- <div style="margin: auto; text-align: center;" dir="ltr">
47
- <p>Search is only available in production builds.</p>
48
- <p>Try building and previewing the site to test it out locally.</p>
46
+ <div style="margin: auto; text-align: center; white-space: pre-line;" dir="ltr">
47
+ <p>{t("search.devWarning")}</p>
49
48
  </div>
50
49
  ) : (
51
50
  <div class="search-container">
package/index.astro CHANGED
@@ -1,122 +1,15 @@
1
1
  ---
2
2
  import type { InferGetStaticPropsType } from 'astro';
3
- import config from 'virtual:starlight/user-config';
4
-
5
- import { getSidebar } from './utils/navigation';
6
3
  import { paths } from './utils/routing';
7
4
 
8
- // Built-in CSS styles.
9
- import './style/props.css';
10
- import './style/reset.css';
11
- import './style/shiki.css';
12
- import './style/util.css';
13
-
14
- // Components — can override built-in CSS, but not user CSS.
15
- import ContentPanel from './components/ContentPanel.astro';
16
- import FallbackContentNotice from './components/FallbackContentNotice.astro';
17
- import HeadSEO from './components/HeadSEO.astro';
18
- import Header from './components/Header.astro';
19
- import Footer from './components/Footer.astro';
20
- import MarkdownContent from './components/MarkdownContent.astro';
21
- import RightSidebar from './components/RightSidebar.astro';
22
- import Sidebar from './components/Sidebar.astro';
23
- import SkipLink from './components/SkipLink.astro';
24
- import ThemeProvider from './components/ThemeProvider.astro';
25
- import PageFrame from './layout/PageFrame.astro';
26
- import TwoColumnContent from './layout/TwoColumnContent.astro';
27
- import Hero from './components/Hero.astro';
28
-
29
- // Remark component CSS (needs to override `MarkdownContent.astro`)
30
- import './style/asides.css';
31
-
32
- // Important that this is the last import so it can override built-in styles.
33
- import 'virtual:starlight/user-css';
5
+ import Page from './layout/Page.astro';
34
6
 
35
7
  export async function getStaticPaths() {
36
8
  return paths;
37
9
  }
38
10
 
39
11
  type Props = InferGetStaticPropsType<typeof getStaticPaths>;
40
-
41
- const { dir, entry, entryMeta, isFallback, lang, locale } = Astro.props;
42
- const { Content, headings } = await entry.render();
43
- const sidebar = getSidebar(Astro.url.pathname, locale);
44
-
45
- const hasSidebar = entry.data.template !== 'splash';
46
- const tocConfig = !hasSidebar
47
- ? false
48
- : entry.data.tableOfContents !== undefined
49
- ? entry.data.tableOfContents
50
- : config.tableOfContents;
51
- const hasToC = Boolean(tocConfig);
52
- const hasHero = Boolean(entry.data.hero);
12
+ const { Content, headings } = await Astro.props.entry.render();
53
13
  ---
54
14
 
55
- <html lang={lang} dir={dir} data-has-toc={hasToC} data-has-sidebar={hasSidebar} data-has-hero={hasHero}>
56
- <head>
57
- <HeadSEO data={entry.data} lang={lang} />
58
- <style>
59
- html:not([data-has-toc]) {
60
- --sl-mobile-toc-height: 0rem;
61
- }
62
- html:not([data-has-sidebar]) {
63
- --sl-content-width: 67.5rem;
64
- }
65
- /* Add scroll padding to ensure anchor headings aren't obscured by nav */
66
- html {
67
- /* Additional padding is needed to account for the mobile TOC */
68
- scroll-padding-top: calc(
69
- 1.5rem + var(--sl-nav-height) + var(--sl-mobile-toc-height)
70
- );
71
- }
72
- main {
73
- padding-bottom: 3vh;
74
- }
75
- @media (min-width: 50em) {
76
- [data-has-sidebar] {
77
- --sl-content-inline-start: var(--sl-sidebar-width);
78
- }
79
- }
80
- @media (min-width: 72em) {
81
- html {
82
- scroll-padding-top: calc(1.5rem + var(--sl-nav-height));
83
- }
84
- }
85
- </style>
86
- </head>
87
- <body>
88
- <ThemeProvider />
89
- <SkipLink {locale} />
90
- <PageFrame {locale} {hasSidebar}>
91
- <Header slot="header" {locale} />
92
- {hasSidebar && <Sidebar slot="sidebar" {sidebar} {locale} />}
93
- <TwoColumnContent {hasToC}>
94
- <RightSidebar slot="right-sidebar" {headings} {locale} {tocConfig} />
95
- <main data-pagefind-body lang={entryMeta.lang} dir={entryMeta.dir}>
96
- {/* TODO: Revisit how this logic flows. */}
97
- {entry.data.hero ? (
98
- <ContentPanel>
99
- <Hero hero={entry.data.hero} fallbackTitle={entry.data.title} />
100
- <MarkdownContent><Content /></MarkdownContent>
101
- </ContentPanel>
102
- ) : (
103
- <ContentPanel>
104
- <h1
105
- id="_top"
106
- data-page-title
107
- style="font-size: var(--sl-text-h1); line-height: var(--sl-line-height-headings); font-weight: 600; color: var(--sl-color-white); margin-top: 1rem;"
108
- >
109
- {entry.data.title}
110
- </h1>
111
- {isFallback && <FallbackContentNotice {locale} />}
112
- </ContentPanel>
113
- <ContentPanel>
114
- <MarkdownContent><Content /></MarkdownContent>
115
- <Footer {...{ entry, dir, lang, locale, sidebar }} />
116
- </ContentPanel>
117
- )}
118
- </main>
119
- </TwoColumnContent>
120
- </PageFrame>
121
- </body>
122
- </html>
15
+ <Page {...Astro.props} {headings}><Content /></Page>
@@ -0,0 +1,116 @@
1
+ ---
2
+ import config from 'virtual:starlight/user-config';
3
+ import type { MarkdownHeading } from 'astro';
4
+ import { getSidebar } from '../utils/navigation';
5
+ import type { Route } from '../utils/routing';
6
+
7
+ // Built-in CSS styles.
8
+ import '../style/props.css';
9
+ import '../style/reset.css';
10
+ import '../style/shiki.css';
11
+ import '../style/util.css';
12
+
13
+ // Components — can override built-in CSS, but not user CSS.
14
+ import ContentPanel from '../components/ContentPanel.astro';
15
+ import FallbackContentNotice from '../components/FallbackContentNotice.astro';
16
+ import Footer from '../components/Footer.astro';
17
+ import HeadSEO from '../components/HeadSEO.astro';
18
+ import Header from '../components/Header.astro';
19
+ import Hero from '../components/Hero.astro';
20
+ import MarkdownContent from '../components/MarkdownContent.astro';
21
+ import RightSidebar from '../components/RightSidebar.astro';
22
+ import Sidebar from '../components/Sidebar.astro';
23
+ import SkipLink from '../components/SkipLink.astro';
24
+ import ThemeProvider from '../components/ThemeProvider.astro';
25
+ import PageFrame from '../layout/PageFrame.astro';
26
+ import TwoColumnContent from '../layout/TwoColumnContent.astro';
27
+
28
+ // Remark component CSS (needs to override `MarkdownContent.astro`)
29
+ import '../style/asides.css';
30
+
31
+ // Important that this is the last import so it can override built-in styles.
32
+ import 'virtual:starlight/user-css';
33
+
34
+ type Props = Route & { headings: MarkdownHeading[] };
35
+
36
+ const { dir, entry, entryMeta, headings, isFallback, lang, locale } = Astro.props;
37
+ const sidebar = getSidebar(Astro.url.pathname, locale);
38
+
39
+ const hasSidebar = entry.data.template !== 'splash';
40
+ const tocConfig = !hasSidebar
41
+ ? false
42
+ : entry.data.tableOfContents !== undefined
43
+ ? entry.data.tableOfContents
44
+ : config.tableOfContents;
45
+ const hasToC = Boolean(tocConfig);
46
+ const hasHero = Boolean(entry.data.hero);
47
+ ---
48
+
49
+ <html lang={lang} dir={dir} data-has-toc={hasToC} data-has-sidebar={hasSidebar} data-has-hero={hasHero}>
50
+ <head>
51
+ <HeadSEO data={entry.data} lang={lang} />
52
+ <style>
53
+ html:not([data-has-toc]) {
54
+ --sl-mobile-toc-height: 0rem;
55
+ }
56
+ html:not([data-has-sidebar]) {
57
+ --sl-content-width: 67.5rem;
58
+ }
59
+ /* Add scroll padding to ensure anchor headings aren't obscured by nav */
60
+ html {
61
+ /* Additional padding is needed to account for the mobile TOC */
62
+ scroll-padding-top: calc(
63
+ 1.5rem + var(--sl-nav-height) + var(--sl-mobile-toc-height)
64
+ );
65
+ }
66
+ main {
67
+ padding-bottom: 3vh;
68
+ }
69
+ @media (min-width: 50em) {
70
+ [data-has-sidebar] {
71
+ --sl-content-inline-start: var(--sl-sidebar-width);
72
+ }
73
+ }
74
+ @media (min-width: 72em) {
75
+ html {
76
+ scroll-padding-top: calc(1.5rem + var(--sl-nav-height));
77
+ }
78
+ }
79
+ </style>
80
+ </head>
81
+ <body>
82
+ <ThemeProvider />
83
+ <SkipLink {locale} />
84
+ <PageFrame {locale} {hasSidebar}>
85
+ <Header slot="header" {locale} />
86
+ {hasSidebar && <Sidebar slot="sidebar" {sidebar} {locale} />}
87
+ <TwoColumnContent {hasToC}>
88
+ <RightSidebar slot="right-sidebar" {headings} {locale} {tocConfig} />
89
+ <main data-pagefind-body={entry.slug !== '404'} lang={entryMeta.lang} dir={entryMeta.dir}>
90
+ {/* TODO: Revisit how this logic flows. */}
91
+ {entry.data.hero ? (
92
+ <ContentPanel>
93
+ <Hero hero={entry.data.hero} fallbackTitle={entry.data.title} />
94
+ <MarkdownContent><slot /></MarkdownContent>
95
+ </ContentPanel>
96
+ ) : (
97
+ <ContentPanel>
98
+ <h1
99
+ id="_top"
100
+ data-page-title
101
+ style="font-size: var(--sl-text-h1); line-height: var(--sl-line-height-headings); font-weight: 600; color: var(--sl-color-white); margin-top: 1rem;"
102
+ >
103
+ {entry.data.title}
104
+ </h1>
105
+ {isFallback && <FallbackContentNotice {locale} />}
106
+ </ContentPanel>
107
+ <ContentPanel>
108
+ <MarkdownContent><slot /></MarkdownContent>
109
+ <Footer {...{ entry, dir, lang, locale, sidebar }} />
110
+ </ContentPanel>
111
+ )}
112
+ </main>
113
+ </TwoColumnContent>
114
+ </PageFrame>
115
+ </body>
116
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/starlight",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "Build beautiful, high-performance documentation websites with Astro",
5
5
  "keywords": [
6
6
  "docs",
package/schemas/i18n.ts CHANGED
@@ -29,6 +29,10 @@ function starlightI18nSchema() {
29
29
  .string()
30
30
  .describe('Text for the “Cancel” button that closes the search modal.'),
31
31
 
32
+ 'search.devWarning': z
33
+ .string()
34
+ .describe('Warning displayed when opening the Search in a dev environment.'),
35
+
32
36
  'themeSelect.accessibleLabel': z
33
37
  .string()
34
38
  .describe('Accessible label for the theme selection dropdown.'),
@@ -94,6 +98,10 @@ function starlightI18nSchema() {
94
98
  .describe(
95
99
  'Label shown on the “next page” pagination arrow in the page footer.'
96
100
  ),
101
+
102
+ '404.text': z
103
+ .string()
104
+ .describe('Text shown on Starlight’s default 404 page'),
97
105
  })
98
106
  .partial();
99
107
  }
@@ -0,0 +1,22 @@
1
+ {
2
+ "skipLink.label": "Přeskočit na obsah",
3
+ "search.label": "Hledat",
4
+ "search.shortcutLabel": "(Vyhledejte stisknutím /)",
5
+ "search.cancelLabel": "Zrušit",
6
+ "search.devWarning": "Vyhledávání je dostupné pouze v produkčních sestaveních. \nZkuste sestavit a zobrazit náhled webu a otestovat jej lokálně.",
7
+ "themeSelect.accessibleLabel": "Vyberte motiv",
8
+ "themeSelect.dark": "Tmavý",
9
+ "themeSelect.light": "Světlý",
10
+ "themeSelect.auto": "Auto",
11
+ "languageSelect.accessibleLabel": "Vyberte jazyk",
12
+ "menuButton.accessibleLabel": "Nabídka",
13
+ "sidebarNav.accessibleLabel": "Hlavní",
14
+ "tableOfContents.onThisPage": "Na této stránce",
15
+ "tableOfContents.overview": "Přehled",
16
+ "i18n.untranslatedContent": "Tento obsah zatím není dostupný ve vašem jazyce.",
17
+ "page.editLink": "Upravit stránku",
18
+ "page.lastUpdated": "Poslední aktualizace:",
19
+ "page.previousLink": "Předchozí",
20
+ "page.nextLink": "Další",
21
+ "404.text": "Stránka nenalezena. Zkontrolujte adresu URL nebo zkuste použít vyhledávací pole."
22
+ }
@@ -3,6 +3,7 @@
3
3
  "search.label": "Suchen",
4
4
  "search.shortcutLabel": "(Drücke / zum Suchen)",
5
5
  "search.cancelLabel": "Abbrechen",
6
+ "search.devWarning": "Search is only available in production builds. \nTry building and previewing the site to test it out locally.",
6
7
  "themeSelect.accessibleLabel": "Farbschema wählen",
7
8
  "themeSelect.dark": "Dunkel",
8
9
  "themeSelect.light": "Hell",
@@ -16,5 +17,6 @@
16
17
  "page.editLink": "Seite bearbeiten",
17
18
  "page.lastUpdated": "Zuletzt bearbeitet:",
18
19
  "page.previousLink": "Vorherige Seite",
19
- "page.nextLink": "Nächste Seite"
20
+ "page.nextLink": "Nächste Seite",
21
+ "404.text": "Seite nicht gefunden. Überprüfe die URL oder nutze die Suchleiste."
20
22
  }
@@ -3,6 +3,7 @@
3
3
  "search.label": "Search",
4
4
  "search.shortcutLabel": "(Press / to Search)",
5
5
  "search.cancelLabel": "Cancel",
6
+ "search.devWarning": "Search is only available in production builds. \nTry building and previewing the site to test it out locally.",
6
7
  "themeSelect.accessibleLabel": "Select theme",
7
8
  "themeSelect.dark": "Dark",
8
9
  "themeSelect.light": "Light",
@@ -16,5 +17,6 @@
16
17
  "page.editLink": "Edit page",
17
18
  "page.lastUpdated": "Last updated:",
18
19
  "page.previousLink": "Previous",
19
- "page.nextLink": "Next"
20
+ "page.nextLink": "Next",
21
+ "404.text": "Page not found. Check the URL or try using the search bar."
20
22
  }
@@ -3,6 +3,7 @@
3
3
  "search.label": "Buscar",
4
4
  "search.shortcutLabel": "(Presiona / para buscar)",
5
5
  "search.cancelLabel": "Interrumpir",
6
+ "search.devWarning": "La búsqueda solo está disponible en las versiones de producción. \nIntenta construir y previsualizar el sitio para probarlo localmente.",
6
7
  "themeSelect.accessibleLabel": "Seleccionar tema",
7
8
  "themeSelect.dark": "Oscuro",
8
9
  "themeSelect.light": "Claro",
@@ -16,5 +17,6 @@
16
17
  "page.editLink": "Edita esta página",
17
18
  "page.lastUpdated": "Última actualización:",
18
19
  "page.previousLink": "Página anterior",
19
- "page.nextLink": "Siguiente página"
20
+ "page.nextLink": "Siguiente página",
21
+ "404.text": "Página no encontrada. Verifique la URL o intente usar la barra de búsqueda."
20
22
  }
@@ -3,6 +3,7 @@
3
3
  "search.label": "Rechercher",
4
4
  "search.shortcutLabel": "(Presser / pour rechercher)",
5
5
  "search.cancelLabel": "Annuler",
6
+ "search.devWarning": "Search is only available in production builds. \nTry building and previewing the site to test it out locally.",
6
7
  "themeSelect.accessibleLabel": "Selectionner le thème",
7
8
  "themeSelect.dark": "Dark",
8
9
  "themeSelect.light": "Light",
@@ -16,5 +17,6 @@
16
17
  "page.editLink": "Editer la page",
17
18
  "page.lastUpdated": "Dernière mise à jour :",
18
19
  "page.previousLink": "Précédent",
19
- "page.nextLink": "Suivant"
20
+ "page.nextLink": "Suivant",
21
+ "404.text": "Page non trouvée. Vérifiez l'URL ou essayez d'utiliser la barre de recherche."
20
22
  }
@@ -1,4 +1,5 @@
1
1
  import { builtinI18nSchema } from '../schemas/i18n';
2
+ import cs from './cs.json';
2
3
  import en from './en.json';
3
4
  import es from './es.json';
4
5
  import de from './de.json';
@@ -10,5 +11,5 @@ import it from './it.json';
10
11
  const { parse } = builtinI18nSchema();
11
12
 
12
13
  export default Object.fromEntries(
13
- Object.entries({ en, es, de, ja, pt, fr, it }).map(([key, dict]) => [key, parse(dict)])
14
+ Object.entries({ cs, en, es, de, ja, pt, fr, it }).map(([key, dict]) => [key, parse(dict)])
14
15
  );
@@ -3,6 +3,7 @@
3
3
  "search.label": "Cerca",
4
4
  "search.shortcutLabel": "(Usa / per cercare)",
5
5
  "search.cancelLabel": "Cancella",
6
+ "search.devWarning": "Search is only available in production builds. \nTry building and previewing the site to test it out locally.",
6
7
  "themeSelect.accessibleLabel": "Seleziona tema",
7
8
  "themeSelect.dark": "Scuro",
8
9
  "themeSelect.light": "Chiaro",
@@ -16,5 +17,6 @@
16
17
  "page.editLink": "Modifica pagina",
17
18
  "page.lastUpdated": "Ultimo aggiornamento:",
18
19
  "page.previousLink": "Indietro",
19
- "page.nextLink": "Avanti"
20
+ "page.nextLink": "Avanti",
21
+ "404.text": "Pagina non trovata. Verifica l'URL o prova a utilizzare la barra di ricerca."
20
22
  }
@@ -3,6 +3,7 @@
3
3
  "search.label": "検索",
4
4
  "search.shortcutLabel": "(/を押して検索)",
5
5
  "search.cancelLabel": "キャンセル",
6
+ "search.devWarning": "検索はプロダクションビルドでのみ利用可能です。\nローカルでテストするには、サイトをビルドしてプレビューしてください。",
6
7
  "themeSelect.accessibleLabel": "テーマの選択",
7
8
  "themeSelect.dark": "ダーク",
8
9
  "themeSelect.light": "ライト",
@@ -16,5 +17,6 @@
16
17
  "page.editLink": "ページを編集",
17
18
  "page.lastUpdated": "最終更新日:",
18
19
  "page.previousLink": "前へ",
19
- "page.nextLink": "次へ"
20
+ "page.nextLink": "次へ",
21
+ "404.text": "ページが見つかりません。 URL を確認するか、検索バーを使用してみてください。"
20
22
  }
@@ -3,6 +3,7 @@
3
3
  "search.label": "Pesquisar",
4
4
  "search.shortcutLabel": "(Pressione / para Pesquisar)",
5
5
  "search.cancelLabel": "Cancelar",
6
+ "search.devWarning": "A pesquisa está disponível apenas em builds em produção. \nTente fazer a build e pré-visualize o site para testar localmente.",
6
7
  "themeSelect.accessibleLabel": "Selecionar tema",
7
8
  "themeSelect.dark": "Escuro",
8
9
  "themeSelect.light": "Claro",
@@ -16,5 +17,6 @@
16
17
  "page.editLink": "Editar página",
17
18
  "page.lastUpdated": "Última atualização:",
18
19
  "page.previousLink": "Anterior",
19
- "page.nextLink": "Próximo"
20
+ "page.nextLink": "Próximo",
21
+ "404.text": "Página não encontrada. Verifique o URL ou tente usar a barra de pesquisa."
20
22
  }
@@ -69,9 +69,9 @@ function groupFromAutogenerateConfig(
69
69
  const dirDocs = routes.filter(
70
70
  (doc) =>
71
71
  // Match against `foo.md` or `foo/index.md`.
72
- doc.slug === localeDir ||
72
+ stripExtension(doc.id) === localeDir ||
73
73
  // Match against `foo/anything/else.md`.
74
- doc.slug.startsWith(localeDir + '/')
74
+ doc.id.startsWith(localeDir + '/')
75
75
  );
76
76
  const tree = treeify(dirDocs, localeDir);
77
77
  return {
@@ -115,16 +115,18 @@ function makeLink(href: string, label: string, currentPathname: string): Link {
115
115
  }
116
116
 
117
117
  /** Get the segments leading to a page. */
118
- function getBreadcrumbs(slug: string, baseDir: string): string[] {
119
- // Index slugs will match `baseDir` and don’t include breadcrumbs.
120
- if (slug === baseDir) return [];
118
+ function getBreadcrumbs(path: string, baseDir: string): string[] {
119
+ // Strip extension from path.
120
+ const pathWithoutExt = stripExtension(path);
121
+ // Index paths will match `baseDir` and don’t include breadcrumbs.
122
+ if (pathWithoutExt === baseDir) return [];
121
123
  // Ensure base directory ends in a trailing slash.
122
124
  if (!baseDir.endsWith('/')) baseDir += '/';
123
- // Strip base directory from slug if present.
124
- const relativeSlug = slug.startsWith(baseDir)
125
- ? slug.replace(baseDir, '')
126
- : slug;
127
- let dir = dirname(relativeSlug);
125
+ // Strip base directory from path if present.
126
+ const relativePath = pathWithoutExt.startsWith(baseDir)
127
+ ? pathWithoutExt.replace(baseDir, '')
128
+ : pathWithoutExt;
129
+ let dir = dirname(relativePath);
128
130
  // Return no breadcrumbs for items in the root directory.
129
131
  if (dir === '.') return [];
130
132
  return dir.split('/');
@@ -134,7 +136,7 @@ function getBreadcrumbs(slug: string, baseDir: string): string[] {
134
136
  function treeify(routes: Route[], baseDir: string): Dir {
135
137
  const treeRoot: Dir = {};
136
138
  routes.forEach((doc) => {
137
- const breadcrumbs = getBreadcrumbs(doc.slug, baseDir);
139
+ const breadcrumbs = getBreadcrumbs(doc.id, baseDir);
138
140
 
139
141
  // Walk down the route’s path to generate the tree.
140
142
  let currentDir = treeRoot;
@@ -236,3 +238,6 @@ export function getPrevNextLinks(sidebar: SidebarEntry[]): {
236
238
  const next = currentIndex > -1 ? entries[currentIndex + 1] : undefined;
237
239
  return { prev, next };
238
240
  }
241
+
242
+ /** Remove the extension from a path. */
243
+ const stripExtension = (path: string) => path.replace(/\.\w+$/, '');
package/utils/routing.ts CHANGED
@@ -3,6 +3,7 @@ import { CollectionEntry, getCollection } from 'astro:content';
3
3
  import config from 'virtual:starlight/user-config';
4
4
  import {
5
5
  LocaleData,
6
+ localizedId,
6
7
  localizedSlug,
7
8
  slugToLocaleData,
8
9
  slugToParam,
@@ -16,6 +17,7 @@ export interface Route extends LocaleData {
16
17
  entry: StarlightDocsEntry;
17
18
  entryMeta: LocaleData;
18
19
  slug: string;
20
+ id: string;
19
21
  isFallback?: true;
20
22
  [key: string]: unknown;
21
23
  }
@@ -41,6 +43,7 @@ function getRoutes(): Route[] {
41
43
  const routes: Route[] = docs.map((entry) => ({
42
44
  entry,
43
45
  slug: entry.slug,
46
+ id: entry.id,
44
47
  entryMeta: slugToLocaleData(entry.slug),
45
48
  ...slugToLocaleData(entry.slug),
46
49
  }));
@@ -61,11 +64,13 @@ function getRoutes(): Route[] {
61
64
  const localeDocs = getLocaleDocs(locale);
62
65
  for (const fallback of defaultLocaleDocs) {
63
66
  const slug = localizedSlug(fallback.slug, locale);
67
+ const id = localizedId(fallback.id, locale);
64
68
  const doesNotNeedFallback = localeDocs.some((doc) => doc.slug === slug);
65
69
  if (doesNotNeedFallback) continue;
66
70
  routes.push({
67
71
  entry: fallback,
68
72
  slug,
73
+ id,
69
74
  isFallback: true,
70
75
  lang: localeConfig.lang || 'en',
71
76
  locale,
package/utils/slugs.ts CHANGED
@@ -90,3 +90,24 @@ export function localizedSlug(
90
90
  }
91
91
  return slug ? locale + '/' + slug : locale;
92
92
  }
93
+
94
+ /**
95
+ * Convert a collection entry ID to a different locale.
96
+ * For example, passing an ID of `en/home.md` and a locale of `fr` results in `fr/home.md`.
97
+ * An undefined locale is treated as the root locale, resulting in `home.md`.
98
+ * @param id A collection entry ID
99
+ * @param locale The target locale
100
+ * @example
101
+ * localizedSlug('en/home.md', 'fr') // => 'fr/home.md'
102
+ * localizedSlug('en/home.md', undefined) // => 'home.md'
103
+ */
104
+ export function localizedId(id: string, locale: string | undefined): string {
105
+ const idLocale = slugToLocale(id);
106
+ if (idLocale) {
107
+ return id.replace(idLocale + '/', locale ? locale + '/' : '');
108
+ } else if (locale) {
109
+ return locale + '/' + id;
110
+ } else {
111
+ return id;
112
+ }
113
+ }