-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathprepare-build.js
More file actions
163 lines (140 loc) · 5.1 KB
/
prepare-build.js
File metadata and controls
163 lines (140 loc) · 5.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#!/usr/bin/env node
/**
* Pre-build script for Ultra Card
* Syncs translation files to ensure all language files have the same keys as en.json
*/
const fs = require('fs');
const path = require('path');
console.log('🔄 Running pre-build checks...\n');
/**
* Function to sync version from version.ts to package.json
* version.ts is the single source of truth for the version
*/
function syncVersion() {
console.log('📦 Syncing version from version.ts...');
const versionTsPath = path.resolve(__dirname, 'src/version.ts');
const packageJsonPath = path.resolve(__dirname, 'package.json');
try {
const versionTsContent = fs.readFileSync(versionTsPath, 'utf8');
const versionMatch = versionTsContent.match(/VERSION\s*=\s*['"]([^'"]+)['"]/);
if (!versionMatch) {
console.error('❌ Could not extract version from version.ts');
return;
}
const version = versionMatch[1];
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
if (packageJson.version !== version) {
packageJson.version = version;
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
console.log(` ✅ Updated package.json version to ${version}`);
} else {
console.log(` ✅ package.json version already at ${version}`);
}
} catch (error) {
console.error('❌ Error syncing version:', error);
}
}
/**
* Function to synchronize translation files
* This ensures all keys present in the English file exist in all other language files
*/
function syncTranslationFiles() {
console.log('📝 Syncing translation files...');
const translationsDir = path.resolve(__dirname, 'src/translations');
const enFilePath = path.resolve(translationsDir, 'en.json');
// Ensure the translations directory exists
if (!fs.existsSync(translationsDir)) {
console.error('❌ Translations directory not found!');
return;
}
// Read the English file as the source of truth
let enTranslations;
try {
enTranslations = JSON.parse(fs.readFileSync(enFilePath, 'utf8'));
} catch (error) {
console.error('❌ Error reading English translations file:', error);
return;
}
// Get all translation files (exclude glossary and per-locale meta sidecars)
const translationFiles = fs.readdirSync(translationsDir).filter(file => {
if (!file.endsWith('.json')) return false;
if (file === 'en.json') return false;
if (file.startsWith('_')) return false;
if (file.endsWith('.meta.json')) return false;
return true;
});
if (translationFiles.length === 0) {
console.log(' No additional translation files found.');
return;
}
/**
* Ensure all keys from source exist in target; record each added path (English fallback).
* @param {Record<string, unknown>} sourceObj
* @param {Record<string, unknown>} targetObj
* @param {string} pathPrefix
* @param {string[]} backfilled
* @returns {boolean}
*/
function ensureKeysExist(sourceObj, targetObj, pathPrefix = '', backfilled = []) {
let modified = false;
for (const key of Object.keys(sourceObj)) {
const newPath = pathPrefix ? `${pathPrefix}.${key}` : key;
if (!(key in targetObj)) {
targetObj[key] = sourceObj[key];
backfilled.push(newPath);
modified = true;
continue;
}
if (
typeof sourceObj[key] === 'object' &&
sourceObj[key] !== null &&
typeof targetObj[key] === 'object' &&
targetObj[key] !== null
) {
const subModified = ensureKeysExist(
/** @type {Record<string, unknown>} */ (sourceObj[key]),
/** @type {Record<string, unknown>} */ (targetObj[key]),
newPath,
backfilled
);
if (subModified) modified = true;
}
}
return modified;
}
let totalModified = 0;
for (const file of translationFiles) {
const filePath = path.resolve(translationsDir, file);
try {
let translations = JSON.parse(fs.readFileSync(filePath, 'utf8'));
const backfilled = [];
const modified = ensureKeysExist(enTranslations, translations, '', backfilled);
if (modified) {
fs.writeFileSync(filePath, JSON.stringify(translations, null, 2) + '\n');
totalModified++;
}
if (backfilled.length > 0) {
console.log(
` [translations] ${file}: backfilled ${backfilled.length} missing key(s) from en.json (English until translated).`
);
if (process.env.TRANSLATIONS_VERBOSE === '1') {
backfilled.slice(0, 40).forEach(p => console.log(` + ${p}`));
if (backfilled.length > 40) {
console.log(` ... and ${backfilled.length - 40} more (set TRANSLATIONS_VERBOSE=1 already on)`);
}
}
}
} catch (error) {
console.error(` ❌ Error processing translation file ${file}:`, error);
}
}
if (totalModified > 0) {
console.log(` ✅ Updated ${totalModified} translation file(s)`);
} else {
console.log(' ✅ All translation files are in sync');
}
}
// Run the synchronization
syncVersion();
syncTranslationFiles();
console.log('\n✨ Pre-build checks complete!\n');