Skip to content

Commit

Permalink
Added csv as supported format and fixed token replacement
Browse files Browse the repository at this point in the history
  • Loading branch information
ravi-nextbit committed Mar 31, 2016
1 parent 0f73cf2 commit b613c98
Showing 9 changed files with 158 additions and 17 deletions.
85 changes: 81 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
@@ -46,6 +46,10 @@ function load(options) {
var iniData = fs.readFileSync(path.join(process.cwd(), options.locales, file));
dictionaries[path.basename(file, path.extname(file))] = flat(ini2json(iniData));
break;
case '.csv':
var csvData = fs.readFileSync(path.join(process.cwd(), options.locales, file));
dictionaries[path.basename(file, path.extname(file))] = csv2json(csvData);
break;
}
}

@@ -54,17 +58,33 @@ function load(options) {
}
}

/**
* Splits a line from an ini file into 2. Any subsequent '=' are ignored.
* @param line
* @returns {*[]}
*/
function splitIniLine(line) {
var separator = line.indexOf('=');
if (separator == -1) {
return [line];
}
return [
line.substr(0, separator),
line.substr(separator + 1)
]
}

/**
* Simple conversion helper to get a json file from an ini file.
* @param iniData
* @param {string} iniData
* @returns {{}}
*/
function ini2json(iniData) {
var result = {};
var iniLines = iniData.toString().split('\n');
var context = null;
for (var i in iniLines) {
var fields = iniLines[i].split('=');
var fields = splitIniLine(iniLines[i]);
for (var j in fields) {
fields[j] = fields[j].trim();
}
@@ -86,6 +106,63 @@ function ini2json(iniData) {
return result;
}

/**
* Converts a line of a CSV file to an array of strings, omitting empty fields.
* @param line
*/
function splitCsvLine(line) {
if (!line.trim().length) {
return [];
}
var fields = [];
var inQuotes = false;
var separator = 0;
for (var i = 0; i < line.length; i++) {
switch(line[i]) {
case "\"":
if (i>0 && line[i-1] != "\\") {
inQuotes = !inQuotes;
}
break;
case ",":
if (!inQuotes) {
if (separator < i) {
var field = line.substring(separator, i).trim();
if (field.length) {
fields.push(field);
}
}
separator = i + 1;
}
break;
}
}
fields.push(line.substring(separator).trim());
return fields;
}

/**
* Simple conversion helper to get a json file from a csv file.
* @param {string} csvData
*/
function csv2json(csvData) {
var result = {};
var csvLines = csvData.toString().split('\n');
for (var i in csvLines) {
var fields = splitCsvLine(csvLines[i]);
if (fields.length) {
var key = '';
for (var k = 0; k < fields.length - 1; k++) {
if (fields[k].length) {
key += '.' + fields[k];
}
}
result[key.substr(1)] = fields[fields.length - 1];
}
}
return result;
}

/**
* Performs the actual translation from a tokenized source to the final content.
* @param options
@@ -127,7 +204,7 @@ function translate(options, contents, copied) {
processed[lang] += contents.substring(copied, i);
processed[lang] += dictionaries[lang][key];
processed[lang] += contents.substring(i + length, next == -1 ? contents.length : next);
copied = next + 1;
copied = next;
}

i = next;
@@ -219,4 +296,4 @@ module.exports = function (options) {

cb();
});
};
};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "gulp-international",
"version": "0.0.1",
"version": "0.0.2",
"description": "A gulp plugin that creates multi language versions of your source files",
"license": "Apache-2.0",
"homepage": "http://github.com/mallocator/gulp-international",
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ Features (cause we all love features):
* Custom language descriptors
* Custom filename format
* Custom translation source directory
* Read from .json, .js or .ini file
* Read from .json, .js, .ini or .csv file (for examples check the test folder)


## Install
68 changes: 59 additions & 9 deletions test/index.test.js
Original file line number Diff line number Diff line change
@@ -56,7 +56,7 @@ describe('gulp-international', () => {
helper(options, (files, options) => {
expect(options.delimiter.prefix.length).to.be.gt(0);
expect(options.delimiter.stopCondition).to.be.a('RegExp');
expect(files.length).to.equal(3);
expect(files.length).to.equal(4);
expect(files[0].contents.toString('utf8')).to.equal('<html><body><h1>Inhalt1</h1></body></html>');
expect(files[0].path).to.equal('test/helloworld-de_DE.html');
done();
@@ -80,7 +80,7 @@ describe('gulp-international', () => {
});


it('should be able to replace token with custom suffix delimiters', done => {
it('should be able to limit languages to a whitelist', done => {
var options = {
locales: 'test/locales',
whitelist: 'en_US'
@@ -100,11 +100,11 @@ describe('gulp-international', () => {
blacklist: 'en_US'
};
helper(options, files => {
expect(files.length).to.equal(2);
expect(files.length).to.equal(3);
expect(files[0].contents.toString('utf8')).to.equal('<html><body><h1>Inhalt1</h1></body></html>');
expect(files[0].path).to.equal('test/helloworld-de_DE.html');
expect(files[1].contents.toString('utf8')).to.equal('<html><body><h1>conteúdo1</h1></body></html>');
expect(files[1].path).to.equal('test/helloworld-pt-BR.html');
expect(files[2].contents.toString('utf8')).to.equal('<html><body><h1>conteúdo1</h1></body></html>');
expect(files[2].path).to.equal('test/helloworld-pt-BR.html');
done();
});
});
@@ -116,7 +116,7 @@ describe('gulp-international', () => {
locales: 'test/locales'
};
helper(options, content, files => {
expect(files.length).to.equal(3);
expect(files.length).to.equal(4);
expect(files[0].contents.toString('utf8')).to.equal('<html><body>Not replaced</body></html>');
expect(files[0].path).to.equal('test/helloworld-de_DE.html');
done();
@@ -130,7 +130,7 @@ describe('gulp-international', () => {
locales: 'test/locales'
};
helper(options, content, files => {
expect(files.length).to.equal(3);
expect(files.length).to.equal(4);
expect(files[0].contents.toString('utf8')).to.equal('');
expect(files[0].path).to.equal('test/helloworld-de_DE.html');
done();
@@ -144,7 +144,7 @@ describe('gulp-international', () => {
locales: 'test/locales'
};
helper(options, content, files => {
expect(files.length).to.equal(3);
expect(files.length).to.equal(4);
expect(files[0].contents.toString('utf8')).to.equal('<html><body><h1>Inhalt2</h1></body></html>');
expect(files[0].path).to.equal('test/helloworld-de_DE.html');
expect(files[1].contents.toString('utf8')).to.equal('<html><body><h1>content2</h1></body></html>');
@@ -154,6 +154,20 @@ describe('gulp-international', () => {
});


it('should be able to use csv data as translation files', done => {
var options = {
locales: 'test/locales',
whitelist: 'fr_FR'
};
helper(options, files => {
expect(files.length).to.equal(1);
expect(files[0].contents.toString('utf8')).to.equal('<html><body><h1>contenu1</h1></body></html>');
expect(files[0].path).to.equal('test/helloworld-fr_FR.html');
done();
});
});


it('should support a custom filename format', done => {
var options = {
locales: 'test/locales',
@@ -162,7 +176,8 @@ describe('gulp-international', () => {
helper(options, files => {
expect(files[0].path).to.equal('de_DE/helloworld.html');
expect(files[1].path).to.equal('en_US/helloworld.html');
expect(files[2].path).to.equal('pt-BR/helloworld.html');
expect(files[2].path).to.equal('fr_FR/helloworld.html');
expect(files[3].path).to.equal('pt-BR/helloworld.html');
done();
});
});
@@ -207,4 +222,39 @@ describe('gulp-international', () => {
expect(e).to.be.an('Error');
}
});


it('should be able to process a larger file with multiple replacements', done => {
var content = `
<html>
<body>
<h1>R.section1.token2</h1>
<img src="img/mascot.png" alt="Our funny mascot" />
<div class="welcome">R.token1</div>
<hr />
<p>R.section1.subsection2.token3</p>
</body>
</html>
`;
var options = {
locales: 'test/locales',
whitelist: 'en_US'
};
helper(options, content, files => {
expect(files.length).to.equal(1);
expect(files[0].contents.toString('utf8')).to.equal(`
<html>
<body>
<h1>content2</h1>
<img src="img/mascot.png" alt="Our funny mascot" />
<div class="welcome">content1</div>
<hr />
<p>content3</p>
</body>
</html>
`);
expect(files[0].path).to.equal('test/helloworld-en_US.html');
done();
});
});
});
3 changes: 3 additions & 0 deletions test/locales/de_DE.ini
Original file line number Diff line number Diff line change
@@ -2,3 +2,6 @@ token1=Inhalt1

[section1]
token2=Inhalt2

[unused]
checksplit=This=that
5 changes: 4 additions & 1 deletion test/locales/en_US.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"token1": "content1",
"section1": {
"token2": "content2"
"token2": "content2",
"subsection2": {
"token3": "content3"
}
}
}
4 changes: 4 additions & 0 deletions test/locales/fr_FR.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
,token1,,contenu1
section1,token2,,contenu2
section1,subsection1,token3,contenu3
invalid,checkquote,,"This is something that should, could and would be \"tested\""
1 change: 1 addition & 0 deletions test/locales/other.file
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is just a file to test that only valid files are being used as language files.
5 changes: 4 additions & 1 deletion test/locales/pt-BR.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module.exports = {
token1: 'conteúdo1',
section1: {
token2: "conteúdo2"
token2: 'conteúdo2',
subsection2: {
token3: 'content'
}
}
};

0 comments on commit b613c98

Please sign in to comment.