fix(docs): community feedback — typo, locale 404s, llms-full (#2091)
* fix(docs): correct Hasselhoff spelling, add locale-aware 404 redirect Fix "Hasslehoff" → "Hasselhoff" typo in customize-bmad.md across all three locales (en, zh-cn, fr). Add client-side locale detection to 404.astro so GitHub Pages serves the correct localized 404 page instead of always showing English. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(build): exclude translated locales from llms-full.txt llms-full.txt was including zh-cn and fr docs, tripling the content with duplicate information in different languages. Restrict to English only — translations add no value for LLM context consumption. Reduces output from ~393K to ~114K chars (~29k tokens). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(i18n): extract locale config to shared module Move locale definitions from astro.config.mjs into a shared website/src/lib/locales.mjs consumed by astro config, build-docs, and 404.astro. Adding a new locale is now a single-file change. --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
10282a4a14
commit
e3f935fd6d
|
|
@ -84,7 +84,7 @@ Ajouter un contexte persistant que l'agent gardera toujours en mémoire :
|
||||||
```yaml
|
```yaml
|
||||||
memories:
|
memories:
|
||||||
- 'Travaille au Krusty Krab'
|
- 'Travaille au Krusty Krab'
|
||||||
- 'Célébrité préférée : David Hasslehoff'
|
- 'Célébrité préférée : David Hasselhoff'
|
||||||
- 'Appris dans l’Epic 1 que ce n’est pas cool de faire semblant que les tests ont passé'
|
- 'Appris dans l’Epic 1 que ce n’est pas cool de faire semblant que les tests ont passé'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ Add persistent context the agent will always remember:
|
||||||
```yaml
|
```yaml
|
||||||
memories:
|
memories:
|
||||||
- 'Works at Krusty Krab'
|
- 'Works at Krusty Krab'
|
||||||
- 'Favorite Celebrity: David Hasslehoff'
|
- 'Favorite Celebrity: David Hasselhoff'
|
||||||
- 'Learned in Epic 1 that it is not cool to just pretend that tests have passed'
|
- 'Learned in Epic 1 that it is not cool to just pretend that tests have passed'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ persona:
|
||||||
```yaml
|
```yaml
|
||||||
memories:
|
memories:
|
||||||
- 'Works at Krusty Krab'
|
- 'Works at Krusty Krab'
|
||||||
- 'Favorite Celebrity: David Hasslehoff'
|
- 'Favorite Celebrity: David Hasselhoff'
|
||||||
- 'Learned in Epic 1 that it is not cool to just pretend that tests have passed'
|
- 'Learned in Epic 1 that it is not cool to just pretend that tests have passed'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { getSiteUrl } from '../website/src/lib/site-url.mjs';
|
import { getSiteUrl } from '../website/src/lib/site-url.mjs';
|
||||||
|
import { translatedLocales } from '../website/src/lib/locales.mjs';
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// Configuration
|
// Configuration
|
||||||
|
|
@ -288,6 +289,9 @@ function shouldExcludeFromLlm(filePath) {
|
||||||
const pathParts = filePath.split(path.sep);
|
const pathParts = filePath.split(path.sep);
|
||||||
if (pathParts.some((part) => part.startsWith('_'))) return true;
|
if (pathParts.some((part) => part.startsWith('_'))) return true;
|
||||||
|
|
||||||
|
// Exclude non-root locale directories (translations duplicate English content)
|
||||||
|
if (translatedLocales.some((locale) => filePath.startsWith(`${locale}/`) || filePath.startsWith(`${locale}${path.sep}`))) return true;
|
||||||
|
|
||||||
// Check configured patterns
|
// Check configured patterns
|
||||||
return LLM_EXCLUDE_PATTERNS.some((pattern) => filePath.includes(pattern));
|
return LLM_EXCLUDE_PATTERNS.some((pattern) => filePath.includes(pattern));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import sitemap from '@astrojs/sitemap';
|
||||||
import rehypeMarkdownLinks from './src/rehype-markdown-links.js';
|
import rehypeMarkdownLinks from './src/rehype-markdown-links.js';
|
||||||
import rehypeBasePaths from './src/rehype-base-paths.js';
|
import rehypeBasePaths from './src/rehype-base-paths.js';
|
||||||
import { getSiteUrl } from './src/lib/site-url.mjs';
|
import { getSiteUrl } from './src/lib/site-url.mjs';
|
||||||
|
import { locales } from './src/lib/locales.mjs';
|
||||||
|
|
||||||
const siteUrl = getSiteUrl();
|
const siteUrl = getSiteUrl();
|
||||||
const urlParts = new URL(siteUrl);
|
const urlParts = new URL(siteUrl);
|
||||||
|
|
@ -45,22 +46,9 @@ export default defineConfig({
|
||||||
title: 'BMAD Method',
|
title: 'BMAD Method',
|
||||||
tagline: 'AI-driven agile development with specialized agents and workflows that scale from bug fixes to enterprise platforms.',
|
tagline: 'AI-driven agile development with specialized agents and workflows that scale from bug fixes to enterprise platforms.',
|
||||||
|
|
||||||
// i18n: English as root (no URL prefix), Chinese at /zh-cn/, French at /fr/
|
// i18n: locale config from shared module (website/src/lib/locales.mjs)
|
||||||
defaultLocale: 'root',
|
defaultLocale: 'root',
|
||||||
locales: {
|
locales,
|
||||||
root: {
|
|
||||||
label: 'English',
|
|
||||||
lang: 'en',
|
|
||||||
},
|
|
||||||
'zh-cn': {
|
|
||||||
label: '简体中文',
|
|
||||||
lang: 'zh-CN',
|
|
||||||
},
|
|
||||||
fr: {
|
|
||||||
label: 'Français',
|
|
||||||
lang: 'fr-FR',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
logo: {
|
logo: {
|
||||||
light: './public/img/bmad-light.png',
|
light: './public/img/bmad-light.png',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Shared i18n locale configuration.
|
||||||
|
*
|
||||||
|
* Single source of truth for locale definitions used by:
|
||||||
|
* - website/astro.config.mjs (Starlight i18n)
|
||||||
|
* - tools/build-docs.mjs (llms-full.txt locale exclusion)
|
||||||
|
* - website/src/pages/404.astro (client-side locale redirect)
|
||||||
|
*
|
||||||
|
* The root locale (English) uses Starlight's 'root' key convention
|
||||||
|
* (no URL prefix). All other locales get a URL prefix matching their key.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const locales = {
|
||||||
|
root: {
|
||||||
|
label: 'English',
|
||||||
|
lang: 'en',
|
||||||
|
},
|
||||||
|
'zh-cn': {
|
||||||
|
label: '简体中文',
|
||||||
|
lang: 'zh-CN',
|
||||||
|
},
|
||||||
|
fr: {
|
||||||
|
label: 'Français',
|
||||||
|
lang: 'fr-FR',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Non-root locale keys (the URL prefixes for translated content).
|
||||||
|
* @type {string[]}
|
||||||
|
*/
|
||||||
|
export const translatedLocales = Object.keys(locales).filter((k) => k !== 'root');
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
---
|
---
|
||||||
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
|
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
|
||||||
import { getEntry } from 'astro:content';
|
import { getEntry } from 'astro:content';
|
||||||
|
import { translatedLocales } from '../lib/locales.mjs';
|
||||||
|
|
||||||
const entry = await getEntry('docs', '404');
|
const entry = await getEntry('docs', '404');
|
||||||
const { Content } = await entry.render();
|
const { Content } = await entry.render();
|
||||||
|
|
@ -9,3 +10,18 @@ const { Content } = await entry.render();
|
||||||
<StarlightPage frontmatter={{ title: entry.data.title, template: entry.data.template }}>
|
<StarlightPage frontmatter={{ title: entry.data.title, template: entry.data.template }}>
|
||||||
<Content />
|
<Content />
|
||||||
</StarlightPage>
|
</StarlightPage>
|
||||||
|
|
||||||
|
<!-- GitHub Pages serves this single 404.html for all paths.
|
||||||
|
Redirect to the locale-specific 404 page when the URL has a locale prefix. -->
|
||||||
|
<script is:inline define:vars={{ translatedLocales }}>
|
||||||
|
(function () {
|
||||||
|
var path = window.location.pathname;
|
||||||
|
for (var i = 0; i < translatedLocales.length; i++) {
|
||||||
|
var prefix = '/' + translatedLocales[i] + '/';
|
||||||
|
if (path.startsWith(prefix) && path !== prefix + '404/') {
|
||||||
|
window.location.replace(prefix + '404/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue