diff --git a/docs/fr/how-to/customize-bmad.md b/docs/fr/how-to/customize-bmad.md index f6a481235..c8975cc55 100644 --- a/docs/fr/how-to/customize-bmad.md +++ b/docs/fr/how-to/customize-bmad.md @@ -84,7 +84,7 @@ Ajouter un contexte persistant que l'agent gardera toujours en mémoire : ```yaml memories: - '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é' ``` diff --git a/docs/how-to/customize-bmad.md b/docs/how-to/customize-bmad.md index cfb75333c..15832df89 100644 --- a/docs/how-to/customize-bmad.md +++ b/docs/how-to/customize-bmad.md @@ -85,7 +85,7 @@ Add persistent context the agent will always remember: ```yaml memories: - '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' ``` diff --git a/docs/zh-cn/how-to/customize-bmad.md b/docs/zh-cn/how-to/customize-bmad.md index 5f762ba20..5ed2d44c3 100644 --- a/docs/zh-cn/how-to/customize-bmad.md +++ b/docs/zh-cn/how-to/customize-bmad.md @@ -85,7 +85,7 @@ persona: ```yaml memories: - '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' ``` diff --git a/tools/build-docs.mjs b/tools/build-docs.mjs index 7d916b515..cada7c0e1 100644 --- a/tools/build-docs.mjs +++ b/tools/build-docs.mjs @@ -14,6 +14,7 @@ import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { getSiteUrl } from '../website/src/lib/site-url.mjs'; +import { translatedLocales } from '../website/src/lib/locales.mjs'; // ============================================================================= // Configuration @@ -288,6 +289,9 @@ function shouldExcludeFromLlm(filePath) { const pathParts = filePath.split(path.sep); 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 return LLM_EXCLUDE_PATTERNS.some((pattern) => filePath.includes(pattern)); } diff --git a/website/astro.config.mjs b/website/astro.config.mjs index b0f44d492..9d7efd99e 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -5,6 +5,7 @@ import sitemap from '@astrojs/sitemap'; import rehypeMarkdownLinks from './src/rehype-markdown-links.js'; import rehypeBasePaths from './src/rehype-base-paths.js'; import { getSiteUrl } from './src/lib/site-url.mjs'; +import { locales } from './src/lib/locales.mjs'; const siteUrl = getSiteUrl(); const urlParts = new URL(siteUrl); @@ -45,22 +46,9 @@ export default defineConfig({ title: 'BMAD Method', 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', - locales: { - root: { - label: 'English', - lang: 'en', - }, - 'zh-cn': { - label: '简体中文', - lang: 'zh-CN', - }, - fr: { - label: 'Français', - lang: 'fr-FR', - }, - }, + locales, logo: { light: './public/img/bmad-light.png', diff --git a/website/src/lib/locales.mjs b/website/src/lib/locales.mjs new file mode 100644 index 000000000..ef7e273e9 --- /dev/null +++ b/website/src/lib/locales.mjs @@ -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'); diff --git a/website/src/pages/404.astro b/website/src/pages/404.astro index 46065d04c..6ae826ab7 100644 --- a/website/src/pages/404.astro +++ b/website/src/pages/404.astro @@ -1,6 +1,7 @@ --- import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro'; import { getEntry } from 'astro:content'; +import { translatedLocales } from '../lib/locales.mjs'; const entry = await getEntry('docs', '404'); const { Content } = await entry.render(); @@ -9,3 +10,18 @@ const { Content } = await entry.render(); + + +