From 08a17416f3a418f503e793a01f4a269ecba9bc0d Mon Sep 17 00:00:00 2001 From: Andy Hawkes Date: Thu, 27 Nov 2014 16:47:52 +0000 Subject: [PATCH 1/2] Added the option to specify which worksheet to use. Added the options to use all worksheets. Added the option to namespace translation keys based on the worksheet title. Added the ability to throw an error if duplicate translation keys are found for any locale. --- README.md | 24 +++++++- tasks/i18n_gspreadsheet.js | 115 +++++++++++++++++++++++++------------ 2 files changed, 102 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 76146fb..ce6bc6b 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ Set to true to prompt for username and password instead of using `options.google #### options.document_key Type: `String` (required) -The spreadsheet key. You can get this from the URL while viewing your spreadsheet +The spreadsheet key. You can get this from the URL while viewing your spreadsheet *Example: `https://docs.google.com/spreadsheet/ccc?key=#gid=0`* #### options.key_column @@ -86,6 +86,28 @@ Type: `Boolean` -- Default: `true` Enable/disable sorting of the translation keys before writing to the file. If false, translations will appear in the same order as they do in the spreadsheet. +#### options.use_all_worksheets +Type: `Boolean` -- Default: `false` + +Set to true to parse all worksheets. This allows you to break up your localisation spreadsheet into more manageable worksheets if you have a lot of content and/or locales. + +#### options.worksheet_id: 1, +Type: `Integer` -- Default: `1` + +An integer value to signify which worksheet to use - this will be ignored if the `use_all_worksheets` option (above) is set to `true`. + +**NOTE** the worksheet index starts from 1, not 0. + +#### options.use_worksheet_namespacing +Type: `Boolean` -- Default: `false` + +Set to true to prefix all translation keys with the name of the selected worksheet. `"About us": "About us"` from `Sheet1` would become `"Sheet1-About us": "About us"` + +#### options.prevent_conflicts +Type: `Boolean` -- Default: `true` + +Set to true to throw an error if any duplicate translation keys are encountered for any locale. This is useful if the `use_all_worksheets` option (above) is set to `true` and the `use_worksheet_namespacing` option (above) is set to `false` and you inadvertently duplicate translateion keys in different worksheets. + ### Command Line Options #### --regex-filter diff --git a/tasks/i18n_gspreadsheet.js b/tasks/i18n_gspreadsheet.js index 9fa4dad..3019e11 100644 --- a/tasks/i18n_gspreadsheet.js +++ b/tasks/i18n_gspreadsheet.js @@ -38,9 +38,13 @@ module.exports = function(grunt) { default_locale: 'en', use_default_on_missing: false, write_default_translations: false, - sort_keys: true + sort_keys: true, + use_all_worksheets: false, + worksheet_id: 1, + use_worksheet_namespacing: false, + prevent_conflicts: true }); - + var regex_filter = grunt.option('regex-filter'); if (regex_filter) { regex_filter = new RegExp(regex_filter); @@ -51,6 +55,7 @@ module.exports = function(grunt) { var locales = []; var translations = {}; + var worksheets = {}; var gsheet = new GoogleSpreadsheet( options.document_key ); var output_dir = path.resolve( process.cwd() + '/' + options.output_dir ); @@ -90,57 +95,95 @@ module.exports = function(grunt) { grunt.log.error('Invalid google credentials for "' + options.google_account + '"'); return done( false ); } - - gsheet.getRows( 1, this ); + gsheet.getInfo( this ); }, - function buildTranslationJson(err, rows){ + function fetchRowData(err, info){ if ( err ){ - grunt.log.error( err ); + grunt.log.error('Error getting sheet info'); return done( false ); } - if ( rows.length === 0 ){ - grunt.log.error('ERROR: no translations found in sheet'); + worksheets = info.worksheets; + grunt.log.writeln( 'Found ' + worksheets.length + ' worksheets'); + var group = this.group(); + if ( options.use_all_worksheets ) { + // Get rows from all worksheets + for( var i=1; i <= worksheets.length; i++){ + gsheet.getRows( i, group() ); + } + } else { + gsheet.getRows( options.worksheet_id, group() ); + } + }, + function buildTranslationJson(err, sheets){ + if ( err ){ + grunt.log.error( err ); return done( false ); } + sheets.forEach(function(rows, ind, arr){ + var sheetTitle = ''; + if ( options.use_all_worksheets ) { + sheetTitle = worksheets[ind].title; + } else { + sheetTitle = worksheets[options.worksheet_id - 1].title; + } + grunt.log.writeln('Processing worksheet: ' + sheetTitle); + if ( rows.length === 0 ){ + grunt.log.error('ERROR: no translations found in sheet'); + grunt.log.error(rows); + return done( false ); + } - // First determine which locales are supported - var gsheet_keys = _(rows[0]).keys(); - _(gsheet_keys).each(function(locale){ - if ( locale != 'id' && locale.length == 2 ){ - locales.push( locale ); - translations[locale] = {}; - if (regex_filter) { - try { - translations[locale] = JSON.parse(fs.readFileSync(output_dir + '/' + locale + options.ext)); + // First determine which locales are supported + var gsheet_keys = _(rows[0]).keys(); + _(gsheet_keys).each(function(locale){ + if ( locale != 'id' && locale.length == 2 ){ + if(locales.indexOf(locale) == -1) { + locales.push( locale ); + translations[locale] = {}; + } + if (regex_filter) { + try { + translations[locale] = JSON.parse(fs.readFileSync(output_dir + '/' + locale + options.ext)); + } + catch (e) {} } - catch (e) {} } - } - }); + }); + + grunt.log.writeln( 'Found '+ rows.length.toString().cyan +' translations in ' + locales.length.toString().cyan + ' languages' ); - grunt.log.writeln( 'Found '+ rows.length.toString().cyan +' translations in ' + locales.length.toString().cyan + ' languages' ); + // read all translations into an object with the correct keys + _(rows).each(function(row){ + // if an key override column is set, check that first, then use the default locale - // read all translations into an object with the correct keys - _(rows).each(function(row){ - // if an key override column is set, check that first, then use the default locale + var use_key_override = options.key_column && row[options.key_column]; + var translation_key = use_key_override ? row[options.key_column] : row[options.default_locale]; + if ( !translation_key ) return; + if (regex_filter && !regex_filter.test(translation_key)) return; - var use_key_override = options.key_column && row[options.key_column]; - var translation_key = use_key_override ? row[options.key_column] : row[options.default_locale]; - if ( !translation_key ) return; - if (regex_filter && !regex_filter.test(translation_key)) return; - _(locales).each(function(locale){ + if(options.use_worksheet_namespacing){ + translation_key = sheetTitle + '-' + translation_key; + } + + _(locales).each(function(locale){ + if( options.prevent_conflicts && translations[locale][translation_key]){ + grunt.log.error('ERROR: duplicated / conflicting content found in ' + sheetTitle + ': ' + locale + ' - ' + translation_key); + return done( false ); + } - if ( locale == options.default_locale ){ - if ( use_key_override || options.write_default_translations ){ + if ( locale == options.default_locale ){ + if ( use_key_override || options.write_default_translations ){ + translations[locale][translation_key] = row[locale]; + } + } else if ( row[locale] ) { translations[locale][translation_key] = row[locale]; + } else if ( options.use_default_on_missing ){ + translations[locale][translation_key] = row[options.default_locale]; } - } else if ( row[locale] ) { - translations[locale][translation_key] = row[locale]; - } else if ( options.use_default_on_missing ){ - translations[locale][translation_key] = row[options.default_locale]; - } + }); }); }); + this(); }, function ensureDirectoryExists(err){ From 36af07029da0d2c9ab562c134031a98d086f7bd0 Mon Sep 17 00:00:00 2001 From: Andy Hawkes Date: Tue, 2 Jun 2015 13:13:49 +0100 Subject: [PATCH 2/2] Updates to config --- Gruntfile.js | 2 +- package.json | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index e3041d8..50640a8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -35,7 +35,7 @@ module.exports = function(grunt) { key_column: 'key', output_dir: 'tmp', // this document key points to the test file -- see readme for more info - document_key: '0Araic6gTol6SdEtwb1Badl92c2tlek45OUxJZDlyN2c', + document_key: '17i9VdgI2_jEq7tLmkA6YtwswjOAyH_8hyGJW7xG2LzU', write_default_translations: true } } diff --git a/package.json b/package.json index a3454f7..9618db6 100644 --- a/package.json +++ b/package.json @@ -28,16 +28,23 @@ "test": "grunt test" }, "devDependencies": { - "grunt-contrib-jshint": "~0.6.0", + "grunt": "~0.4.1", "grunt-contrib-clean": "~0.4.0", - "grunt-contrib-nodeunit": "~0.2.0", - "grunt": "~0.4.1" + "grunt-contrib-jshint": "~0.6.0", + "grunt-contrib-nodeunit": "~0.2.0" }, "peerDependencies": { "grunt": "~0.4.1" }, "keywords": [ - "gruntplugin", "grunt", "i18n", "google", "spreadsheet", "gdocs", "locale", "translation" + "gruntplugin", + "grunt", + "i18n", + "google", + "spreadsheet", + "gdocs", + "locale", + "translation" ], "dependencies": { "google-spreadsheet": "~0.2.6",