11const GenerateSchema = require ( "generate-schema" ) ;
22const fs = require ( "fs" ) ;
3+ const path = require ( "path" ) ;
34
4- const schema = GenerateSchema . json ( "Catalogi translations schema" , require ( "../src/customization/translations/en.json" ) ) ;
5+ // Read the input translation file
6+ const translationsPath = path . resolve ( __dirname , "../src/customization/translations/en.json" ) ;
7+ const outputPath = path . resolve ( __dirname , "../src/customization/translations/schema.json" ) ;
8+ const translations = require ( translationsPath ) ;
59
6- fs . writeFileSync ( "./src/customization/translations/schema.json" , JSON . stringify ( schema , null , 2 ) ) ;
10+ // Generate the base schema
11+ console . log ( "Generating schema from translations..." ) ;
12+ const schema = GenerateSchema . json ( "Catalogi translations schema" , translations ) ;
13+
14+ // Enhance the schema with translation-specific features
15+ console . log ( "Enhancing schema with translation validation features..." ) ;
16+
17+ // Set schema version
18+ schema . $schema = "http://json-schema.org/draft-07/schema#" ;
19+ schema . description = "Schema for translation files with support for pluralization and validation" ;
20+
21+ // Add pattern properties for pluralization
22+ schema . patternProperties = {
23+ "^.*_one$" : {
24+ type : "string" ,
25+ description : "Singular form for translation"
26+ } ,
27+ "^.*_other$" : {
28+ type : "string" ,
29+ description : "Plural form for translation"
30+ } ,
31+ "^.*_zero$" : {
32+ type : "string" ,
33+ description : "Zero form for translation"
34+ }
35+ } ;
36+
37+ // Recursively process all objects in the schema to:
38+ // 1. Add additionalProperties: false to ensure no typos slip through
39+ // 2. Add required properties so missing translations are flagged
40+ // 3. Add descriptions where possible
41+ // 4. Add examples from the translations
42+ function enhanceSchemaObject ( schemaObj , translationObj , path = "" ) {
43+ if ( schemaObj . type === "object" && schemaObj . properties ) {
44+ // Don't allow additional properties (catches typos)
45+ schemaObj . additionalProperties = false ;
46+
47+ // Make all properties required
48+ if ( Object . keys ( schemaObj . properties ) . length > 0 ) {
49+ schemaObj . required = Object . keys ( schemaObj . properties ) ;
50+ }
51+
52+ // Process each property
53+ Object . entries ( schemaObj . properties ) . forEach ( ( [ key , prop ] ) => {
54+ const currentPath = path ? `${ path } .${ key } ` : key ;
55+
56+ // Add description based on key characteristics
57+ if ( key . includes ( "hint" ) ) {
58+ prop . description = "Helper text explaining the field" ;
59+ } else if ( key . includes ( "title" ) ) {
60+ prop . description = "Title text" ;
61+ } else if ( key . includes ( "label" ) ) {
62+ prop . description = "Label for a form field or button" ;
63+ } else if ( key . includes ( "button" ) ) {
64+ prop . description = "Text for a button" ;
65+ } else if ( currentPath . startsWith ( "common" ) ) {
66+ prop . description = "Common reusable translation" ;
67+ }
68+
69+ // Add example from the original translation
70+ try {
71+ const pathParts = currentPath . split ( "." ) ;
72+ let example = translationObj ;
73+ let foundExample = true ;
74+
75+ for ( const part of pathParts ) {
76+ if ( example && example [ part ] !== undefined ) {
77+ example = example [ part ] ;
78+ } else {
79+ foundExample = false ;
80+ break ;
81+ }
82+ }
83+
84+ if ( foundExample && typeof example === "string" ) {
85+ prop . examples = [ example ] ;
86+ }
87+ } catch ( e ) {
88+ // Skip if can't extract example
89+ }
90+
91+ // Recursively enhance nested objects
92+ if ( prop . type === "object" ) {
93+ const nestedTranslationObj = getNestedObject ( translationObj , currentPath . split ( "." ) ) ;
94+ enhanceSchemaObject ( prop , nestedTranslationObj || { } , currentPath ) ;
95+ }
96+ } ) ;
97+ }
98+ }
99+
100+ // Helper to safely navigate nested objects
101+ function getNestedObject ( obj , pathArray ) {
102+ return pathArray . reduce ( ( prev , curr ) =>
103+ prev && prev [ curr ] ? prev [ curr ] : undefined , obj ) ;
104+ }
105+
106+ // Apply enhancements
107+ enhanceSchemaObject ( schema , translations ) ;
108+
109+ // Write the enhanced schema
110+ console . log ( `Writing schema to ${ outputPath } ` ) ;
111+ fs . writeFileSync ( outputPath , JSON . stringify ( schema , null , 2 ) ) ;
112+
113+ console . log ( "✅ Schema generation complete!" ) ;
0 commit comments