sheets-translate-to-json
Version:
A Node.js library that facilitates the retrieval and conversion of previously translated Google Sheets spreadsheets into structured JSON files, optimizing the management of localized resources.
1 lines • 23.8 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { GoogleSpreadsheet } from \"google-spreadsheet\";\nimport { JWT } from \"google-auth-library\";\nimport fs from \"fs\";\nimport path from \"path\";\n\ninterface NestedObject {\n [key: string]: string | NestedObject | undefined;\n}\n\ninterface SheetData {\n [key: string]: NestedObject;\n}\n\ntype SyncStrategy = 'local' | 'remote' | 'merge';\n\ninterface SyncOptions {\n strategy?: SyncStrategy;\n sheetName?: string;\n createSheet?: boolean;\n}\n\ninterface SyncResult {\n added: { local: number; remote: number };\n updated: { local: number; remote: number };\n languages: string[];\n}\n\nexport class SheetManager {\n private doc: GoogleSpreadsheet;\n private jwt: JWT;\n\n constructor(\n privateKey: string,\n clientEmail: string,\n sheetId: string,\n ) {\n const SCOPES = [\n \"https://www.googleapis.com/auth/spreadsheets\",\n \"https://www.googleapis.com/auth/drive.file\",\n ];\n\n this.jwt = new JWT({\n email: clientEmail,\n key: privateKey,\n scopes: SCOPES,\n });\n\n this.doc = new GoogleSpreadsheet(sheetId, this.jwt); \n }\n\n async init(userPath: string, sheetNames?: string[]) {\n try {\n await this.jwt.authorize();\n \n if (sheetNames && sheetNames.length > 0) {\n // Traiter plusieurs feuilles spécifiques et les combiner\n const combinedData: SheetData = {};\n \n for (const sheetName of sheetNames) {\n const data = await this.readByName(sheetName);\n if (data && Object.keys(data).length > 0) {\n // Combiner les données de cette feuille avec les données existantes\n Object.keys(data).forEach(language => {\n if (!combinedData[language]) {\n combinedData[language] = {};\n }\n // Fusionner les données de cette langue\n this.mergeNestedObjects(combinedData[language] as NestedObject, data[language] as NestedObject);\n });\n } else {\n console.warn(`No data found in sheet: ${sheetName}`);\n }\n }\n \n if (Object.keys(combinedData).length > 0) {\n this.write(combinedData, userPath);\n }\n } else {\n // Traiter toutes les feuilles et les combiner\n const allSheetsData = await this.readAllSheets();\n const combinedData: SheetData = {};\n \n // Combiner les données de toutes les feuilles\n Object.keys(allSheetsData).forEach(sheetName => {\n const sheetData = allSheetsData[sheetName];\n Object.keys(sheetData).forEach(language => {\n if (!combinedData[language]) {\n combinedData[language] = {};\n }\n // Fusionner les données de cette langue\n this.mergeNestedObjects(combinedData[language] as NestedObject, sheetData[language] as NestedObject);\n });\n });\n \n if (Object.keys(combinedData).length > 0) {\n this.write(combinedData, userPath);\n } else {\n console.error(\"No data found in the sheet\");\n }\n }\n } catch (err) {\n console.error(\"Error during initialization:\", err);\n }\n }\n\n async read(sheetPosition: number = 0): Promise<SheetData> {\n if (sheetPosition < 0) {\n sheetPosition = 0;\n }\n await this.doc.loadInfo();\n const sheet = this.doc.sheetsByIndex[sheetPosition];\n return this.processSheet(sheet);\n }\n\n async readByName(sheetName: string): Promise<SheetData> {\n await this.doc.loadInfo();\n const sheet = this.doc.sheetsByTitle[sheetName];\n \n if (!sheet) {\n throw new Error(`Sheet with name \"${sheetName}\" not found`);\n }\n \n return this.processSheet(sheet);\n }\n\n async readAllSheets(): Promise<{ [sheetName: string]: SheetData }> {\n await this.doc.loadInfo();\n const allData: { [sheetName: string]: SheetData } = {};\n \n for (const sheet of this.doc.sheetsByIndex) {\n try {\n const data = await this.processSheet(sheet);\n if (data && Object.keys(data).length > 0) {\n allData[sheet.title] = data;\n }\n } catch (error) {\n console.error(`Error processing sheet \"${sheet.title}\":`, error);\n }\n }\n \n return allData;\n }\n\n private async processSheet(sheet: any): Promise<SheetData> {\n await sheet.loadHeaderRow();\n const colTitles = sheet.headerValues;\n const rows = await sheet.getRows({ limit: sheet.rowCount });\n\n const result: SheetData = {};\n \n rows.forEach((row: any) => {\n // Vérifier si la ligne n'est pas vide\n const keyValue = row.get(colTitles[0]);\n \n // Ignorer les lignes vides ou avec une clé vide/undefined\n if (!keyValue || keyValue.trim() === '') {\n return;\n }\n\n colTitles.slice(1).forEach((title: string) => {\n const key = keyValue.trim();\n const value = row.get(title);\n const cleanValue = value && value.trim() !== '' ? value.trim() : undefined;\n\n // Initialiser la structure pour cette colonne si elle n'existe pas\n if (!result[title]) {\n result[title] = {};\n }\n\n // Gérer les clés imbriquées avec support de plusieurs niveaux\n if (key.includes(\".\")) {\n this.setNestedValue(result[title] as NestedObject, key, cleanValue);\n } else {\n (result[title] as NestedObject)[key] = cleanValue;\n }\n });\n });\n\n return result;\n }\n\n private setNestedValue(obj: NestedObject, keyPath: string, value: string | undefined): void {\n const keys = keyPath.split(\".\");\n let current = obj;\n\n // Naviguer jusqu'à l'avant-dernier niveau\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i];\n \n if (!current[key] || typeof current[key] !== 'object') {\n current[key] = {};\n }\n \n current = current[key] as NestedObject;\n }\n\n // Définir la valeur finale\n const finalKey = keys[keys.length - 1];\n current[finalKey] = value;\n }\n\n private mergeNestedObjects(target: NestedObject, source: NestedObject): void {\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (typeof sourceValue === 'object' && sourceValue !== null && typeof targetValue === 'object' && targetValue !== null) {\n this.mergeNestedObjects(targetValue as NestedObject, sourceValue as NestedObject);\n } else {\n target[key] = sourceValue;\n }\n }\n }\n }\n\n write(data: SheetData, directoryPath: string): void {\n if (!fs.existsSync(directoryPath)) {\n fs.mkdirSync(directoryPath, { recursive: true });\n }\n\n Object.keys(data).forEach((key) => {\n const fileName = `${key}.json`;\n const filePath = path.join(directoryPath, fileName);\n \n fs.writeFile(filePath, JSON.stringify(data[key], null, 2), (err) => {\n if (err) {\n console.error(`Error writing file ${filePath}:`, err);\n return;\n }\n console.log(`File written: ${filePath}`);\n });\n });\n }\n\n // Méthode utilitaire pour lister toutes les feuilles disponibles\n async listSheets(): Promise<string[]> {\n await this.doc.loadInfo();\n return this.doc.sheetsByIndex.map(sheet => sheet.title);\n }\n\n readLocal(directoryPath: string): SheetData {\n if (!fs.existsSync(directoryPath)) {\n throw new Error(`Directory not found: ${directoryPath}`);\n }\n\n const result: SheetData = {};\n const files = fs.readdirSync(directoryPath).filter(f => f.endsWith('.json'));\n\n for (const file of files) {\n const language = file.replace('.json', '');\n const filePath = path.join(directoryPath, file);\n const content = fs.readFileSync(filePath, 'utf-8');\n result[language] = JSON.parse(content);\n }\n\n return result;\n }\n\n async push(directoryPath: string, sheetName?: string): Promise<void> {\n const localData = this.readLocal(directoryPath);\n\n if (Object.keys(localData).length === 0) {\n console.warn('No JSON files found in directory');\n return;\n }\n\n await this.doc.loadInfo();\n\n let sheet: any;\n if (sheetName) {\n sheet = this.doc.sheetsByTitle[sheetName];\n if (!sheet) {\n sheet = await this.doc.addSheet({ title: sheetName });\n }\n } else {\n sheet = this.doc.sheetsByIndex[0];\n }\n\n const languages = Object.keys(localData);\n const flatData = this.flattenAllLanguages(localData);\n\n await sheet.clear();\n await sheet.setHeaderRow(['key', ...languages]);\n\n const rows = flatData.map(entry => {\n const row: { [key: string]: string } = { key: entry.key };\n for (const lang of languages) {\n row[lang] = entry.values[lang] || '';\n }\n return row;\n });\n\n if (rows.length > 0) {\n await sheet.addRows(rows);\n }\n\n console.log(`Pushed ${rows.length} keys in ${languages.length} languages to sheet \"${sheet.title}\"`);\n }\n\n async sync(directoryPath: string, options: SyncOptions = {}): Promise<SyncResult> {\n const { strategy = 'merge', sheetName, createSheet = false } = options;\n\n await this.doc.loadInfo();\n\n const result: SyncResult = {\n added: { local: 0, remote: 0 },\n updated: { local: 0, remote: 0 },\n languages: [],\n };\n\n // Read remote data\n let remoteData: SheetData;\n let sheet: any;\n\n if (sheetName) {\n sheet = this.doc.sheetsByTitle[sheetName];\n if (!sheet) {\n if (createSheet) {\n sheet = await this.doc.addSheet({ title: sheetName });\n remoteData = {};\n } else {\n throw new Error(`Sheet \"${sheetName}\" not found. Use createSheet: true to create it.`);\n }\n } else {\n remoteData = await this.processSheet(sheet);\n }\n } else {\n sheet = this.doc.sheetsByIndex[0];\n remoteData = await this.processSheet(sheet);\n }\n\n // Read local data\n let localData: SheetData = {};\n if (fs.existsSync(directoryPath)) {\n localData = this.readLocal(directoryPath);\n }\n\n // Collect all languages\n const allLanguages = new Set([\n ...Object.keys(remoteData),\n ...Object.keys(localData),\n ]);\n result.languages = [...allLanguages];\n\n // Merge data based on strategy\n const mergedData: SheetData = {};\n const remoteFlat = this.flattenSheetData(remoteData);\n const localFlat = this.flattenSheetData(localData);\n const allKeys = new Set([...Object.keys(remoteFlat), ...Object.keys(localFlat)]);\n\n for (const compositeKey of allKeys) {\n const remoteValues = remoteFlat[compositeKey] || {};\n const localValues = localFlat[compositeKey] || {};\n const isNewLocal = !remoteFlat[compositeKey];\n const isNewRemote = !localFlat[compositeKey];\n\n if (isNewLocal) result.added.local++;\n if (isNewRemote) result.added.remote++;\n\n for (const lang of allLanguages) {\n if (!mergedData[lang]) mergedData[lang] = {};\n\n const remoteVal = remoteValues[lang];\n const localVal = localValues[lang];\n let finalVal: string | undefined;\n\n if (strategy === 'local') {\n finalVal = localVal ?? remoteVal;\n } else if (strategy === 'remote') {\n finalVal = remoteVal ?? localVal;\n } else {\n // merge: prefer non-empty, local wins on conflict\n if (localVal && remoteVal && localVal !== remoteVal) {\n finalVal = localVal;\n if (!isNewLocal && !isNewRemote) result.updated.local++;\n } else {\n finalVal = localVal ?? remoteVal;\n }\n }\n\n if (finalVal !== undefined) {\n // Parse the composite key (lang is separate, compositeKey is the dot-path)\n const keyPath = compositeKey;\n if (keyPath.includes('.')) {\n this.setNestedValue(mergedData[lang] as NestedObject, keyPath, finalVal);\n } else {\n (mergedData[lang] as NestedObject)[keyPath] = finalVal;\n }\n }\n }\n }\n\n // Write merged data to local files\n this.write(mergedData, directoryPath);\n\n // Write merged data back to remote sheet\n const mergedLanguages = Object.keys(mergedData);\n const flatMerged = this.flattenAllLanguages(mergedData);\n\n await sheet.clear();\n await sheet.setHeaderRow(['key', ...mergedLanguages]);\n\n const rows = flatMerged.map(entry => {\n const row: { [key: string]: string } = { key: entry.key };\n for (const lang of mergedLanguages) {\n row[lang] = entry.values[lang] || '';\n }\n return row;\n });\n\n if (rows.length > 0) {\n await sheet.addRows(rows);\n }\n\n result.updated.remote = flatMerged.length;\n\n console.log(`Sync complete: ${result.added.local} new local keys, ${result.added.remote} new remote keys`);\n return result;\n }\n\n private flattenNestedObject(obj: NestedObject, prefix: string = ''): { [key: string]: string } {\n const result: { [key: string]: string } = {};\n\n for (const key in obj) {\n if (!Object.prototype.hasOwnProperty.call(obj, key)) continue;\n const value = obj[key];\n const fullKey = prefix ? `${prefix}.${key}` : key;\n\n if (typeof value === 'object' && value !== null) {\n Object.assign(result, this.flattenNestedObject(value as NestedObject, fullKey));\n } else if (typeof value === 'string') {\n result[fullKey] = value;\n }\n }\n\n return result;\n }\n\n private flattenSheetData(data: SheetData): { [key: string]: { [lang: string]: string | undefined } } {\n const result: { [key: string]: { [lang: string]: string | undefined } } = {};\n\n for (const lang of Object.keys(data)) {\n const flat = this.flattenNestedObject(data[lang] as NestedObject);\n for (const key of Object.keys(flat)) {\n if (!result[key]) result[key] = {};\n result[key][lang] = flat[key];\n }\n }\n\n return result;\n }\n\n private flattenAllLanguages(data: SheetData): { key: string; values: { [lang: string]: string } }[] {\n const languages = Object.keys(data);\n const allKeys = new Set<string>();\n\n const flatByLang: { [lang: string]: { [key: string]: string } } = {};\n for (const lang of languages) {\n flatByLang[lang] = this.flattenNestedObject(data[lang] as NestedObject);\n for (const key of Object.keys(flatByLang[lang])) {\n allKeys.add(key);\n }\n }\n\n const sortedKeys = [...allKeys].sort();\n return sortedKeys.map(key => ({\n key,\n values: Object.fromEntries(\n languages.map(lang => [lang, flatByLang[lang][key] || ''])\n ),\n }));\n }\n}"],"mappings":"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","names":[]}