11import { MarkdownParser , Section } from './markdown-parser.js' ;
22import { Change , Delta , DeltaOperation , Requirement } from '../schemas/index.js' ;
3+ import { CHANGE_SECTIONS , DELTA_SECTIONS , findSectionByTitleVariants } from '../i18n/section-titles.js' ;
34import path from 'path' ;
45import { promises as fs } from 'fs' ;
56
@@ -19,24 +20,27 @@ export class ChangeParser extends MarkdownParser {
1920
2021 async parseChangeWithDeltas ( name : string ) : Promise < Change > {
2122 const sections = this . parseSections ( ) ;
22- const why = this . findSection ( sections , 'Why' ) ?. content || '' ;
23- const whatChanges = this . findSection ( sections , 'What Changes' ) ?. content || '' ;
24-
23+ const whySection = findSectionByTitleVariants ( sections , CHANGE_SECTIONS . WHY ) ;
24+ const whatChangesSection = findSectionByTitleVariants ( sections , CHANGE_SECTIONS . WHAT_CHANGES ) ;
25+
26+ const why = whySection ?. content || '' ;
27+ const whatChanges = whatChangesSection ?. content || '' ;
28+
2529 if ( ! why ) {
26- throw new Error ( 'Change must have a Why section ' ) ;
30+ throw new Error ( '變更必須包含為什麼區段 ' ) ;
2731 }
28-
32+
2933 if ( ! whatChanges ) {
30- throw new Error ( 'Change must have a What Changes section ' ) ;
34+ throw new Error ( '變更必須包含變更內容區段 ' ) ;
3135 }
3236
3337 // Parse deltas from the What Changes section (simple format)
3438 const simpleDeltas = this . parseDeltas ( whatChanges ) ;
35-
39+
3640 // Check if there are spec files with delta format
3741 const specsDir = path . join ( this . changeDir , 'specs' ) ;
3842 const deltaDeltas = await this . parseDeltaSpecs ( specsDir ) ;
39-
43+
4044 // Combine both types of deltas, preferring delta format if available
4145 const deltas = deltaDeltas . length > 0 ? deltaDeltas : simpleDeltas ;
4246
@@ -84,85 +88,86 @@ export class ChangeParser extends MarkdownParser {
8488 private parseSpecDeltas ( specName : string , content : string ) : Delta [ ] {
8589 const deltas : Delta [ ] = [ ] ;
8690 const sections = this . parseSectionsFromContent ( content ) ;
87-
88- // Parse ADDED requirements
89- const addedSection = this . findSection ( sections , ' ADDED Requirements' ) ;
91+
92+ // Parse ADDED requirements (支援多語言)
93+ const addedSection = findSectionByTitleVariants ( sections , DELTA_SECTIONS . ADDED ) ;
9094 if ( addedSection ) {
9195 const requirements = this . parseRequirements ( addedSection ) ;
9296 requirements . forEach ( req => {
9397 deltas . push ( {
9498 spec : specName ,
9599 operation : 'ADDED' as DeltaOperation ,
96- description : `Add requirement: ${ req . text } ` ,
100+ description : `新增需求: ${ req . text } ` ,
97101 // Provide both single and plural forms for compatibility
98102 requirement : req ,
99103 requirements : [ req ] ,
100104 } ) ;
101105 } ) ;
102106 }
103-
104- // Parse MODIFIED requirements
105- const modifiedSection = this . findSection ( sections , ' MODIFIED Requirements' ) ;
107+
108+ // Parse MODIFIED requirements (支援多語言)
109+ const modifiedSection = findSectionByTitleVariants ( sections , DELTA_SECTIONS . MODIFIED ) ;
106110 if ( modifiedSection ) {
107111 const requirements = this . parseRequirements ( modifiedSection ) ;
108112 requirements . forEach ( req => {
109113 deltas . push ( {
110114 spec : specName ,
111115 operation : 'MODIFIED' as DeltaOperation ,
112- description : `Modify requirement: ${ req . text } ` ,
116+ description : `修改需求: ${ req . text } ` ,
113117 requirement : req ,
114118 requirements : [ req ] ,
115119 } ) ;
116120 } ) ;
117121 }
118-
119- // Parse REMOVED requirements
120- const removedSection = this . findSection ( sections , ' REMOVED Requirements' ) ;
122+
123+ // Parse REMOVED requirements (支援多語言)
124+ const removedSection = findSectionByTitleVariants ( sections , DELTA_SECTIONS . REMOVED ) ;
121125 if ( removedSection ) {
122126 const requirements = this . parseRequirements ( removedSection ) ;
123127 requirements . forEach ( req => {
124128 deltas . push ( {
125129 spec : specName ,
126130 operation : 'REMOVED' as DeltaOperation ,
127- description : `Remove requirement: ${ req . text } ` ,
131+ description : `移除需求: ${ req . text } ` ,
128132 requirement : req ,
129133 requirements : [ req ] ,
130134 } ) ;
131135 } ) ;
132136 }
133-
134- // Parse RENAMED requirements
135- const renamedSection = this . findSection ( sections , ' RENAMED Requirements' ) ;
137+
138+ // Parse RENAMED requirements (支援多語言)
139+ const renamedSection = findSectionByTitleVariants ( sections , DELTA_SECTIONS . RENAMED ) ;
136140 if ( renamedSection ) {
137141 const renames = this . parseRenames ( renamedSection . content ) ;
138142 renames . forEach ( rename => {
139143 deltas . push ( {
140144 spec : specName ,
141145 operation : 'RENAMED' as DeltaOperation ,
142- description : `Rename requirement from " ${ rename . from } " to " ${ rename . to } " ` ,
146+ description : `重新命名需求:從「 ${ rename . from } 」改為「 ${ rename . to } 」 ` ,
143147 rename,
144148 } ) ;
145149 } ) ;
146150 }
147-
151+
148152 return deltas ;
149153 }
150154
151155 private parseRenames ( content : string ) : Array < { from : string ; to : string } > {
152156 const renames : Array < { from : string ; to : string } > = [ ] ;
153157 const lines = ChangeParser . normalizeContent ( content ) . split ( '\n' ) ;
154-
158+
155159 let currentRename : { from ?: string ; to ?: string } = { } ;
156-
160+
157161 for ( const line of lines ) {
158- const fromMatch = line . match ( / ^ \s * - ? \s * F R O M : \s * ` ? # # # \s * R e q u i r e m e n t : \s * ( .+ ?) ` ? \s * $ / ) ;
159- const toMatch = line . match ( / ^ \s * - ? \s * T O : \s * ` ? # # # \s * R e q u i r e m e n t : \s * ( .+ ?) ` ? \s * $ / ) ;
160-
162+ // 支援多語言:FROM: 或 從:, ### Requirement: 或 ### 需求:
163+ const fromMatch = line . match ( / ^ \s * - ? \s * (?: F R O M : | 從 : ) \s * ` ? # # # \s * (?: R e q u i r e m e n t : | 需 求 : ) \s * ( .+ ?) ` ? \s * $ / ) ;
164+ const toMatch = line . match ( / ^ \s * - ? \s * (?: T O : | 至 : ) \s * ` ? # # # \s * (?: R e q u i r e m e n t : | 需 求 : ) \s * ( .+ ?) ` ? \s * $ / ) ;
165+
161166 if ( fromMatch ) {
162167 currentRename . from = fromMatch [ 1 ] . trim ( ) ;
163168 } else if ( toMatch ) {
164169 currentRename . to = toMatch [ 1 ] . trim ( ) ;
165-
170+
166171 if ( currentRename . from && currentRename . to ) {
167172 renames . push ( {
168173 from : currentRename . from ,
@@ -172,7 +177,7 @@ export class ChangeParser extends MarkdownParser {
172177 }
173178 }
174179 }
175-
180+
176181 return renames ;
177182 }
178183
0 commit comments