diff --git a/lib/backends/fs.js b/lib/backends/fs.js index c9435f0..6826db8 100644 --- a/lib/backends/fs.js +++ b/lib/backends/fs.js @@ -1,6 +1,7 @@ /* istanbul ignore file */ var glob = require('glob'), + yaml = require('js-yaml'), path = require('path'), fs = require('fs'), callsites = require('callsites'), @@ -39,12 +40,12 @@ module.exports = { } options = Object.assign({ - path: 'locales/__lng__/__ns__.json' + path: 'locales/__lng__/__ns__.__ext__' }, options); options.path = path.normalize(options.path); - var glb = options.path.replace('__lng__', '[a-zA-Z\-_]*').replace('__ns__', '[a-zA-Z\-_]*'); - var rgx = options.path.replace('__lng__', '([a-zA-Z\-_]*)').replace('__ns__', '([a-zA-Z\-_]*)'); + var glb = options.path.replace('__lng__', '[a-zA-Z\-_]*').replace('__ns__', '[a-zA-Z\-_]*').replace('__ext__', '@(json|yml|yaml)'); + var rgx = options.path.replace('__lng__', '([a-zA-Z\-_]*)').replace('__ns__', '([a-zA-Z\-_]*)').replace('__ext__', '([a-zA-Z\-_]*)'); rgx = rgx.split('\\').join('\\\\'); // Windows hack, noop for unix file paths rgx = new RegExp(rgx); @@ -90,10 +91,11 @@ module.exports = { var lng = parts[lngIndex]; var ns = parts[nsIndex]; + var ext = path.extname(filename).substr(1); if (lng && ns) { filename = path.resolve(dir, filename); - files.push({ filename, lng, ns }); + files.push({ filename, lng, ns, ext }); } }); done(); @@ -110,16 +112,27 @@ module.exports = { fs.readFile(file.filename, function (err, buffer) { if (err) return done(err); + + let data; try { - datastore[file.lng] = datastore[file.lng] || {}; - let data = JSON.parse(buffer.toString()); - datastore[file.lng][file.ns] = deepCloneMerge(data, datastore[file.lng][file.ns]); + if (file.ext === 'json') { + data = JSON.parse(buffer.toString()); + } + else if (file.ext === 'yaml' || file.ext === 'yml') { + data = yaml.load(buffer.toString()); + } else { + throw new Error('Unknown localisation file format: ' + file.filename); + } } catch(e) { - if (e instanceof SyntaxError) { + if (e instanceof SyntaxError || e instanceof yaml.YAMLException) { e.message = 'Localisation file syntax error: ' + file.filename + ': ' + e.message; } return done(e); } + + datastore[file.lng] = datastore[file.lng] || {}; + datastore[file.lng][file.ns] = deepCloneMerge(data, datastore[file.lng][file.ns]); + done(); }); }, done); diff --git a/package-lock.json b/package-lock.json index 90a2b81..89f9789 100644 --- a/package-lock.json +++ b/package-lock.json @@ -341,6 +341,15 @@ "strip-json-comments": "^3.1.1" }, "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "debug": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", @@ -359,6 +368,16 @@ "type-fest": "^0.8.1" } }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -380,6 +399,15 @@ "resolve-from": "^5.0.0" }, "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -390,6 +418,16 @@ "path-exists": "^4.0.0" } }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -575,13 +613,9 @@ "dev": true }, "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "array-flatten": { "version": "1.1.1", @@ -1014,6 +1048,15 @@ "color-convert": "^2.0.1" } }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "chalk": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", @@ -1063,6 +1106,16 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1835,13 +1888,11 @@ "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" } }, "jsesc": { diff --git a/package.json b/package.json index 163862e..7f4d128 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "deep-clone-merge": "^1.5.2", "findup": "^0.1.5", "glob": "^7.1.7", + "js-yaml": "^4.1.0", "lodash": "^4.17.21" }, "devDependencies": { diff --git a/test/spec/backends/locales/de/test.json b/test/spec/backends/locales/de/test.json deleted file mode 100644 index ab4d4a6..0000000 --- a/test/spec/backends/locales/de/test.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "Hans", - "deep": { - "object": "German" - } -} \ No newline at end of file diff --git a/test/spec/backends/locales/de/test.yaml b/test/spec/backends/locales/de/test.yaml new file mode 100644 index 0000000..15595a1 --- /dev/null +++ b/test/spec/backends/locales/de/test.yaml @@ -0,0 +1,3 @@ +name: Hans +deep: + object: German