1
1
const GenerateSchema = require ( "generate-schema" ) ;
2
2
const fs = require ( "fs" ) ;
3
+ const path = require ( "path" ) ;
3
4
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 ) ;
5
9
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