@el-j/google-sheet-translations 1.3.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -55
- package/dist/action-entrypoint.d.ts +2 -0
- package/dist/action-entrypoint.d.ts.map +1 -0
- package/dist/esm/index.js +1226 -0
- package/dist/esm/package.json +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1288 -41
- package/dist/utils/dataConverter/findLocalChanges.d.ts +2 -1
- package/dist/utils/dataConverter/findLocalChanges.d.ts.map +1 -1
- package/dist/utils/localeNormalizer.d.ts +31 -0
- package/dist/utils/localeNormalizer.d.ts.map +1 -1
- package/dist/utils/translationHelpers.d.ts +107 -0
- package/dist/utils/translationHelpers.d.ts.map +1 -0
- package/package.json +21 -14
- package/dist/constants.js +0 -9
- package/dist/constants.js.map +0 -1
- package/dist/getSpreadSheetData.js +0 -170
- package/dist/getSpreadSheetData.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/utils/auth.js +0 -23
- package/dist/utils/auth.js.map +0 -1
- package/dist/utils/configurationHandler.js +0 -29
- package/dist/utils/configurationHandler.js.map +0 -1
- package/dist/utils/dataConverter/convertFromDataJsonFormat.js +0 -47
- package/dist/utils/dataConverter/convertFromDataJsonFormat.js.map +0 -1
- package/dist/utils/dataConverter/convertToDataJsonFormat.js +0 -51
- package/dist/utils/dataConverter/convertToDataJsonFormat.js.map +0 -1
- package/dist/utils/dataConverter/findLocalChanges.js +0 -70
- package/dist/utils/dataConverter/findLocalChanges.js.map +0 -1
- package/dist/utils/fileWriter.js +0 -119
- package/dist/utils/fileWriter.js.map +0 -1
- package/dist/utils/getFileLastModified.js +0 -23
- package/dist/utils/getFileLastModified.js.map +0 -1
- package/dist/utils/isDataJsonNewer.js +0 -40
- package/dist/utils/isDataJsonNewer.js.map +0 -1
- package/dist/utils/localeFilter.js +0 -49
- package/dist/utils/localeFilter.js.map +0 -1
- package/dist/utils/localeNormalizer.js +0 -176
- package/dist/utils/localeNormalizer.js.map +0 -1
- package/dist/utils/publicSheetReader.js +0 -109
- package/dist/utils/publicSheetReader.js.map +0 -1
- package/dist/utils/rateLimiter.js +0 -55
- package/dist/utils/rateLimiter.js.map +0 -1
- package/dist/utils/readDataJson.js +0 -29
- package/dist/utils/readDataJson.js.map +0 -1
- package/dist/utils/sheetProcessor.js +0 -121
- package/dist/utils/sheetProcessor.js.map +0 -1
- package/dist/utils/spreadsheetCreator.js +0 -121
- package/dist/utils/spreadsheetCreator.js.map +0 -1
- package/dist/utils/spreadsheetUpdater.js +0 -227
- package/dist/utils/spreadsheetUpdater.js.map +0 -1
- package/dist/utils/syncManager.js +0 -62
- package/dist/utils/syncManager.js.map +0 -1
- package/dist/utils/validateEnv.js +0 -41
- package/dist/utils/validateEnv.js.map +0 -1
- package/dist/utils/wait.js +0 -19
- package/dist/utils/wait.js.map +0 -1
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.findLocalChanges = findLocalChanges;
|
|
4
|
-
const localeNormalizer_1 = require("../localeNormalizer");
|
|
5
|
-
/**
|
|
6
|
-
* Resolves a locale key from `localData` to the corresponding key actually
|
|
7
|
-
* present in `spreadsheetData`, using a three-step strategy:
|
|
8
|
-
*
|
|
9
|
-
* 1. Exact match – `'en-us'` → `'en-us'`
|
|
10
|
-
* 2. Lowercase match – `'en-US'` → `'en-us'`
|
|
11
|
-
* 3. Language-family prefix – `'en'` or `'en-GB'` → `'en-us'`
|
|
12
|
-
* (when `'en-us'` is the only English variant in the spreadsheet data)
|
|
13
|
-
*
|
|
14
|
-
* Returns `undefined` when no matching locale exists in `spreadsheetData`.
|
|
15
|
-
*/
|
|
16
|
-
function resolveLocaleAlias(locale, spreadsheetData) {
|
|
17
|
-
if (spreadsheetData[locale])
|
|
18
|
-
return locale;
|
|
19
|
-
const lower = locale.toLowerCase();
|
|
20
|
-
if (spreadsheetData[lower])
|
|
21
|
-
return lower;
|
|
22
|
-
const langCode = (0, localeNormalizer_1.getLanguagePrefix)(lower);
|
|
23
|
-
return Object.keys(spreadsheetData).find((k) => (0, localeNormalizer_1.getLanguagePrefix)(k) === langCode);
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Compares local languageData.json with spreadsheet data to find new keys.
|
|
27
|
-
*
|
|
28
|
-
* A key is considered "new" when:
|
|
29
|
-
* - No matching locale exists in `spreadsheetData` for that locale, OR
|
|
30
|
-
* - The sheet or key is absent for the resolved locale.
|
|
31
|
-
*
|
|
32
|
-
* Locale matching is fuzzy: `'en'` and `'en-GB'` will both match against
|
|
33
|
-
* an `'en-us'` entry in `spreadsheetData` (language-family resolution).
|
|
34
|
-
*
|
|
35
|
-
* @param localData - Data from local languageData.json file
|
|
36
|
-
* @param spreadsheetData - Data fetched from the spreadsheet
|
|
37
|
-
* @returns Object with new keys that are in localData but not in spreadsheetData
|
|
38
|
-
*/
|
|
39
|
-
function findLocalChanges(localData, spreadsheetData) {
|
|
40
|
-
const changes = {};
|
|
41
|
-
// Check each locale in local data
|
|
42
|
-
for (const locale of Object.keys(localData)) {
|
|
43
|
-
if (!localData[locale])
|
|
44
|
-
continue;
|
|
45
|
-
// Resolve the locale to the matching key in spreadsheetData (fuzzy match)
|
|
46
|
-
const resolvedLocale = resolveLocaleAlias(locale, spreadsheetData);
|
|
47
|
-
// Check each sheet in local data
|
|
48
|
-
for (const sheet of Object.keys(localData[locale])) {
|
|
49
|
-
if (!localData[locale][sheet])
|
|
50
|
-
continue;
|
|
51
|
-
// Check each key in local data
|
|
52
|
-
for (const key of Object.keys(localData[locale][sheet])) {
|
|
53
|
-
// If the spreadsheet doesn't have this locale, sheet, or key, it's a new key
|
|
54
|
-
const isNewKey = !resolvedLocale ||
|
|
55
|
-
!spreadsheetData[resolvedLocale]?.[sheet] ||
|
|
56
|
-
!spreadsheetData[resolvedLocale][sheet][key];
|
|
57
|
-
// If it's a new key, add it to changes
|
|
58
|
-
if (isNewKey) {
|
|
59
|
-
if (!changes[locale])
|
|
60
|
-
changes[locale] = {};
|
|
61
|
-
if (!changes[locale][sheet])
|
|
62
|
-
changes[locale][sheet] = {};
|
|
63
|
-
changes[locale][sheet][key] = localData[locale][sheet][key];
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return changes;
|
|
69
|
-
}
|
|
70
|
-
//# sourceMappingURL=findLocalChanges.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"findLocalChanges.js","sourceRoot":"","sources":["../../../src/utils/dataConverter/findLocalChanges.ts"],"names":[],"mappings":";;AAyCA,4CAmCC;AA3ED,0DAAwD;AAExD;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB,CAC1B,MAAc,EACd,eAAgC;IAEhC,IAAI,eAAe,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,IAAI,eAAe,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,MAAM,QAAQ,GAAG,IAAA,oCAAiB,EAAC,KAAK,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,IAAI,CACvC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,oCAAiB,EAAC,CAAC,CAAC,KAAK,QAAQ,CACxC,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAgB,gBAAgB,CAC/B,SAA0B,EAC1B,eAAgC;IAEhC,MAAM,OAAO,GAAoB,EAAE,CAAC;IAEpC,kCAAkC;IAClC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QAC7C,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;YAAE,SAAS;QAEjC,0EAA0E;QAC1E,MAAM,cAAc,GAAG,kBAAkB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QAEnE,iCAAiC;QACjC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YACpD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;gBAAE,SAAS;YAExC,+BAA+B;YAC/B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACzD,6EAA6E;gBAC7E,MAAM,QAAQ,GAAG,CAAC,cAAc;oBAC/B,CAAC,eAAe,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC;oBACzC,CAAC,eAAe,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;gBAE9C,uCAAuC;gBACvC,IAAI,QAAQ,EAAE,CAAC;oBACd,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;wBAAE,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC;oBAC3C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC;wBAAE,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;oBACzD,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;gBAC7D,CAAC;YACF,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC"}
|
package/dist/utils/fileWriter.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.writeTranslationFiles = writeTranslationFiles;
|
|
7
|
-
exports.writeLocalesFile = writeLocalesFile;
|
|
8
|
-
exports.writeLanguageDataFile = writeLanguageDataFile;
|
|
9
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
-
const convertToDataJsonFormat_1 = require("./dataConverter/convertToDataJsonFormat");
|
|
12
|
-
/**
|
|
13
|
-
* Writes locale files to the translations directory
|
|
14
|
-
* @param translations Translation data organized by locale
|
|
15
|
-
* @param locales Array of locale identifiers
|
|
16
|
-
* @param translationsOutputDir Directory to write translation files to
|
|
17
|
-
*/
|
|
18
|
-
function writeTranslationFiles(translations, locales, translationsOutputDir) {
|
|
19
|
-
// Make sure the translations directory exists
|
|
20
|
-
if (!node_fs_1.default.existsSync(translationsOutputDir)) {
|
|
21
|
-
try {
|
|
22
|
-
node_fs_1.default.mkdirSync(translationsOutputDir, { recursive: true });
|
|
23
|
-
}
|
|
24
|
-
catch (err) {
|
|
25
|
-
throw new Error(`Failed to create translations directory "${translationsOutputDir}"`, { cause: err });
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
// Write files for all locales
|
|
29
|
-
for (const locale of locales) {
|
|
30
|
-
if (!translations[locale] || Object.keys(translations[locale]).length === 0) {
|
|
31
|
-
console.warn(`No translations found for locale "${locale}"`);
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
// Sanitize locale to prevent path traversal attacks
|
|
35
|
-
const safeName = locale.toLowerCase().replace(/[^a-z0-9_-]/g, '_');
|
|
36
|
-
if (safeName !== locale.toLowerCase()) {
|
|
37
|
-
console.warn(`Locale "${locale}" contained unsafe characters; sanitised to "${safeName}"`);
|
|
38
|
-
}
|
|
39
|
-
try {
|
|
40
|
-
node_fs_1.default.writeFileSync(node_path_1.default.join(translationsOutputDir, `${safeName}.json`), JSON.stringify(translations[locale], null, 2), "utf8");
|
|
41
|
-
console.log(`Successfully wrote translations for ${locale}`);
|
|
42
|
-
}
|
|
43
|
-
catch (err) {
|
|
44
|
-
console.error(`Failed to write translation file for locale "${locale}" at "${node_path_1.default.join(translationsOutputDir, `${safeName}.json`)}":`, err);
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Writes the locales.ts file containing the array of available locales and header mapping
|
|
50
|
-
* @param locales Array of normalized locale identifiers (filtered to only include valid locales)
|
|
51
|
-
* @param localeMapping Mapping from normalized locales to original spreadsheet headers
|
|
52
|
-
* @param localesOutputPath Path to write the locales.ts file
|
|
53
|
-
*/
|
|
54
|
-
function writeLocalesFile(locales, localeMapping, localesOutputPath) {
|
|
55
|
-
// Create locales.ts file directory if it doesn't exist
|
|
56
|
-
const localesOutputDir = node_path_1.default.dirname(localesOutputPath);
|
|
57
|
-
if (!node_fs_1.default.existsSync(localesOutputDir)) {
|
|
58
|
-
try {
|
|
59
|
-
node_fs_1.default.mkdirSync(localesOutputDir, { recursive: true });
|
|
60
|
-
}
|
|
61
|
-
catch (err) {
|
|
62
|
-
throw new Error(`Failed to create directory "${localesOutputDir}"`, { cause: err });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
const validLocales = locales.filter(locale => locale && locale.trim().length > 0);
|
|
66
|
-
// Create the content with both locales and header mapping
|
|
67
|
-
const content = `/**
|
|
68
|
-
* This file is auto-generated from the Google Spreadsheet package.
|
|
69
|
-
* It contains the list of available locales and their mappings to original spreadsheet headers.
|
|
70
|
-
* Do not edit this file manually, it will be overwritten by the package.
|
|
71
|
-
*/
|
|
72
|
-
|
|
73
|
-
export const locales = ${JSON.stringify(validLocales)};
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Mapping from normalized locale codes to original spreadsheet headers
|
|
77
|
-
* Used for syncing changes back to the spreadsheet
|
|
78
|
-
*/
|
|
79
|
-
export const localeHeaderMapping = ${JSON.stringify(localeMapping, null, 2)};
|
|
80
|
-
|
|
81
|
-
export default locales;
|
|
82
|
-
`;
|
|
83
|
-
try {
|
|
84
|
-
node_fs_1.default.writeFileSync(localesOutputPath, content, "utf8");
|
|
85
|
-
}
|
|
86
|
-
catch (err) {
|
|
87
|
-
throw new Error(`Failed to write locales file at "${localesOutputPath}"`, { cause: err });
|
|
88
|
-
}
|
|
89
|
-
console.log(`Successfully wrote locales file with ${validLocales.length} locales:`, validLocales);
|
|
90
|
-
console.log('Header mapping includes:', Object.keys(localeMapping).length, 'mappings');
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Writes the languageData.json file containing all translation data
|
|
94
|
-
* @param translations Translation data organized by locale
|
|
95
|
-
* @param locales Array of locale identifiers
|
|
96
|
-
* @param dataJsonPath Path to write the languageData.json file
|
|
97
|
-
*/
|
|
98
|
-
function writeLanguageDataFile(translations, locales, dataJsonPath) {
|
|
99
|
-
// Create languageData.json directory if it doesn't exist
|
|
100
|
-
const dataJsonDir = node_path_1.default.dirname(dataJsonPath);
|
|
101
|
-
if (!node_fs_1.default.existsSync(dataJsonDir)) {
|
|
102
|
-
try {
|
|
103
|
-
node_fs_1.default.mkdirSync(dataJsonDir, { recursive: true });
|
|
104
|
-
}
|
|
105
|
-
catch (err) {
|
|
106
|
-
throw new Error(`Failed to create directory "${dataJsonDir}"`, { cause: err });
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
// Convert the object format to the array format expected in languageData.json
|
|
110
|
-
const dataJsonContent = (0, convertToDataJsonFormat_1.convertToDataJsonFormat)(translations, locales);
|
|
111
|
-
try {
|
|
112
|
-
node_fs_1.default.writeFileSync(dataJsonPath, JSON.stringify(dataJsonContent, null, 2), "utf8");
|
|
113
|
-
}
|
|
114
|
-
catch (err) {
|
|
115
|
-
throw new Error(`Failed to write language data file at "${dataJsonPath}"`, { cause: err });
|
|
116
|
-
}
|
|
117
|
-
console.log("Successfully updated languageData.json with fresh spreadsheet data");
|
|
118
|
-
}
|
|
119
|
-
//# sourceMappingURL=fileWriter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fileWriter.js","sourceRoot":"","sources":["../../src/utils/fileWriter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getFileLastModified = getFileLastModified;
|
|
7
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
/**
|
|
9
|
-
* Gets the last modified time of a file
|
|
10
|
-
* @param filePath - Path to the file
|
|
11
|
-
* @returns The last modified time as a Date object, or null if file doesn't exist
|
|
12
|
-
*/
|
|
13
|
-
function getFileLastModified(filePath) {
|
|
14
|
-
try {
|
|
15
|
-
const stats = node_fs_1.default.statSync(filePath);
|
|
16
|
-
return stats.mtime;
|
|
17
|
-
}
|
|
18
|
-
catch (error) {
|
|
19
|
-
console.warn(`Could not read file stats for "${filePath}":`, error);
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=getFileLastModified.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"getFileLastModified.js","sourceRoot":"","sources":["../../src/utils/getFileLastModified.ts"],"names":[],"mappings":";;;;;AAOA,kDAQC;AAfD,sDAAyB;AAEzB;;;;GAIG;AACH,SAAgB,mBAAmB,CAAC,QAAgB;IACnD,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,iBAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACpC,OAAO,KAAK,CAAC,KAAK,CAAC;IACpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,kCAAkC,QAAQ,IAAI,EAAE,KAAK,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC"}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isDataJsonNewer = isDataJsonNewer;
|
|
7
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
-
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
-
const getFileLastModified_1 = require("./getFileLastModified");
|
|
10
|
-
/**
|
|
11
|
-
* Checks if languageData.json has been modified more recently than the translation files
|
|
12
|
-
* @param dataJsonPath - Path to languageData.json
|
|
13
|
-
* @param translationsOutputDir - Directory containing translation files
|
|
14
|
-
* @returns True if languageData.json is newer than the translation files
|
|
15
|
-
*/
|
|
16
|
-
function isDataJsonNewer(dataJsonPath, translationsOutputDir) {
|
|
17
|
-
const dataJsonMtime = (0, getFileLastModified_1.getFileLastModified)(dataJsonPath);
|
|
18
|
-
if (!dataJsonMtime)
|
|
19
|
-
return false;
|
|
20
|
-
// Get the most recent translation file modification time
|
|
21
|
-
try {
|
|
22
|
-
const files = node_fs_1.default.readdirSync(translationsOutputDir)
|
|
23
|
-
.filter(file => file.endsWith('.json'))
|
|
24
|
-
.map(file => node_path_1.default.join(translationsOutputDir, file));
|
|
25
|
-
if (files.length === 0)
|
|
26
|
-
return true;
|
|
27
|
-
const mostRecentTranslationMtime = files
|
|
28
|
-
.map(file => (0, getFileLastModified_1.getFileLastModified)(file))
|
|
29
|
-
.filter((d) => d !== null)
|
|
30
|
-
.reduce((max, d) => (max === null || d > max ? d : max), null);
|
|
31
|
-
if (!mostRecentTranslationMtime)
|
|
32
|
-
return true;
|
|
33
|
-
return dataJsonMtime > mostRecentTranslationMtime;
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
console.warn("Error comparing file modification times:", error);
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
//# sourceMappingURL=isDataJsonNewer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"isDataJsonNewer.js","sourceRoot":"","sources":["../../src/utils/isDataJsonNewer.ts"],"names":[],"mappings":";;;;;AAUA,0CA2BC;AArCD,sDAAyB;AACzB,0DAA6B;AAC7B,+DAA4D;AAE5D;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,YAAoB,EAAE,qBAA6B;IAClF,MAAM,aAAa,GAAG,IAAA,yCAAmB,EAAC,YAAY,CAAC,CAAC;IAExD,IAAI,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC;IAEjC,yDAAyD;IACzD,IAAI,CAAC;QACJ,MAAM,KAAK,GAAG,iBAAE,CAAC,WAAW,CAAC,qBAAqB,CAAC;aACjD,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;aACtC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,mBAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,IAAI,CAAC,CAAC,CAAC;QAEtD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEpC,MAAM,0BAA0B,GAAG,KAAK;aACtC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAA,yCAAmB,EAAC,IAAI,CAAC,CAAC;aACtC,MAAM,CAAC,CAAC,CAAC,EAAa,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;aACpC,MAAM,CACN,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAC/C,IAAI,CACJ,CAAC;QAEH,IAAI,CAAC,0BAA0B;YAAE,OAAO,IAAI,CAAC;QAC7C,OAAO,aAAa,GAAG,0BAA0B,CAAC;IACnD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,OAAO,CAAC,IAAI,CAAC,0CAA0C,EAAE,KAAK,CAAC,CAAC;QAChE,OAAO,KAAK,CAAC;IACd,CAAC;AACF,CAAC"}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Locale validation utilities
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.isValidLocale = isValidLocale;
|
|
7
|
-
exports.filterValidLocales = filterValidLocales;
|
|
8
|
-
const COMMON_LOCALE_PATTERNS = [
|
|
9
|
-
/^[a-z]{2}$/, // en, de, fr
|
|
10
|
-
/^[a-z]{2}-[a-z]{2}$/, // en-us, de-de
|
|
11
|
-
/^[a-z]{2}_[a-z]{2}$/, // en_us, de_de
|
|
12
|
-
/^[a-z]{2}-[a-z]{2}-[a-z]+$/, // en-us-traditional
|
|
13
|
-
];
|
|
14
|
-
const NON_LOCALE_KEYWORDS = [
|
|
15
|
-
'key', 'keys', 'id', 'identifier', 'name', 'title', 'label',
|
|
16
|
-
'description', 'comment', 'note', 'context', 'category', 'type',
|
|
17
|
-
'status', 'updated', 'created', 'modified', 'version', 'source',
|
|
18
|
-
'i18n', 'translation', 'namespace', 'section'
|
|
19
|
-
];
|
|
20
|
-
/**
|
|
21
|
-
* Determines if a string represents a valid locale identifier
|
|
22
|
-
* @param value The string to test
|
|
23
|
-
* @returns true if the string appears to be a locale identifier
|
|
24
|
-
*/
|
|
25
|
-
function isValidLocale(value) {
|
|
26
|
-
if (!value || typeof value !== 'string') {
|
|
27
|
-
return false;
|
|
28
|
-
}
|
|
29
|
-
const normalized = value.toLowerCase().trim();
|
|
30
|
-
// Check if it's a common non-locale keyword
|
|
31
|
-
if (NON_LOCALE_KEYWORDS.includes(normalized)) {
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
// Check if it matches common locale patterns (only accept lowercase patterns)
|
|
35
|
-
return COMMON_LOCALE_PATTERNS.some(pattern => pattern.test(normalized));
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Filters header row to only include valid locale columns, excluding the key column
|
|
39
|
-
* @param headerRow Array of column names from the sheet header
|
|
40
|
-
* @param keyColumn The name of the key column to exclude
|
|
41
|
-
* @returns Array of valid locale identifiers
|
|
42
|
-
*/
|
|
43
|
-
function filterValidLocales(headerRow, keyColumn) {
|
|
44
|
-
return headerRow
|
|
45
|
-
.filter(column => column.toLowerCase() !== keyColumn.toLowerCase())
|
|
46
|
-
.filter(column => isValidLocale(column)) // Use original case for validation
|
|
47
|
-
.map(locale => locale.toLowerCase()); // Then normalize to lowercase
|
|
48
|
-
}
|
|
49
|
-
//# sourceMappingURL=localeFilter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"localeFilter.js","sourceRoot":"","sources":["../../src/utils/localeFilter.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAqBH,sCAcC;AAQD,gDAKC;AA9CD,MAAM,sBAAsB,GAAG;IAC9B,YAAY,EAAqB,aAAa;IAC9C,qBAAqB,EAAW,eAAe;IAC/C,qBAAqB,EAAW,eAAe;IAC/C,4BAA4B,EAAI,oBAAoB;CACpD,CAAC;AAEF,MAAM,mBAAmB,GAAG;IAC3B,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO;IAC3D,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM;IAC/D,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ;IAC/D,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS;CAC7C,CAAC;AAEF;;;;GAIG;AACH,SAAgB,aAAa,CAAC,KAAa;IAC1C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACzC,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAE9C,4CAA4C;IAC5C,IAAI,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;QAC9C,OAAO,KAAK,CAAC;IACd,CAAC;IAED,8EAA8E;IAC9E,OAAO,sBAAsB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;;GAKG;AACH,SAAgB,kBAAkB,CAAC,SAAmB,EAAE,SAAiB;IACxE,OAAO,SAAS;SACd,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,SAAS,CAAC,WAAW,EAAE,CAAC;SAClE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,mCAAmC;SAC3E,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,8BAA8B;AACtE,CAAC"}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Locale normalization utilities for converting simple language codes to full locale codes
|
|
4
|
-
* and maintaining mappings between normalized codes and original spreadsheet headers
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.getLanguagePrefix = getLanguagePrefix;
|
|
8
|
-
exports.normalizeLocaleCode = normalizeLocaleCode;
|
|
9
|
-
exports.createLocaleMapping = createLocaleMapping;
|
|
10
|
-
exports.getOriginalHeaderForLocale = getOriginalHeaderForLocale;
|
|
11
|
-
exports.getNormalizedLocaleForHeader = getNormalizedLocaleForHeader;
|
|
12
|
-
/**
|
|
13
|
-
* Returns the language prefix of a locale code (the part before the first
|
|
14
|
-
* `-` or `_` separator), lowercased.
|
|
15
|
-
*
|
|
16
|
-
* Examples:
|
|
17
|
-
* - `'en-US'` → `'en'`
|
|
18
|
-
* - `'zh_CN'` → `'zh'`
|
|
19
|
-
* - `'de'` → `'de'`
|
|
20
|
-
*
|
|
21
|
-
* Used for language-family matching when an exact locale code is not found.
|
|
22
|
-
*/
|
|
23
|
-
function getLanguagePrefix(locale) {
|
|
24
|
-
return locale.toLowerCase().split(/[-_]/)[0];
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Common language to country mappings for normalization
|
|
28
|
-
* Maps language codes to their most common country variants
|
|
29
|
-
*/
|
|
30
|
-
const LANGUAGE_TO_COUNTRY_MAP = {
|
|
31
|
-
'en': 'en-GB',
|
|
32
|
-
'de': 'de-DE',
|
|
33
|
-
'fr': 'fr-FR',
|
|
34
|
-
'es': 'es-ES',
|
|
35
|
-
'it': 'it-IT',
|
|
36
|
-
'pt': 'pt-PT',
|
|
37
|
-
'pl': 'pl-PL',
|
|
38
|
-
'ru': 'ru-RU',
|
|
39
|
-
'zh': 'zh-CN',
|
|
40
|
-
'ja': 'ja-JP',
|
|
41
|
-
'ko': 'ko-KR',
|
|
42
|
-
'ar': 'ar-SA',
|
|
43
|
-
'hi': 'hi-IN',
|
|
44
|
-
'th': 'th-TH',
|
|
45
|
-
'vi': 'vi-VN',
|
|
46
|
-
'tr': 'tr-TR',
|
|
47
|
-
'nl': 'nl-NL',
|
|
48
|
-
'sv': 'sv-SE',
|
|
49
|
-
'da': 'da-DK',
|
|
50
|
-
'no': 'no-NO',
|
|
51
|
-
'fi': 'fi-FI',
|
|
52
|
-
'cs': 'cs-CZ',
|
|
53
|
-
'sk': 'sk-SK',
|
|
54
|
-
'hu': 'hu-HU',
|
|
55
|
-
'ro': 'ro-RO',
|
|
56
|
-
'bg': 'bg-BG',
|
|
57
|
-
'hr': 'hr-HR',
|
|
58
|
-
'sl': 'sl-SI',
|
|
59
|
-
'et': 'et-EE',
|
|
60
|
-
'lv': 'lv-LV',
|
|
61
|
-
'lt': 'lt-LT',
|
|
62
|
-
'el': 'el-GR',
|
|
63
|
-
'he': 'he-IL',
|
|
64
|
-
'uk': 'uk-UA',
|
|
65
|
-
'be': 'be-BY',
|
|
66
|
-
};
|
|
67
|
-
/**
|
|
68
|
-
* Normalizes a language code to include country code if missing
|
|
69
|
-
* @param locale The original locale code from spreadsheet header
|
|
70
|
-
* @returns Normalized locale with country code
|
|
71
|
-
*/
|
|
72
|
-
function normalizeLocaleCode(locale) {
|
|
73
|
-
if (!locale || typeof locale !== 'string') {
|
|
74
|
-
return '';
|
|
75
|
-
}
|
|
76
|
-
const normalized = locale.toLowerCase().trim();
|
|
77
|
-
// If already has country code, return as is
|
|
78
|
-
if (normalized.includes('-') || normalized.includes('_')) {
|
|
79
|
-
return normalized;
|
|
80
|
-
}
|
|
81
|
-
// Look up the language in our mapping first
|
|
82
|
-
const withCountry = LANGUAGE_TO_COUNTRY_MAP[normalized];
|
|
83
|
-
if (withCountry) {
|
|
84
|
-
return withCountry;
|
|
85
|
-
}
|
|
86
|
-
// If not in mapping and it's a 2-letter code, append the same code in uppercase
|
|
87
|
-
// This handles cases like "pl" -> "pl-PL"
|
|
88
|
-
if (normalized.length === 2 && /^[a-z]{2}$/.test(normalized)) {
|
|
89
|
-
return `${normalized}-${normalized.toUpperCase()}`;
|
|
90
|
-
}
|
|
91
|
-
// Return original if we can't normalize it
|
|
92
|
-
return normalized;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Creates a mapping between normalized locale codes and their original spreadsheet headers
|
|
96
|
-
* @param originalHeaders Array of original header names from spreadsheet
|
|
97
|
-
* @param keyColumn The key column name to exclude
|
|
98
|
-
* @returns Object with normalized locales and header mapping
|
|
99
|
-
*/
|
|
100
|
-
function createLocaleMapping(originalHeaders, keyColumn) {
|
|
101
|
-
const localeMapping = {}; // normalized -> original
|
|
102
|
-
const originalMapping = {}; // original -> normalized
|
|
103
|
-
const normalizedLocales = [];
|
|
104
|
-
for (const header of originalHeaders) {
|
|
105
|
-
const headerLower = header.toLowerCase();
|
|
106
|
-
// Skip key column and non-locale headers
|
|
107
|
-
if (headerLower === keyColumn.toLowerCase()) {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
// Check if this looks like a locale
|
|
111
|
-
const isLocale = /^[a-z]{2}([_-][a-z]{2})?([_-][a-z]+)?$/.test(headerLower);
|
|
112
|
-
if (!isLocale) {
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
const normalized = normalizeLocaleCode(headerLower);
|
|
116
|
-
localeMapping[normalized] = header; // Store original case
|
|
117
|
-
originalMapping[headerLower] = normalized;
|
|
118
|
-
normalizedLocales.push(normalized);
|
|
119
|
-
}
|
|
120
|
-
return {
|
|
121
|
-
normalizedLocales: [...new Set(normalizedLocales)], // Remove duplicates
|
|
122
|
-
localeMapping, // normalized -> original header
|
|
123
|
-
originalMapping // original header (lowercase) -> normalized
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Finds the original header name for a given normalized locale.
|
|
128
|
-
*
|
|
129
|
-
* Lookup order (most-specific → most-lenient):
|
|
130
|
-
* 1. Direct key match (`'en-us'` → `'en-US'`)
|
|
131
|
-
* 2. Lowercase key match (`'EN-US'` → key `'en-us'`)
|
|
132
|
-
* 3. Case-insensitive key comparison
|
|
133
|
-
* 4. Language-family prefix match – e.g. `'en'` or `'en-GB'` finds `'en-US'`
|
|
134
|
-
* when `'en-US'` is the only English variant present in the mapping.
|
|
135
|
-
*
|
|
136
|
-
* @param normalizedLocale The normalized locale code (e.g., `'en-GB'`, `'en'`)
|
|
137
|
-
* @param localeMapping Mapping from normalized locales to original headers
|
|
138
|
-
* @returns Original header name or undefined if not found
|
|
139
|
-
*/
|
|
140
|
-
function getOriginalHeaderForLocale(normalizedLocale, localeMapping) {
|
|
141
|
-
// Try direct lookup first
|
|
142
|
-
let result = localeMapping[normalizedLocale];
|
|
143
|
-
if (result)
|
|
144
|
-
return result;
|
|
145
|
-
// Try lowercase lookup if direct lookup fails
|
|
146
|
-
const lowercaseLocale = normalizedLocale.toLowerCase();
|
|
147
|
-
result = localeMapping[lowercaseLocale];
|
|
148
|
-
if (result)
|
|
149
|
-
return result;
|
|
150
|
-
// Try finding by case-insensitive key comparison
|
|
151
|
-
for (const [key, value] of Object.entries(localeMapping)) {
|
|
152
|
-
if (key.toLowerCase() === lowercaseLocale) {
|
|
153
|
-
return value;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
// Language-family fallback: 'en' or 'en-GB' should find 'en-US' when that
|
|
157
|
-
// is the only English variant present in the localeMapping.
|
|
158
|
-
const inputLangCode = getLanguagePrefix(normalizedLocale);
|
|
159
|
-
for (const [key, value] of Object.entries(localeMapping)) {
|
|
160
|
-
if (getLanguagePrefix(key) === inputLangCode) {
|
|
161
|
-
return value;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
return undefined;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Finds the normalized locale for a given original header
|
|
168
|
-
* @public
|
|
169
|
-
* @param originalHeader The original header name (e.g., 'pl')
|
|
170
|
-
* @param originalMapping Mapping from original headers to normalized locales
|
|
171
|
-
* @returns Normalized locale code or undefined if not found
|
|
172
|
-
*/
|
|
173
|
-
function getNormalizedLocaleForHeader(originalHeader, originalMapping) {
|
|
174
|
-
return originalMapping[originalHeader.toLowerCase()];
|
|
175
|
-
}
|
|
176
|
-
//# sourceMappingURL=localeNormalizer.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"localeNormalizer.js","sourceRoot":"","sources":["../../src/utils/localeNormalizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.readPublicSheet = readPublicSheet;
|
|
7
|
-
const node_https_1 = __importDefault(require("node:https"));
|
|
8
|
-
const node_http_1 = __importDefault(require("node:http"));
|
|
9
|
-
/**
|
|
10
|
-
* Fetches the raw response body from a URL using the built-in http/https module.
|
|
11
|
-
* Follows a single redirect if the server issues one (3xx).
|
|
12
|
-
*/
|
|
13
|
-
function fetchUrl(url) {
|
|
14
|
-
return new Promise((resolve, reject) => {
|
|
15
|
-
const client = url.startsWith("https") ? node_https_1.default : node_http_1.default;
|
|
16
|
-
const req = client.get(url, (res) => {
|
|
17
|
-
// Follow one redirect (e.g. Google auth redirect)
|
|
18
|
-
if (res.statusCode !== undefined &&
|
|
19
|
-
res.statusCode >= 300 &&
|
|
20
|
-
res.statusCode < 400 &&
|
|
21
|
-
res.headers.location) {
|
|
22
|
-
fetchUrl(res.headers.location).then(resolve).catch(reject);
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
if (res.statusCode !== undefined && res.statusCode >= 400) {
|
|
26
|
-
reject(new Error(`HTTP ${res.statusCode} while fetching ${url}`));
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
let data = "";
|
|
30
|
-
res.on("data", (chunk) => {
|
|
31
|
-
data += chunk.toString();
|
|
32
|
-
});
|
|
33
|
-
res.on("end", () => resolve(data));
|
|
34
|
-
res.on("error", reject);
|
|
35
|
-
});
|
|
36
|
-
req.on("error", reject);
|
|
37
|
-
req.end();
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Strips the JSONP wrapper that the Google Visualization API adds and parses
|
|
42
|
-
* the inner JSON object.
|
|
43
|
-
*
|
|
44
|
-
* Expected wrapper format:
|
|
45
|
-
* `/*O_o*\/\ngoogle.visualization.Query.setResponse({...});`
|
|
46
|
-
*/
|
|
47
|
-
function parseGvizResponse(raw) {
|
|
48
|
-
const match = raw.match(/google\.visualization\.Query\.setResponse\((\{[\s\S]*?\})\)/);
|
|
49
|
-
if (!match) {
|
|
50
|
-
throw new Error('Unexpected response format from Google Visualization API. ' +
|
|
51
|
-
'Make sure the spreadsheet is shared as "Anyone with link can view".');
|
|
52
|
-
}
|
|
53
|
-
return JSON.parse(match[1]);
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Reads rows from a *publicly accessible* Google Spreadsheet sheet without
|
|
57
|
-
* requiring any service-account credentials or API key.
|
|
58
|
-
*
|
|
59
|
-
* The spreadsheet must be shared with **"Anyone with link can view"** (or
|
|
60
|
-
* broader). Works via Google's Visualization (gviz) query endpoint which
|
|
61
|
-
* is available at no cost for public sheets.
|
|
62
|
-
*
|
|
63
|
-
* @param spreadsheetId - The Google Spreadsheet ID (from the URL)
|
|
64
|
-
* @param sheetName - The sheet tab name to fetch
|
|
65
|
-
* @returns An array of row objects keyed by column header
|
|
66
|
-
* @throws If the sheet is not accessible or the response cannot be parsed
|
|
67
|
-
*/
|
|
68
|
-
async function readPublicSheet(spreadsheetId, sheetName) {
|
|
69
|
-
// `headers=1` tells the gviz API to treat the first spreadsheet row as column
|
|
70
|
-
// labels (col.label). Without it Google may return empty labels and fall back
|
|
71
|
-
// to column IDs (A, B, C …) which are not valid locale codes.
|
|
72
|
-
const url = `https://docs.google.com/spreadsheets/d/${encodeURIComponent(spreadsheetId)}` +
|
|
73
|
-
`/gviz/tq?tqx=out:json&headers=1&sheet=${encodeURIComponent(sheetName)}`;
|
|
74
|
-
let raw;
|
|
75
|
-
try {
|
|
76
|
-
raw = await fetchUrl(url);
|
|
77
|
-
}
|
|
78
|
-
catch (err) {
|
|
79
|
-
throw new Error(`Failed to fetch public sheet "${sheetName}" from spreadsheet "${spreadsheetId}"`, { cause: err });
|
|
80
|
-
}
|
|
81
|
-
let data;
|
|
82
|
-
try {
|
|
83
|
-
data = parseGvizResponse(raw);
|
|
84
|
-
}
|
|
85
|
-
catch (err) {
|
|
86
|
-
throw new Error(`Failed to parse response for sheet "${sheetName}" in spreadsheet "${spreadsheetId}"`, { cause: err });
|
|
87
|
-
}
|
|
88
|
-
if (data.status !== "ok") {
|
|
89
|
-
const message = data.errors?.[0]?.message ?? "Unknown error";
|
|
90
|
-
throw new Error(`Google Visualization API returned an error for sheet "${sheetName}": ${message}`);
|
|
91
|
-
}
|
|
92
|
-
if (!data.table) {
|
|
93
|
-
return [];
|
|
94
|
-
}
|
|
95
|
-
const { cols, rows } = data.table;
|
|
96
|
-
const headers = cols.map((col) => col.label || col.id);
|
|
97
|
-
return rows
|
|
98
|
-
.filter((row) => row && row.c)
|
|
99
|
-
.map((row) => {
|
|
100
|
-
const obj = {};
|
|
101
|
-
for (let i = 0; i < headers.length; i++) {
|
|
102
|
-
const cell = row.c?.[i];
|
|
103
|
-
obj[headers[i]] = cell?.v != null ? String(cell.v) : "";
|
|
104
|
-
}
|
|
105
|
-
return obj;
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
exports.default = readPublicSheet;
|
|
109
|
-
//# sourceMappingURL=publicSheetReader.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"publicSheetReader.js","sourceRoot":"","sources":["../../src/utils/publicSheetReader.ts"],"names":[],"mappings":"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"}
|