@@ -14,6 +14,21 @@ const __filename = fileURLToPath(import.meta.url);
1414const __dirname = path . dirname ( __filename ) ;
1515const rootDir = path . join ( __dirname , '..' ) ;
1616
17+ // Read supported locales from i18n config
18+ function getSupportedLocales ( ) {
19+ const configPath = path . join ( rootDir , 'src/i18n/config.ts' ) ;
20+ const configContent = fs . readFileSync ( configPath , 'utf8' ) ;
21+ // Extract locales array from: export const locales = ['en', 'zh-Hans', 'de'] as const;
22+ const match = configContent . match ( / e x p o r t c o n s t l o c a l e s = \[ ( [ ^ \] ] + ) \] / ) ;
23+ if ( ! match ) {
24+ throw new Error ( 'Could not find locales export in src/i18n/config.ts' ) ;
25+ }
26+ // Parse the array: "'en', 'zh-Hans', 'de'" -> ['en', 'zh-Hans', 'de']
27+ return match [ 1 ] . split ( ',' ) . map ( s => s . trim ( ) . replace ( / [ ' " ] / g, '' ) ) ;
28+ }
29+
30+ const SUPPORTED_LOCALES = getSupportedLocales ( ) ;
31+
1732function getMDXFiles ( directory ) {
1833 return fs . readdirSync ( directory ) . filter ( file => file . endsWith ( '.mdx' ) ) ;
1934}
@@ -28,11 +43,6 @@ function getSlugFromFilename(fileName) {
2843 return fileName . replace ( / \. m d x $ / , '' ) ;
2944}
3045
31- function extractH1FromMDX ( content ) {
32- const match = content . match ( / ^ # \s + ( .+ ) $ / m) ;
33- return match ? match [ 1 ] . trim ( ) : '' ;
34- }
35-
3646// Parse FAQ sections from a unified index.mdx file
3747// Each H1 heading becomes a FAQ item with its title and content
3848function parseFaqSections ( content ) {
@@ -43,7 +53,6 @@ function parseFaqSections(content) {
4353 const sections = [ ] ;
4454 const h1Regex = / ^ # ( .+ ) $ / gm;
4555 let match ;
46- let lastIndex = 0 ;
4756 const matches = [ ] ;
4857
4958 // Find all H1 headings and their positions
@@ -106,7 +115,6 @@ function generateArticlesMetadataForLocale(locale) {
106115
107116// Generate articles metadata for all locales
108117function generateArticlesMetadata ( ) {
109- const SUPPORTED_LOCALES = [ 'en' , 'zh-Hans' ] ;
110118 const articlesMetadata = { } ;
111119
112120 for ( const locale of SUPPORTED_LOCALES ) {
@@ -145,7 +153,6 @@ function generateDocsMetadataForLocale(locale) {
145153
146154// Generate docs metadata for all locales
147155function generateDocsMetadata ( ) {
148- const SUPPORTED_LOCALES = [ 'en' , 'zh-Hans' ] ;
149156 const docsMetadata = { } ;
150157
151158 for ( const locale of SUPPORTED_LOCALES ) {
@@ -186,7 +193,6 @@ function generateFaqMetadataForLocale(locale) {
186193
187194// Generate FAQ metadata for all locales
188195function generateFaqMetadata ( ) {
189- const SUPPORTED_LOCALES = [ 'en' , 'zh-Hans' ] ;
190196 const faqMetadata = { } ;
191197
192198 for ( const locale of SUPPORTED_LOCALES ) {
@@ -208,9 +214,6 @@ function generateStackCounts() {
208214 vendors : 'vendors' ,
209215 } ;
210216
211- // Single files (old structure)
212- const singleFiles = { } ;
213-
214217 const stackCounts = { } ;
215218
216219 // Count files in directories
@@ -232,27 +235,45 @@ function generateStackCounts() {
232235 }
233236 }
234237
235- // Count items in single files
236- for ( const [ stackId , fileName ] of Object . entries ( singleFiles ) ) {
237- const manifestPath = path . join ( rootDir , 'manifests' , fileName ) ;
238+ return stackCounts ;
239+ }
238240
239- if ( ! fs . existsSync ( manifestPath ) ) {
240- console . warn ( `⚠️ Manifest file not found: ${ manifestPath } ` ) ;
241- stackCounts [ stackId ] = 0 ;
242- continue ;
241+ // Generate component imports for articles
242+ function generateArticleComponentsCode ( articles ) {
243+ const locales = Object . keys ( articles ) ;
244+ const componentLines = [ ] ;
245+
246+ for ( const locale of locales ) {
247+ const localeArticles = articles [ locale ] ;
248+ const componentEntries = localeArticles . map ( article =>
249+ ` '${ article . slug } ': require('@content/articles/${ locale } /${ article . slug } .mdx').default,`
250+ ) . join ( '\n' ) ;
251+
252+ if ( componentEntries ) {
253+ componentLines . push ( ` '${ locale } ': {\n${ componentEntries } \n },` ) ;
243254 }
255+ }
244256
245- try {
246- const fileContents = fs . readFileSync ( manifestPath , 'utf8' ) ;
247- const manifestData = JSON . parse ( fileContents ) ;
248- stackCounts [ stackId ] = Array . isArray ( manifestData ) ? manifestData . length : 0 ;
249- } catch ( error ) {
250- console . error ( `❌ Error reading ${ fileName } :` , error . message ) ;
251- stackCounts [ stackId ] = 0 ;
257+ return `const articleComponents: Record<string, Record<string, React.ComponentType>> = {\n${ componentLines . join ( '\n' ) } \n};` ;
258+ }
259+
260+ // Generate component imports for docs
261+ function generateDocComponentsCode ( docs ) {
262+ const locales = Object . keys ( docs ) ;
263+ const componentLines = [ ] ;
264+
265+ for ( const locale of locales ) {
266+ const localeDocs = docs [ locale ] ;
267+ const componentEntries = localeDocs . map ( doc =>
268+ ` '${ doc . slug } ': require('@content/docs/${ locale } /${ doc . slug } .mdx').default,`
269+ ) . join ( '\n' ) ;
270+
271+ if ( componentEntries ) {
272+ componentLines . push ( ` '${ locale } ': {\n${ componentEntries } \n },` ) ;
252273 }
253274 }
254275
255- return stackCounts ;
276+ return `const docComponents: Record<string, Record<string, React.ComponentType>> = {\n ${ componentLines . join ( '\n' ) } \n};` ;
256277}
257278
258279// Main execution
@@ -277,8 +298,8 @@ function main() {
277298 const content = `// This file is auto-generated by scripts/generate-metadata.mjs
278299// DO NOT EDIT MANUALLY
279300
280- import type { ArticleMetadata } from '.. /articles';
281- import type { DocSection } from '.. /docs';
301+ import type { ArticleMetadata } from './articles';
302+ import type { DocSection } from './docs';
282303import type { CollectionSection } from '../collections';
283304import type { FaqItem } from '../faq';
284305
@@ -295,6 +316,85 @@ export const stackCounts: Record<string, number> = ${JSON.stringify(stackCounts,
295316
296317 fs . writeFileSync ( outputFile , content , 'utf8' ) ;
297318
319+ // Generate articles.ts file in generated directory
320+ const articlesGeneratedFile = path . join ( outputDir , 'articles.ts' ) ;
321+ const articlesComponentsCode = generateArticleComponentsCode ( articles ) ;
322+ const articlesGeneratedContent = `// This file is auto-generated by scripts/generate-metadata.mjs
323+ // DO NOT EDIT MANUALLY
324+
325+ import { articlesMetadata } from './metadata';
326+
327+ export type ArticleMetadata = {
328+ title: string;
329+ description: string;
330+ date: string;
331+ slug: string;
332+ };
333+
334+ // Get articles for a specific locale with fallback to English
335+ export function getArticles(locale: string = 'en'): ArticleMetadata[] {
336+ return articlesMetadata[locale] || articlesMetadata['en'] || [];
337+ }
338+
339+ // Get all articles (backward compatibility)
340+ export const articles: ArticleMetadata[] = getArticles('en');
341+
342+ // Get a specific article by slug for a given locale
343+ export function getArticleBySlug(slug: string, locale: string = 'en'): ArticleMetadata | undefined {
344+ const localeArticles = getArticles(locale);
345+ return localeArticles.find((article) => article.slug === slug);
346+ }
347+
348+ // MDX components mapping for all locales (webpack will handle this at build time)
349+ ${ articlesComponentsCode }
350+
351+ // Get components for a specific locale with fallback to English
352+ export function getArticleComponents(locale: string = 'en'): Record<string, React.ComponentType> {
353+ return articleComponents[locale] || articleComponents['en'] || {};
354+ }
355+ ` ;
356+
357+ fs . writeFileSync ( articlesGeneratedFile , articlesGeneratedContent , 'utf8' ) ;
358+
359+ // Generate docs.ts file in generated directory
360+ const docsGeneratedFile = path . join ( outputDir , 'docs.ts' ) ;
361+ const docsComponentsCode = generateDocComponentsCode ( docs ) ;
362+ const docsGeneratedContent = `// This file is auto-generated by scripts/generate-metadata.mjs
363+ // DO NOT EDIT MANUALLY
364+
365+ import { docsMetadata } from './metadata';
366+
367+ export type DocSection = {
368+ id: string;
369+ title: string;
370+ slug: string;
371+ };
372+
373+ // Get doc sections for a specific locale with fallback to English
374+ export function getDocSections(locale: string): DocSection[] {
375+ return docsMetadata[locale] || docsMetadata['en'] || [];
376+ }
377+
378+ // Get all doc sections (backward compatibility)
379+ export const docSections: DocSection[] = getDocSections('en');
380+
381+ // Get a specific doc by slug for a given locale
382+ export function getDocBySlug(slug: string, locale: string = 'en'): DocSection | undefined {
383+ const sections = getDocSections(locale);
384+ return sections.find((doc) => doc.slug === slug);
385+ }
386+
387+ // MDX components mapping for all locales (webpack will handle this at build time)
388+ ${ docsComponentsCode }
389+
390+ // Get components for a specific locale with fallback to English
391+ export function getDocComponents(locale: string = 'en'): Record<string, React.ComponentType> {
392+ return docComponents[locale] || docComponents['en'] || {};
393+ }
394+ ` ;
395+
396+ fs . writeFileSync ( docsGeneratedFile , docsGeneratedContent , 'utf8' ) ;
397+
298398 // Calculate total docs, articles, and faqs across all locales
299399 const totalDocs = Object . values ( docs ) . reduce ( ( sum , localeDocs ) => sum + localeDocs . length , 0 ) ;
300400 const totalArticles = Object . values ( articles ) . reduce ( ( sum , localeArticles ) => sum + localeArticles . length , 0 ) ;
@@ -307,7 +407,10 @@ export const stackCounts: Record<string, number> = ${JSON.stringify(stackCounts,
307407
308408 console . log ( `✅ Generated metadata for ${ totalArticles } articles (${ articlesLocalesCounts } ), ${ totalDocs } docs (${ docsLocalesCounts } ), ${ totalFaqs } faqs (${ faqsLocalesCounts } ), and collections (${ collectionsLocales } )` ) ;
309409 console . log ( `✅ Generated stack counts: ${ stackCountsSummary } ` ) ;
310- console . log ( `📝 Output: ${ outputFile } ` ) ;
410+ console . log ( `📝 Generated files:` ) ;
411+ console . log ( ` - ${ outputFile } ` ) ;
412+ console . log ( ` - ${ articlesGeneratedFile } ` ) ;
413+ console . log ( ` - ${ docsGeneratedFile } ` ) ;
311414}
312415
313416main ( ) ;
0 commit comments