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
| #!/usr/bin/env node
import { program } from 'commander'; import { I18nSyncer } from '../lib/index.js'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import dotenv from 'dotenv';
dotenv.config();
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const packageJsonPath = path.join(__dirname, '../package.json'); const { version } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
program .name('i18n-syncer') .description('CLI to pull and push translations between Google Sheets and local files') .version(version);
const createSyncer = (options) => { return new I18nSyncer({ spreadsheetId: options.spreadsheetId, credentialsPath: options.credentials, translationDir: options.translationDir, }); };
const handleError = (error) => { if (error.code === 'ENOENT' && error.path?.includes('credentials.json')) { console.error('Error: Credentials file not found. Please provide a valid path to your Google API credentials.'); process.exit(1); }
if (error.message?.includes('invalid_grant') || error.message?.includes('authorization')) { console.error('Error: Google API authorization failed. Please check your credentials and permissions.'); process.exit(1); }
if (error.response?.status === 404) { console.error('Error: Spreadsheet not found. Please check your spreadsheet ID.'); process.exit(1); }
console.error('Error:', error.message); process.exit(1); };
program .command('pull') .description('Pull translations from Google Sheets to translation files') .option('-s, --spreadsheet-id <id>', 'Google Spreadsheet ID', process.env.I18N_SYNCER_SPREADSHEET_ID) .option('-n, --sheet-name <name>', 'Name of the sheet to pull data from', process.env.I18N_SYNCER_SHEET_NAME) .option('-c, --credentials <path>', 'Path to credentials file', process.env.I18N_SYNCER_CREDENTIALS_PATH || './credentials.json') .option('-t, --translation-dir <directory>', 'Directory for translation JSON files', process.env.I18N_SYNCER_TRANSLATION_DIR || './translations') .option('-f, --format <format>', 'Format of translation files (json or js)', process.env.I18N_SYNCER_FORMAT || 'json') .action(async (options) => { try { if (!options.spreadsheetId) { console.error('Error: Spreadsheet ID is required. Provide it with --spreadsheet-id option or set I18N_SYNCER_SPREADSHEET_ID in .env file.'); process.exit(1); }
console.log('Starting translation pull from Google Sheets...');
const syncer = createSyncer(options);
await syncer.pull({ sheetName: options.sheetName, translationDir: options.translationDir, format: options.format, });
} catch (error) { handleError(error); } });
program .command('push') .description('Push translations from translation files to Google Sheets') .option('-s, --spreadsheet-id <id>', 'Google Spreadsheet ID', process.env.I18N_SYNCER_SPREADSHEET_ID) .option('-n, --sheet-name <name>', 'Name of the sheet to push data to', process.env.I18N_SYNCER_SHEET_NAME) .option('-c, --credentials <path>', 'Path to credentials file', process.env.I18N_SYNCER_CREDENTIALS_PATH || './credentials.json') .option('-t, --translation-dir <directory>', 'Directory for translation JSON files', process.env.I18N_SYNCER_TRANSLATION_DIR || './translations') .option('-f, --format <format>', 'Format of translation files to read (json or js)', process.env.I18N_SYNCER_FORMAT || 'json') .action(async (options) => { try { if (!options.spreadsheetId) { console.error('Error: Spreadsheet ID is required. Provide it with --spreadsheet-id option or set I18N_SYNCER_SPREADSHEET_ID in .env file.'); process.exit(1); }
console.log('Starting translation push to Google Sheets...');
const syncer = createSyncer(options);
await syncer.push({ sheetName: options.sheetName, translationDir: options.translationDir, format: options.format, });
} catch (error) { handleError(error); } });
program.parse();
|