68 Commits

Author SHA1 Message Date
6164134eaf update
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-04-24 12:49:24 +03:00
4aa2cbfe04 cleanup
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-04-24 12:31:26 +03:00
Ruben Vermeersch
a0328f1590 Merge pull request #45 from rubenv/dependabot/npm_and_yarn/cached-path-relative-1.1.0
Bump cached-path-relative from 1.0.2 to 1.1.0
2022-01-28 08:47:05 +01:00
dependabot[bot]
92183c905f Bump cached-path-relative from 1.0.2 to 1.1.0
Bumps [cached-path-relative](https://github.com/ashaffer/cached-path-relative) from 1.0.2 to 1.1.0.
- [Release notes](https://github.com/ashaffer/cached-path-relative/releases)
- [Commits](https://github.com/ashaffer/cached-path-relative/commits)

---
updated-dependencies:
- dependency-name: cached-path-relative
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-27 15:37:00 +00:00
Ruben Vermeersch
e2bdad57be Release v1.1.3 2022-01-19 15:37:38 +01:00
Ruben Vermeersch
2e7e5b6be8 Merge pull request #44 from iddan-flycode/patch-1
Make obsolete public
2022-01-19 15:37:10 +01:00
Iddan Aaronsohn
61363b872b Make obsolete public
Currently, it is impossible in TypeScript to tell if an item is obsolete or not.
2022-01-19 16:14:10 +02:00
Ruben Vermeersch
8d2b93c6c7 Fix build 2021-12-01 10:11:17 +01:00
dependabot[bot]
acb555b562 Bump grunt from 1.0.4 to 1.3.0
Bumps [grunt](https://github.com/gruntjs/grunt) from 1.0.4 to 1.3.0.
- [Release notes](https://github.com/gruntjs/grunt/releases)
- [Changelog](https://github.com/gruntjs/grunt/blob/main/CHANGELOG)
- [Commits](https://github.com/gruntjs/grunt/compare/v1.0.4...v1.3.0)

---
updated-dependencies:
- dependency-name: grunt
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-01 09:08:09 +00:00
Ruben Vermeersch
88364bc5e1 Release v1.1.2 2021-12-01 10:06:48 +01:00
Remko Tronçon
685be92923 Support multiple spaces after msgid 2021-12-01 09:48:44 +01:00
Ruben Vermeersch
ff1b888af1 Release v1.1.1 2021-03-09 09:22:33 +01:00
Ruben Vermeersch
3535e60695 Rebuild 2021-03-09 09:22:03 +01:00
Ruben Vermeersch
11b1affe5b Merge pull request #40 from septs/master
lazy require fs
2021-03-09 09:21:07 +01:00
Septs
29d40186c9 lazy require fs 2021-03-06 01:59:15 +08:00
Ruben Vermeersch
d6937a7da2 Merge pull request #39 from rubenv/revert-38-patch-1
Revert "Fix type of PO.Item"
2020-04-21 09:38:15 +02:00
Ruben Vermeersch
c62b82a98d Revert "Fix type of PO.Item" 2020-04-21 09:38:00 +02:00
Ruben Vermeersch
fe23027f32 Merge pull request #38 from kirillku/patch-1
Fix type of PO.Item
2020-04-21 09:37:31 +02:00
Kirill Kubryakov
d92e1f9e89 Fix type of PO.Item 2020-04-21 10:25:53 +03:00
Ruben Vermeersch
0359aa12a4 Release v1.1.0 2019-06-25 13:31:56 +02:00
Ruben Vermeersch
6357bf3edd Merge pull request #34 from septs/master
rewrite typescript definition file
2019-06-25 13:31:05 +02:00
Septs
3b28b3ed08 remove test code 2019-06-25 19:27:45 +08:00
Septs
207308a1ac rewrite ts define 2019-06-25 19:12:53 +08:00
Ruben Vermeersch
b8676a4fe6 Release v1.0.11 2018-05-25 11:34:42 +02:00
Ruben Vermeersch
bf879ca5ee Rebuild 2018-05-25 11:34:26 +02:00
Martin Bachtík
8bd7810703 header order 2018-05-25 11:21:23 +02:00
Ruben Vermeersch
ad71dba6ad Release v1.0.10 2017-12-04 14:08:38 +01:00
Ruben Vermeersch
ab3d6f8405 Merge pull request #31 from tafkanator/master
added support for multiline msgctxt strings
2017-12-04 14:06:04 +01:00
Taavi Sangel
58ee1abedb added compiled files #31 2017-12-04 13:57:12 +02:00
Taavi Sangel
0aef81f4e9 added test for multiline msgctxt #31 2017-12-04 13:53:16 +02:00
Taavi Sangel
579a5635a6 added support for multiline msgctxt strings 2017-11-21 13:29:28 +02:00
Ruben Vermeersch
03a257b40d Release v1.0.9 2017-09-14 15:27:44 +02:00
Ruben Vermeersch
58875dc119 Merge pull request #30 from janhommes/master
Fixed issue with plural multi line text.
2017-09-14 15:26:50 +02:00
janhommes
a6937bb7f0 Fixed issue with plural multiline text. 2017-09-14 14:37:45 +02:00
Ruben Vermeersch
cfe01e8aea Release v1.0.8 2017-04-24 20:38:10 +02:00
megaboich
14bad962eb Updated Typescript definitions (#29) 2017-04-24 20:36:49 +02:00
Ruben Vermeersch
ff0e5655f9 Release v1.0.7 2017-03-20 10:27:27 +01:00
Ruben Vermeersch
bb56f6e34c Rebuild for #28 2017-03-20 10:27:12 +01:00
Ruben Vermeersch
f035affef6 Merge pull request #28 from dedesite/patch-1
Avoid putting a space in empty comments
2017-03-20 10:26:46 +01:00
Andréas Livet
18a4cc0cb5 Add test to ensure no spaces are added on empty comments 2017-03-20 10:20:04 +01:00
Andréas Livet
0fcff887fe Avoid putting a space in empty comments
In our pipeline, empty comments in po files are generated without
a space after '#' and saving a po file using pofile lib generates
unwanted diff that need to be handle manually which is really annoying.
This pull request simply trim the comment line.
2017-03-17 14:25:20 +01:00
Ruben Vermeersch
9689ae5b7f Release v1.0.6 2017-03-13 19:39:23 +01:00
Ruben Vermeersch
5cbb657f20 Merge pull request #27 from ma2ciek/master
Add support for the typescript projects and IDE-s.
2017-03-13 19:39:04 +01:00
Maciej Bukowski
e038f25d5b Added support for the typescript projects and IDE-s. 2017-03-13 17:40:01 +01:00
Ruben Vermeersch
f26ecb0d63 Release v1.0.5 2017-03-09 07:45:36 +01:00
Ruben Vermeersch
3324041669 Rebuild 2017-03-09 07:45:14 +01:00
Ruben Vermeersch
d30a02f3c2 Merge pull request #25 from appropos/msgstr-nplurals
Stub out missing translations according to language plurals
2017-03-09 07:44:43 +01:00
rosston
0e3a6d74f3 Stub out missing translations according to language plurals. 2017-03-08 10:24:51 -05:00
Ruben Vermeersch
d783222d37 Test with "node" 2017-03-06 17:30:59 +01:00
Ruben Vermeersch
36f5d05828 Release v1.0.4 2017-03-06 17:26:55 +01:00
Ruben Vermeersch
8fe9cd7bf8 Fix alias 2017-03-06 17:26:45 +01:00
Ruben Vermeersch
48fa2c39f3 Bump 2017-02-10 17:47:45 +01:00
Ruben Vermeersch
037edff739 Release v1.0.3 2017-02-10 17:46:32 +01:00
Ruben Vermeersch
16f423879a Rebuild 2017-02-10 17:02:46 +01:00
Ruben Vermeersch
52c11f77e9 Merge pull request #24 from appropos/msgstr-0
Write proper plural msgstr[0]
2017-02-10 17:01:30 +01:00
rosston
115459160e Use msgstr[0] when stringifying an untranslated plural item. 2017-02-10 10:18:01 -05:00
rosston
79407fcf5e Remove lodash.isarray (use native Array.isArray).
Other code was already depending on Object.keys() and
Array.prototype.filter(), which are also ES5 along with
Array.isArray().
2017-02-09 22:44:46 -05:00
rosston
e2330bd433 Upgrade dev dependencies. 2017-02-09 22:44:45 -05:00
Ruben Vermeersch
853823f214 Merge pull request #22 from paulpdaniels/patch-1
Fix readme reference
2015-10-21 07:28:53 +02:00
Paul Daniels
832962d30d Fix readme reference 2015-10-20 16:07:21 -07:00
Ruben Vermeersch
f6119a57af Release v1.0.2 2015-09-23 07:41:22 +02:00
Ruben Vermeersch
6c09df93a2 Rebuild 2015-09-23 07:41:09 +02:00
Ruben Vermeersch
1bf498ecf7 Merge pull request #19 from rubenv/no_headers
Add proper support for no headers in po files
2015-09-23 07:40:44 +02:00
Julian Bäume
71bb04f046 add support for po files without headers
basically fix all the examples.
2015-09-22 23:36:12 +02:00
Julian Bäume
ba9a2db453 add examples for po files without any headers
those should at least be fixed
2015-09-22 10:38:43 +02:00
Ruben Vermeersch
fbe773c636 Release v1.0.1 2015-09-21 09:35:02 +02:00
Ruben Vermeersch
7ceda82794 Merge pull request #17 from rubenv/fix_issue16
fix issue #16
2015-09-21 09:34:41 +02:00
Julian Bäume
d1be0f51b0 fix issue #16
add a blank line in the comments of the headers of the big.po file. This
breaks parsing the headers. msgcat of gettext tools just ignores empty
lines until a header is found and treats everything above as header
comment.

The change to the library itself fixes the tests again, after the blank
linke broke 3.
2015-09-21 09:13:43 +02:00
22 changed files with 14082 additions and 1072 deletions

View File

@@ -1,6 +1,5 @@
language: node_js
node_js:
- "0.10"
- "0.11"
- "node"
before_install:
- npm install -g grunt-cli

View File

@@ -5,7 +5,7 @@ module.exports = (grunt) ->
@loadNpmTasks('grunt-contrib-jshint')
@loadNpmTasks('grunt-contrib-uglify')
@loadNpmTasks('grunt-contrib-watch')
@loadNpmTasks('grunt-jscs-checker')
@loadNpmTasks('grunt-jscs')
@loadNpmTasks('grunt-mocha-cli')
@initConfig
@@ -43,7 +43,8 @@ module.exports = (grunt) ->
files:
'dist/pofile.js': ['lib/po.js']
options:
alias: 'lib/po.js:pofile'
alias:
pofile: './lib/po.js'
uglify:
dist:
@@ -52,7 +53,7 @@ module.exports = (grunt) ->
bump:
options:
files: ['package.json', 'bower.json']
files: ['package.json', 'package-lock.json', 'bower.json']
commitFiles: ['-a']
pushTo: 'origin'

View File

@@ -1,4 +1,4 @@
Copyright (C) 2013-2014 Ruben Vermeersch
Copyright (C) 2013-2017 Ruben Vermeersch
Copyright (C) 2012 Michael Holly
Permission is hereby granted, free of charge, to any person obtaining a copy of

View File

@@ -81,7 +81,7 @@ po.save('out.po', function (err) {
### The PO.Item class
The `PO` class exposes the following members:
The `PO.Item` class exposes the following members:
* `msgid`: The message id.
* `msgid_plural`: The plural message id (null if absent).
@@ -143,7 +143,7 @@ PO.load('text.po', function (err, po) {
(The MIT License)
Copyright (C) 2013-2014 by Ruben Vermeersch <ruben@rocketeer.be>
Copyright (C) 2013-2017 by Ruben Vermeersch <ruben@rocketeer.be>
Copyright (C) 2012 by Michael Holly
Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -1,6 +1,6 @@
{
"name": "pofile",
"version": "1.0.0",
"version": "1.1.3",
"authors": [
"Ruben Vermeersch <ruben@rocketeer.be>"
],

213
dist/pofile.js vendored
View File

@@ -1,9 +1,4 @@
require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"pofile":[function(require,module,exports){
module.exports=require('W8CkM0');
},{}],"W8CkM0":[function(require,module,exports){
var fs = require('fs');
var isArray = require('lodash.isarray');
require=(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({"pofile":[function(require,module,exports){
function trim(string) {
return string.replace(/^\s+|\s+$/g, '');
}
@@ -12,33 +7,46 @@ var PO = function () {
this.comments = [];
this.extractedComments = [];
this.headers = {};
this.headerOrder = [];
this.items = [];
};
PO.prototype.save = function (filename, callback) {
fs.writeFile(filename, this.toString(), callback);
};
PO.prototype.toString = function () {
var lines = [];
if (this.comments) {
this.comments.forEach(function (comment) {
lines.push('# ' + comment);
lines.push(('# ' + comment).trim());
});
}
if (this.extractedComments) {
this.extractedComments.forEach(function (comment) {
lines.push('#. ' + comment);
lines.push(('#. ' + comment).trim());
});
}
lines.push('msgid ""');
lines.push('msgstr ""');
var keys = Object.keys(this.headers);
var self = this;
var headerOrder = [];
this.headerOrder.forEach(function (key) {
if (key in self.headers) {
headerOrder.push(key);
}
});
var keys = Object.keys(this.headers);
keys.forEach(function (key) {
if (headerOrder.indexOf(key) === -1) {
headerOrder.push(key);
}
});
headerOrder.forEach(function (key) {
lines.push('"' + key + ': ' + self.headers[key] + '\\n"');
});
@@ -52,22 +60,22 @@ PO.prototype.toString = function () {
return lines.join('\n');
};
PO.load = function (filename, callback) {
fs.readFile(filename, 'utf-8', function (err, data) {
if (err) {
return callback(err);
}
var po = PO.parse(data);
callback(null, po);
});
};
PO.parse = function (data) {
//support both unix and windows newline formats.
data = data.replace(/\r\n/g, '\n');
var po = new PO();
var sections = data.split(/\n\n/);
var headers = sections.shift();
var headers = [];
//everything until the first 'msgid ""' is considered header
while (sections[0] && (headers.length === 0 || headers[headers.length - 1].indexOf('msgid ""') < 0)) {
if (sections[0].match(/msgid\s+"[^"]/)) {
//found first real string, adding a dummy header item
headers.push('msgid ""');
} else {
headers.push(sections.shift());
}
}
headers = headers.join('\n');
var lines = sections.join('\n').split(/\n/);
po.headers = {
@@ -82,6 +90,7 @@ PO.parse = function (data) {
'Content-Transfer-Encoding': '',
'Plural-Forms': '',
};
po.headerOrder = [];
headers.split(/\n/).reduce(function (acc, line) {
if (acc.merge) {
@@ -105,10 +114,13 @@ PO.parse = function (data) {
var name = p.shift().trim();
var value = p.join(':').trim();
po.headers[name] = value;
po.headerOrder.push(name);
}
});
var item = new PO.Item();
var parsedPluralForms = PO.parsePluralForms(po.headers['Plural-Forms']);
var nplurals = parsedPluralForms.nplurals;
var item = new PO.Item({ nplurals: nplurals });
var context = null;
var plural = 0;
var obsoleteCount = 0;
@@ -122,7 +134,7 @@ PO.parse = function (data) {
obsoleteCount = 0;
noCommentLineCount = 0;
po.items.push(item);
item = new PO.Item();
item = new PO.Item({ nplurals: nplurals });
}
}
@@ -204,6 +216,7 @@ PO.parse = function (data) {
} else if (line.match(/^msgctxt/)) { // Context
finish();
item.msgctxt = extract(line);
context = 'msgctxt';
noCommentLineCount++;
} else { // Probably multiline string or blank
if (line.length > 0) {
@@ -214,6 +227,8 @@ PO.parse = function (data) {
item.msgid += extract(line);
} else if (context === 'msgid_plural') {
item.msgid_plural += extract(line);
} else if (context === 'msgctxt') {
item.msgctxt += extract(line);
}
}
}
@@ -228,7 +243,26 @@ PO.parse = function (data) {
return po;
};
PO.Item = function () {
PO.parsePluralForms = function (pluralFormsString) {
var results = (pluralFormsString || '')
.split(';')
.reduce(function (acc, keyValueString) {
var trimmedString = keyValueString.trim();
var equalsIndex = trimmedString.indexOf('=');
var key = trimmedString.substring(0, equalsIndex).trim();
var value = trimmedString.substring(equalsIndex + 1).trim();
acc[key] = value;
return acc;
}, {});
return {
nplurals: results.nplurals,
plural: results.plural
};
};
PO.Item = function (options) {
var nplurals = options && options.nplurals;
this.msgid = '';
this.msgctxt = null;
this.references = [];
@@ -238,6 +272,8 @@ PO.Item = function () {
this.extractedComments = [];
this.flags = {};
this.obsolete = false;
var npluralsNumber = Number(nplurals);
this.nplurals = (isNaN(npluralsNumber)) ? 2 : npluralsNumber;
};
PO.Item.prototype.toString = function () {
@@ -284,6 +320,15 @@ PO.Item.prototype.toString = function () {
return lines;
};
//handle \n in single-line texts (can not be handled in _escape)
var _processLineBreak = function (keyword, text, index) {
var processed = _process(keyword, text, index);
for (var i = 1; i < processed.length - 1; i++) {
processed[i] = processed[i].slice(0, -1) + '\\n"';
}
return processed;
};
// https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
// says order is translator-comments, extracted-comments, references, flags
@@ -310,17 +355,28 @@ PO.Item.prototype.toString = function () {
['msgctxt', 'msgid', 'msgid_plural', 'msgstr'].forEach(function (keyword) {
var text = self[keyword];
if (text != null) {
if (isArray(text) && text.length > 1) {
text.forEach(function (t, i) {
lines = lines.concat(mkObsolete + _process(keyword, t, i));
var hasTranslation = false;
if (Array.isArray(text)) {
hasTranslation = text.some(function (text) {
return text;
});
} else {
text = isArray(text) ? text.join() : text;
var processed = _process(keyword, text);
//handle \n in single-line texts (can not be handled in _escape)
for (var i = 1; i < processed.length - 1; i++) {
processed[i] = processed[i].slice(0, -1) + '\\n"';
}
if (Array.isArray(text) && text.length > 1) {
text.forEach(function (t, i) {
var processed = _processLineBreak(keyword, t, i);
lines = lines.concat(mkObsolete + processed.join('\n' + mkObsolete));
});
} else if (self.msgid_plural && keyword === 'msgstr' && !hasTranslation) {
for (var pluralIndex = 0; pluralIndex < self.nplurals; pluralIndex++) {
lines = lines.concat(mkObsolete + _process(keyword, '', pluralIndex));
}
} else {
var index = (self.msgid_plural && Array.isArray(text)) ?
0 :
undefined;
text = Array.isArray(text) ? text.join() : text;
var processed = _processLineBreak(keyword, text, index);
lines = lines.concat(mkObsolete + processed.join('\n' + mkObsolete));
}
}
@@ -331,89 +387,4 @@ PO.Item.prototype.toString = function () {
module.exports = PO;
},{"fs":3,"lodash.isarray":4}],3:[function(require,module,exports){
},{}],4:[function(require,module,exports){
/**
* Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
* Build: `lodash modularize modern exports="npm" -o ./npm/`
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <http://lodash.com/license>
*/
var isNative = require('lodash._isnative');
/** `Object#toString` result shortcuts */
var arrayClass = '[object Array]';
/** Used for native method references */
var objectProto = Object.prototype;
/** Used to resolve the internal [[Class]] of values */
var toString = objectProto.toString;
/* Native method shortcuts for methods with the same name as other `lodash` methods */
var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray;
/**
* Checks if `value` is an array.
*
* @static
* @memberOf _
* @type Function
* @category Objects
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is an array, else `false`.
* @example
*
* (function() { return _.isArray(arguments); })();
* // => false
*
* _.isArray([1, 2, 3]);
* // => true
*/
var isArray = nativeIsArray || function(value) {
return value && typeof value == 'object' && typeof value.length == 'number' &&
toString.call(value) == arrayClass || false;
};
module.exports = isArray;
},{"lodash._isnative":5}],5:[function(require,module,exports){
/**
* Lo-Dash 2.4.1 (Custom Build) <http://lodash.com/>
* Build: `lodash modularize modern exports="npm" -o ./npm/`
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.5.2 <http://underscorejs.org/LICENSE>
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
* Available under MIT license <http://lodash.com/license>
*/
/** Used for native method references */
var objectProto = Object.prototype;
/** Used to resolve the internal [[Class]] of values */
var toString = objectProto.toString;
/** Used to detect if a method is native */
var reNative = RegExp('^' +
String(toString)
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
.replace(/toString| for [^\]]+/g, '.*?') + '$'
);
/**
* Checks if `value` is a native function.
*
* @private
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if the `value` is a native function, else `false`.
*/
function isNative(value) {
return typeof value == 'function' && reNative.test(value);
}
module.exports = isNative;
},{}]},{},["W8CkM0"])
},{}]},{},["pofile"]);

2
dist/pofile.min.js vendored

File diff suppressed because one or more lines are too long

122
lib/po.js
View File

@@ -1,6 +1,3 @@
var fs = require('fs');
var isArray = require('lodash.isarray');
function trim(string) {
return string.replace(/^\s+|\s+$/g, '');
}
@@ -9,33 +6,46 @@ var PO = function () {
this.comments = [];
this.extractedComments = [];
this.headers = {};
this.headerOrder = [];
this.items = [];
};
PO.prototype.save = function (filename, callback) {
fs.writeFile(filename, this.toString(), callback);
};
PO.prototype.toString = function () {
var lines = [];
if (this.comments) {
this.comments.forEach(function (comment) {
lines.push('# ' + comment);
lines.push(('# ' + comment).trim());
});
}
if (this.extractedComments) {
this.extractedComments.forEach(function (comment) {
lines.push('#. ' + comment);
lines.push(('#. ' + comment).trim());
});
}
lines.push('msgid ""');
lines.push('msgstr ""');
var keys = Object.keys(this.headers);
var self = this;
var headerOrder = [];
this.headerOrder.forEach(function (key) {
if (key in self.headers) {
headerOrder.push(key);
}
});
var keys = Object.keys(this.headers);
keys.forEach(function (key) {
if (headerOrder.indexOf(key) === -1) {
headerOrder.push(key);
}
});
headerOrder.forEach(function (key) {
lines.push('"' + key + ': ' + self.headers[key] + '\\n"');
});
@@ -49,22 +59,22 @@ PO.prototype.toString = function () {
return lines.join('\n');
};
PO.load = function (filename, callback) {
fs.readFile(filename, 'utf-8', function (err, data) {
if (err) {
return callback(err);
}
var po = PO.parse(data);
callback(null, po);
});
};
PO.parse = function (data) {
//support both unix and windows newline formats.
data = data.replace(/\r\n/g, '\n');
var po = new PO();
var sections = data.split(/\n\n/);
var headers = sections.shift();
var headers = [];
//everything until the first 'msgid ""' is considered header
while (sections[0] && (headers.length === 0 || headers[headers.length - 1].indexOf('msgid ""') < 0)) {
if (sections[0].match(/msgid\s+"[^"]/)) {
//found first real string, adding a dummy header item
headers.push('msgid ""');
} else {
headers.push(sections.shift());
}
}
headers = headers.join('\n');
var lines = sections.join('\n').split(/\n/);
po.headers = {
@@ -79,6 +89,7 @@ PO.parse = function (data) {
'Content-Transfer-Encoding': '',
'Plural-Forms': '',
};
po.headerOrder = [];
headers.split(/\n/).reduce(function (acc, line) {
if (acc.merge) {
@@ -102,10 +113,13 @@ PO.parse = function (data) {
var name = p.shift().trim();
var value = p.join(':').trim();
po.headers[name] = value;
po.headerOrder.push(name);
}
});
var item = new PO.Item();
var parsedPluralForms = PO.parsePluralForms(po.headers['Plural-Forms']);
var nplurals = parsedPluralForms.nplurals;
var item = new PO.Item({ nplurals: nplurals });
var context = null;
var plural = 0;
var obsoleteCount = 0;
@@ -119,7 +133,7 @@ PO.parse = function (data) {
obsoleteCount = 0;
noCommentLineCount = 0;
po.items.push(item);
item = new PO.Item();
item = new PO.Item({ nplurals: nplurals });
}
}
@@ -201,6 +215,7 @@ PO.parse = function (data) {
} else if (line.match(/^msgctxt/)) { // Context
finish();
item.msgctxt = extract(line);
context = 'msgctxt';
noCommentLineCount++;
} else { // Probably multiline string or blank
if (line.length > 0) {
@@ -211,6 +226,8 @@ PO.parse = function (data) {
item.msgid += extract(line);
} else if (context === 'msgid_plural') {
item.msgid_plural += extract(line);
} else if (context === 'msgctxt') {
item.msgctxt += extract(line);
}
}
}
@@ -225,7 +242,26 @@ PO.parse = function (data) {
return po;
};
PO.Item = function () {
PO.parsePluralForms = function (pluralFormsString) {
var results = (pluralFormsString || '')
.split(';')
.reduce(function (acc, keyValueString) {
var trimmedString = keyValueString.trim();
var equalsIndex = trimmedString.indexOf('=');
var key = trimmedString.substring(0, equalsIndex).trim();
var value = trimmedString.substring(equalsIndex + 1).trim();
acc[key] = value;
return acc;
}, {});
return {
nplurals: results.nplurals,
plural: results.plural
};
};
PO.Item = function (options) {
var nplurals = options && options.nplurals;
this.msgid = '';
this.msgctxt = null;
this.references = [];
@@ -235,6 +271,8 @@ PO.Item = function () {
this.extractedComments = [];
this.flags = {};
this.obsolete = false;
var npluralsNumber = Number(nplurals);
this.nplurals = (isNaN(npluralsNumber)) ? 2 : npluralsNumber;
};
PO.Item.prototype.toString = function () {
@@ -281,6 +319,15 @@ PO.Item.prototype.toString = function () {
return lines;
};
//handle \n in single-line texts (can not be handled in _escape)
var _processLineBreak = function (keyword, text, index) {
var processed = _process(keyword, text, index);
for (var i = 1; i < processed.length - 1; i++) {
processed[i] = processed[i].slice(0, -1) + '\\n"';
}
return processed;
};
// https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
// says order is translator-comments, extracted-comments, references, flags
@@ -307,17 +354,28 @@ PO.Item.prototype.toString = function () {
['msgctxt', 'msgid', 'msgid_plural', 'msgstr'].forEach(function (keyword) {
var text = self[keyword];
if (text != null) {
if (isArray(text) && text.length > 1) {
text.forEach(function (t, i) {
lines = lines.concat(mkObsolete + _process(keyword, t, i));
var hasTranslation = false;
if (Array.isArray(text)) {
hasTranslation = text.some(function (text) {
return text;
});
} else {
text = isArray(text) ? text.join() : text;
var processed = _process(keyword, text);
//handle \n in single-line texts (can not be handled in _escape)
for (var i = 1; i < processed.length - 1; i++) {
processed[i] = processed[i].slice(0, -1) + '\\n"';
}
if (Array.isArray(text) && text.length > 1) {
text.forEach(function (t, i) {
var processed = _processLineBreak(keyword, t, i);
lines = lines.concat(mkObsolete + processed.join('\n' + mkObsolete));
});
} else if (self.msgid_plural && keyword === 'msgstr' && !hasTranslation) {
for (var pluralIndex = 0; pluralIndex < self.nplurals; pluralIndex++) {
lines = lines.concat(mkObsolete + _process(keyword, '', pluralIndex));
}
} else {
var index = (self.msgid_plural && Array.isArray(text)) ?
0 :
undefined;
text = Array.isArray(text) ? text.join() : text;
var processed = _processLineBreak(keyword, text, index);
lines = lines.concat(mkObsolete + processed.join('\n' + mkObsolete));
}
}

13831
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,27 @@
{
"name": "pofile",
"description": "Parse and serialize Gettext PO files.",
"version": "1.0.0",
"version": "1.1.5",
"author": {
"name": "Ruben Vermeersch",
"email": "ruben@savanne.be",
"url": "http://savanne.be/"
"name": "Vasiliy Tolstov",
"email": "v.tolstov@unistack.org",
"url": "https://unistack.org"
},
"contributors": [
"Eyal Lewinsohn",
"Gabe Gorelick",
"Julian Bäume",
"Mike Holly",
"Sander Houttekier"
"Sander Houttekier",
"Vasiliy Tolstov"
],
"homepage": "http://github.com/rubenv/pofile",
"homepage": "http://github.com/unistack-org/pofile",
"repository": {
"type": "git",
"url": "http://github.com/rubenv/pofile.git"
"url": "http://github.com/unistack-org/pofile.git"
},
"main": "./lib/po",
"types": "./pofile.d.ts",
"keywords": [
"i18n",
"l10n",
@@ -35,18 +37,16 @@
"test": "test"
},
"devDependencies": {
"browserify": "~3.11.1",
"grunt": "~0.4.2",
"grunt-browserify": "~1.3.0",
"grunt-bump": "0.0.13",
"grunt-contrib-clean": "~0.5.0",
"grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-uglify": "~0.2.7",
"grunt-contrib-watch": "~0.5.3",
"grunt-jscs-checker": "^0.5.1",
"grunt-mocha-cli": "~1.4.0"
},
"dependencies": {
"lodash.isarray": "~2.4.1"
"browserify": "~14.0.0",
"coffeescript": "^2.6.1",
"grunt": "~1.3.0",
"grunt-browserify": "^5.1.0",
"grunt-bump": "0.8.0",
"grunt-contrib-clean": "^2.0.1",
"grunt-contrib-jshint": "^3.2.0",
"grunt-contrib-uglify": "^2.3.0",
"grunt-contrib-watch": "^1.1.0",
"grunt-jscs": "^3.0.1",
"grunt-mocha-cli": "^6.0.0"
}
}

39
pofile.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
declare interface IHeaders {
'Project-Id-Version': string;
'Report-Msgid-Bugs-To': string;
'POT-Creation-Date': string;
'PO-Revision-Date': string;
'Last-Translator': string;
'Language': string;
'Language-Team': string;
'Content-Type': string;
'Content-Transfer-Encoding': string;
'Plural-Forms': string;
[name: string]: string;
}
declare class Item {
public msgid: string;
public msgctxt?: string;
public references: string[];
public msgid_plural?: string;
public msgstr: string[];
public comments: string[];
public extractedComments: string[];
public flags: Record<string, boolean | undefined>;
public obsolete: boolean;
private nplurals: number;
}
declare class PO {
public comments: string[];
public extractedComments: string[];
public items: Item[];
public headers: Partial<IHeaders>
public static parse(data: string): PO;
public static parsePluralForms(forms: string): PO;
public static Item: typeof Item;
}
export = PO

View File

@@ -1,25 +0,0 @@
var assert = require('assert');
var PO = require('..');
describe('Comments', function () {
var po;
before(function (done) {
PO.load(__dirname + '/fixtures/big.po', function (err, result) {
assert.equal(err, null);
po = result;
done();
});
});
it('Parses the po file', function () {
assert.notEqual(po, null);
});
it('Parses the comments', function () {
assert.equal(po.comments.length, 3);
assert.equal(po.comments[0], 'French translation of Link (6.x-2.9)');
assert.equal(po.comments[1], 'Copyright (c) 2011 by the French translation team');
assert.equal(po.comments[2], '');
});
});

297
test/fixtures/big.po vendored
View File

@@ -1,297 +0,0 @@
# French translation of Link (6.x-2.9)
# Copyright (c) 2011 by the French translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Link (6.x-2.9)\n"
"POT-Creation-Date: 2011-12-31 23:39+0000\n"
"PO-Revision-Date: 2013-12-17 14:21+0100\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Last-Translator: Ruben Vermeersch <ruben@rocketeer.be>\n"
"Language: fr\n"
"X-Generator: Poedit 1.6.2\n"
msgid "Title"
msgstr "Titre"
msgid "CCK"
msgstr "CCK"
msgid "Content"
msgstr "Contenu"
msgid "Link"
msgstr "Lien"
msgid "Link Target"
msgstr "Cible du Lien"
msgid "URL"
msgstr "URL"
msgid "Placeholder tokens"
msgstr "Jetons (tokens) de substitution"
msgid ""
"The following placeholder tokens can be used in both paths and titles. When "
"used in a path or title, they will be replaced with the appropriate values."
msgstr ""
"Les ébauches de jetons suivantes peuvent être utilisées à la fois dans les "
"chemins et dans les titres. Lorsqu'elles sont utilisées dans un chemin ou un "
"titre, elles seront remplacées par les valeurs appropriées."
msgid "Optional Title"
msgstr "Titre Optionnel"
msgid "Required Title"
msgstr "Titre Obligatoire"
msgid "No Title"
msgstr "Aucun Titre"
msgid "Link Title"
msgstr "Titre du Lien"
msgid "URL Display Cutoff"
msgstr "Coupure de l'Affichage de l'URL"
msgid ""
"If the user does not include a title for this link, the URL will be used as "
"the title. When should the link title be trimmed and finished with an "
"elipsis (&hellip;)? Leave blank for no limit."
msgstr ""
"Si l'utilisateur n'inclue pas de titre pour ce lien, l'URL sera utilisée en "
"tant que titre. A quel endroit le lien devra-t-il être coupé et terminé par "
"une ellipse (&hellip;) ? Laissez vide pour aucune limite."
msgid "Default (no target attribute)"
msgstr "Par Défaut (aucun attribut de cible)"
msgid "Open link in window root"
msgstr "Ouvrir le lien dans la fenêtre courante"
msgid "Open link in new window"
msgstr "Ouvrir le lien dans une nouvelle fenêtre"
msgid "Allow the user to choose"
msgstr "Autoriser l'utilisateur à choisir"
msgid "Additional CSS Class"
msgstr "Classe CSS additionnelle"
msgid "Not a valid URL."
msgstr "Cette URL n'est pas valide."
msgid "Titles are required for all links."
msgstr "Les titres sont obligatoires pour tous les liens."
msgid "Open URL in a New Window"
msgstr "Ouvril l'URL dans une Nouvelle Fenêtre"
msgid "Defines simple link field types."
msgstr "Définit les types de champs \"lien simple\"."
msgid "Link URL"
msgstr "Url du Lien"
msgid "Wildcard"
msgstr "Joker"
msgid "="
msgstr "="
msgid "Protocol"
msgstr "Protocole"
msgid "Optional URL"
msgstr "URL optionnelle"
msgid "Static Title: "
msgstr "Titre Statique : "
msgid ""
"If the link title is optional or required, a field will be displayed to the "
"end user. If the link title is static, the link will always use the same "
"title. If <a href=\"http://drupal.org/project/token\">token module</a> is "
"installed, the static title value may use any other node field as its value. "
"Static and token-based titles may include most inline XHTML tags such as "
"<em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc."
msgstr ""
"Si le titre du lien est facultatif ou obligatoire, un champ sera affiché à "
"l'utilisateur final. Si le titre du lien est statique, le lien utilisera "
"toujours le même titre. Si le <a href=\"http://drupal.org/project/token"
"\">module token</a> est installé, le titre statique peut utiliser n'importe "
"quel autre champ du nœud pour sa valeur. Les titres statiques et basés sur "
"des jetons (tokens) peuvent contenir la plupart des balises XHTML en ligne, "
"telles que <em>strong</em>, <em>em</em>, <em>img</em>, <em>span</em>, etc."
msgid "Allow user-entered tokens"
msgstr "Autoriser les jetons (tokens) saisis par l'utilisateur"
msgid ""
"Checking will allow users to enter tokens in URLs and Titles on the node "
"edit form. This does not affect the field settings on this page."
msgstr ""
"Le fait de cocher cette case permettra aux utilisateurs de saisir des jetons "
"dans les URL et les Titres dans le formulaire d'édition du nœud. Ceci "
"n'affecte pas les configurations de champ sur cette page."
msgid "Rel Attribute"
msgstr "Attribut Rel"
msgid ""
"When output, this link will have this rel attribute. The most common usage "
"is <a href=\"http://en.wikipedia.org/wiki/Nofollow\">rel=&quot;nofollow&quot;"
"</a> which prevents some search engines from spidering entered links."
msgstr ""
"Quand il sera affiché, ce lien aura cet attribut rel. L'usage le plus commun "
"est <a href=\"http://fr.wikipedia.org/wiki/Nofollow\">rel=&quot;"
"nofollow&quot;</a> qui empêche certains moteurs de recherche d'aspirer les "
"liens suivis."
msgid "A default title must be provided if the title is a static value"
msgstr ""
"Un titre pas défaut doit être fourni si le titre est une valeur statique"
msgid "At least one title or URL must be entered."
msgstr "Vous devez saisir au moins un titre ou une URL."
msgid "You cannot enter a title without a link url."
msgstr "Vous ne pouvez pas saisir un titre dans une url de lien."
msgid "Title, as link (default)"
msgstr "Titre, en tant que lien (par défaut)"
msgid "URL, as link"
msgstr "URL, en tant que lien"
msgid "Short, as link with title \"Link\""
msgstr "Court, comme lien avec le titre \"Lien\""
msgid "Label, as link with label as title"
msgstr "Étiquette, comme lien avec l'étiquette comme titre"
msgid "Separate title and URL"
msgstr "Titre et URL séparés"
msgid "Validator"
msgstr "Validateur"
msgid "Is one of"
msgstr "Fait partie de"
msgid "@label title"
msgstr "Titre de @label"
msgid "@label protocol"
msgstr "Protocole de @label"
msgid "@label target"
msgstr "Cible de @label"
msgid ""
"The title to use when this argument is present; it will override the title "
"of the view and titles from previous arguments. You can use percent "
"substitution here to replace with argument titles. Use \"%1\" for the first "
"argument, \"%2\" for the second, etc."
msgstr ""
"Le titre à utiliser lorsque cet argument est présent ; il écrasera le titre "
"de la vue et les titres provenant des arguments précédents. Vous pouvez "
"utiliser ici les substitutions de pourcentage pour remplacer avec les titres "
"des arguments. Utilisez \"%1\" pour le premier argument, \"%2\" pour le "
"second, etc."
msgid "Action to take if argument is not present"
msgstr "Action à mener si l'argument est absent"
msgid ""
"If this value is received as an argument, the argument will be ignored; i.e, "
"\"all values\""
msgstr ""
"Si cette valeur est reçue comme argument, l'argument sera ignoré ; "
"correspond à \"toutes les valeurs\""
msgid "Wildcard title"
msgstr "Titre du joker"
msgid "The title to use for the wildcard in substitutions elsewhere."
msgstr ""
"Le titre à utiliser pour le joker dans les substitutions partout ailleurs."
msgid "<Basic validation>"
msgstr "<Validation basique>"
msgid "Action to take if argument does not validate"
msgstr "Actions à mener si l'argument ne passe pas la validation"
msgid ""
"The protocols displayed here are those globally available. You may add more "
"protocols by modifying the <em>filter_allowed_protocols</em> variable in "
"your installation."
msgstr ""
"Les protocoles affichés ici sont ceux disponibles de manière globale. Vous "
"pouvez ajouter plus de protocoles en modifiant la variable "
"<em>filter_allowed_protocols</em> de votre installation."
msgid "Link title"
msgstr "Titre du lien"
msgid "exposed"
msgstr "exposé"
msgid "Formatted html link"
msgstr "Lien html formaté"
msgid "Store a title, href, and attributes in the database to assemble a link."
msgstr ""
"Stocker un titre, href et des attributs dans la base de données pour les "
"assembler dans un lien."
msgid "URL, as plain text"
msgstr "URL, texte simple"
msgid "@label URL"
msgstr "URL de @label"
msgid "Validate URL"
msgstr "Valider l'URL"
msgid ""
"If checked, the URL field will be verified as a valid URL during validation."
msgstr ""
"Si coché, la validité du format de l'URL sera verifiée durant la validation."
msgid ""
"If checked, the URL field is optional and submitting a title alone will be "
"acceptable. If the URL is omitted, the title will be displayed as plain text."
msgstr ""
"Si coché, le champ URL est optionnel and soumettre un titre seul sera "
"accepté. SI l'URL est omise, le titre sera affiché en texte brut."
msgid ""
"When output, this link will have this class attribute. Multiple classes "
"should be separated by spaces."
msgstr ""
"Lors de l'affichage, le lien aura cet attribut de classe (class). Les "
"classes doivent être séparées par des espaces."
msgid "Link 'title' Attribute"
msgstr "Attribut 'title' du lien"
# Comment
msgid "Title, as plain text"
msgstr "Attribut title, en tant que texte brut"
# Empty should be adjective
msgctxt "folder display"
msgid "Empty folder"
msgstr "This folder is empty."
# Empty should be verb
msgctxt "folder action"
msgid "Empty folder"
msgstr "Make this folder empty."

View File

@@ -1,59 +0,0 @@
# French translation of Link (6.x-2.9)
# Copyright (c) 2011 by the French translation team
msgid ""
msgstr ""
"Project-Id-Version: Link (6.x-2.9)\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2011-12-31 23:39+0000\n"
"PO-Revision-Date: 2013-12-17 14:59+0100\n"
"Last-Translator: Ruben Vermeersch <ruben@rocketeer.be>\n"
"Language: fr\n"
"Language-Team: French\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"MIME-Version: 1.0\n"
"X-Generator: Poedit 1.6.2\n"
msgid "The name field must not contain characters like \" or \\"
msgstr ""
# possibility to reorder items depending on locale
#. Format of addresses
#. %1$s is the street
#. %2$s is the postal code
#. %3$s is the city
#. %4$s is the state
#. %5$s is the country
msgid ""
"%1$s\n"
"%2$s %3$s\n"
"%4$s\n"
"%5$s"
msgstr ""
# "i18"ned code
#. used in <pre> environment, so don't remove any control sequences
msgid ""
"define('some/test/module', function () {\n"
"\t'use strict';\n"
"\treturn {};\n"
"});\n"
""
msgstr ""
"define('random/test/file', function () {\n"
"\t'use strict';\n"
"\treturn {};\n"
"});\n"
""
# all one-letter escape characters
# be aware, that \a, \b, \v, \f and \r should not be used
# in i18ned messages (according to gettext tools)
# however, they should be properly parsed, anyway
msgid ""
"\a\b\t\n"
"\v\f\r"
msgstr ""
"\a\b\t\n"
"\v\f\r"

View File

@@ -1,30 +0,0 @@
# French translation of Link (6.x-2.9)
# Copyright (c) 2011 by the French translation team
#
#. extracted from test
msgid ""
msgstr ""
"Project-Id-Version: Link (6.x-2.9)\n"
"POT-Creation-Date: 2011-12-31 23:39+0000\n"
"PO-Revision-Date: 2013-12-17 14:21+0100\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Last-Translator: Ruben Vermeersch <ruben@rocketeer.be>\n"
"Language: fr\n"
"X-Generator: Poedit 1.6.2\n"
# Translator comment
#. Extracted comment
msgid "Title, as plain text"
msgstr "Attribut title, en tant que texte brut"
#
#.
#:
#, fuzzy
msgid "Empty comment"
msgstr "Empty"

View File

@@ -1,33 +0,0 @@
msgid ""
msgstr ""
"Project-Id-Version: Test\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: 2014-02-17 14:11+0100\n"
"Last-Translator: Ruben Vermeersch <ruben@rocketeer.be>\n"
"Language-Team: \n"
"Language: nl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Poedit 1.6.4\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-POOTLE-MTIME: 1390921449.000000\n"
#: .tmp/ui/settings/views/console-modal.html
msgid "{{dataLoader.data.length}} results"
msgstr "{{dataLoader.data.length}} resultaten"
#~ msgid "Add order"
#~ msgstr "Order toevoegen"
#~ # commented obsolete item
#~ #, fuzzy
#~ msgid "Commented item"
#~ msgstr "not sure"
# commented obsolete item
#, fuzzy
#~ msgid "Second commented item"
#~ msgstr "also not sure"

View File

@@ -1,20 +0,0 @@
# French translation of Link (6.x-2.9)
# Copyright (c) 2011 by the French translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Link (6.x-2.9)\n"
"POT-Creation-Date: 2011-12-31 23:39+0000\n"
"PO-Revision-Date: 2013-12-17 14:59+0100\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Last-Translator: Ruben Vermeersch <ruben@rocketeer.be>\n"
"Language: fr\n"
"X-Generator: Poedit 1.6.2\n"
#, fuzzy
msgid "Sources"
msgstr "Source"

View File

@@ -1,27 +0,0 @@
# French translation of Link (6.x-2.9)
# Copyright (c) 2011 by the French translation team
#
## Plural-Forms by polish translation team to demonstrate multi-line ##
#
msgid ""
msgstr ""
"Project-Id-Version: Link (6.x-2.9)\n"
"POT-Creation-Date: 2011-12-31 23:39+0000\n"
"PO-Revision-Date: 2013-12-17 14:21+0100\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2;\n"
"Last-Translator: Ruben Vermeersch <ruben@rocketeer.be>\n"
"Language: fr\n"
"X-Generator: Poedit 1.6.2\n"
msgid ""
"The following placeholder tokens can be used in both paths and titles. When "
"used in a path or title, they will be replaced with the appropriate values."
msgstr ""
"Les ébauches de jetons suivantes peuvent être utilisées à la fois dans les "
"chemins et dans les titres. Lorsqu'elles sont utilisées dans un chemin ou un "
"titre, elles seront remplacées par les valeurs appropriées."

View File

@@ -1,30 +0,0 @@
# French translation of Link (6.x-2.9)
# Copyright (c) 2011 by the French translation team
#
msgid ""
msgstr ""
"Project-Id-Version: Link (6.x-2.9)\n"
"POT-Creation-Date: 2011-12-31 23:39+0000\n"
"PO-Revision-Date: 2013-12-17 14:21+0100\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Last-Translator: Ruben Vermeersch <ruben@rocketeer.be>\n"
"Language: fr\n"
"X-Generator: Poedit 1.6.2\n"
# Comment
#: .tmp/crm/controllers/map.js
msgid "Title, as plain text"
msgstr "Attribut title, en tant que texte brut"
#: a
#: b
msgid "X"
msgstr "Y"
#: standard input:12 standard input:17
msgid "Z"
msgstr "ZZ"

View File

@@ -1,30 +0,0 @@
var assert = require('assert');
var PO = require('..');
describe('Headers', function () {
var po;
before(function (done) {
PO.load(__dirname + '/fixtures/big.po', function (err, result) {
assert.equal(err, null);
po = result;
done();
});
});
it('Parses the po file', function () {
assert.notEqual(po, null);
});
it('Parses headers correctly', function () {
assert.equal(po.headers['Project-Id-Version'], 'Link (6.x-2.9)');
assert.equal(po.headers['MIME-Version'], '1.0');
assert.equal(po.headers['Plural-Forms'], 'nplurals=2; plural=(n > 1);');
});
it('Parses all headers', function () {
// There are 11 headers in the .po file, but some default headers
// are defined (nr. 12 in this case is Report-Msgid-Bugs-To).
assert.equal(Object.keys(po.headers).length, 12);
});
});

View File

@@ -1,175 +0,0 @@
var assert = require('assert');
var fs = require('fs');
var PO = require('..');
describe('Parse', function () {
it('Parses the big po file', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/big.po', 'utf8'));
assert.notEqual(po, null);
assert.equal(po.items.length, 69);
var item = po.items[0];
assert.equal(item.msgid, 'Title');
assert.equal(item.msgstr, 'Titre');
});
it('Handles multi-line strings', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/multi-line.po', 'utf8'));
assert.notEqual(po, null);
assert.equal(po.items.length, 1);
var item = po.items[0];
assert.equal(item.msgid, 'The following placeholder tokens can be used in both paths and titles. When used in a path or title, they will be replaced with the appropriate values.');
assert.equal(item.msgstr, 'Les ébauches de jetons suivantes peuvent être utilisées à la fois dans les chemins et dans les titres. Lorsqu\'elles sont utilisées dans un chemin ou un titre, elles seront remplacées par les valeurs appropriées.');
});
it('Handles multi-line headers', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/multi-line.po', 'utf8'));
assert.notEqual(po, null);
assert.equal(po.items.length, 1);
assert.equal(po.headers['Plural-Forms'], 'nplurals=3; plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;');
});
it('Handle empty comments', function (done) {
PO.load(__dirname + '/fixtures/comment.po', function (err, po) {
assert.equal(err, null);
var item = po.items[1];
assert.equal(item.msgid, 'Empty comment');
assert.equal(item.msgstr, 'Empty');
assert.deepEqual(item.comments, ['']);
assert.deepEqual(item.extractedComments, ['']);
assert.deepEqual(item.references, ['']);
done();
});
});
it('Handles translator comments', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/comment.po', 'utf8'));
assert.notEqual(po, null);
assert.equal(po.items.length, 2);
var item = po.items[0];
assert.equal(item.msgid, 'Title, as plain text');
assert.equal(item.msgstr, 'Attribut title, en tant que texte brut');
assert.deepEqual(item.comments, ['Translator comment']);
});
it('Handles extracted comments', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/comment.po', 'utf8'));
assert.notEqual(po, null);
assert.equal(po.items.length, 2);
assert.equal(po.extractedComments.length, 1);
assert.equal(po.extractedComments[0], 'extracted from test');
var item = po.items[0];
assert.equal(item.msgid, 'Title, as plain text');
assert.equal(item.msgstr, 'Attribut title, en tant que texte brut');
assert.deepEqual(item.extractedComments, ['Extracted comment']);
});
describe('Handles string references', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/reference.po', 'utf8'));
assert.notEqual(po, null);
assert.equal(po.items.length, 3);
it('in simple cases', function () {
var item = po.items[0];
assert.equal(item.msgid, 'Title, as plain text');
assert.equal(item.msgstr, 'Attribut title, en tant que texte brut');
assert.deepEqual(item.comments, ['Comment']);
assert.deepEqual(item.references, ['.tmp/crm/controllers/map.js']);
});
it('with two different references', function () {
var item = po.items[1];
assert.equal(item.msgid, 'X');
assert.equal(item.msgstr, 'Y');
assert.deepEqual(item.references, ['a', 'b']);
});
it('and does not process reference items', function () {
var item = po.items[2];
assert.equal(item.msgid, 'Z');
assert.equal(item.msgstr, 'ZZ');
assert.deepEqual(item.references, ['standard input:12 standard input:17']);
});
});
it('Parses flags', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/fuzzy.po', 'utf8'));
assert.notEqual(po, null);
assert.equal(po.items.length, 1);
var item = po.items[0];
assert.equal(item.msgid, 'Sources');
assert.equal(item.msgstr, 'Source');
assert.notEqual(item.flags, null);
assert.equal(item.flags.fuzzy, true);
});
it('Parses item context', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/big.po', 'utf8'));
var ambiguousItems = po.items.filter(function (item) {
return item.msgid === 'Empty folder';
});
assert.equal(ambiguousItems[0].msgctxt, 'folder display');
assert.equal(ambiguousItems[1].msgctxt, 'folder action');
});
it('Handles obsolete items', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/commented.po', 'utf8'));
assert.equal(po.items.length, 4);
var item = po.items[0];
assert.equal(item.obsolete, false);
assert.equal(item.msgid, '{{dataLoader.data.length}} results');
assert.equal(item.msgstr, '{{dataLoader.data.length}} resultaten');
item = po.items[1];
assert.equal(item.obsolete, true);
assert.equal(item.msgid, 'Add order');
assert.equal(item.msgstr, 'Order toevoegen');
item = po.items[2];
assert.equal(item.obsolete, true);
assert.equal(item.msgid, 'Commented item');
assert.equal(item.msgstr, 'not sure');
item = po.items[3];
assert.equal(item.obsolete, true);
assert.equal(item.msgid, 'Second commented item');
assert.equal(item.msgstr, 'also not sure');
});
describe('C-Strings', function () {
var po = PO.parse(fs.readFileSync(__dirname + '/fixtures/c-strings.po', 'utf8'));
it('should parse the c-strings.po file', function () {
assert.notEqual(po, null);
});
it('should extract strings containing " and \\ characters', function () {
var items = po.items.filter(function (item) {
return (/^The name field must not contain/).test(item.msgid);
});
assert.equal(items[0].msgid, 'The name field must not contain characters like " or \\');
});
it('should handle \\n characters', function () {
var item = po.items[1];
assert.equal(item.msgid, '%1$s\n%2$s %3$s\n%4$s\n%5$s');
});
it('should handle \\t characters', function () {
var item = po.items[2];
assert.equal(item.msgid, 'define(\'some/test/module\', function () {\n' +
'\t\'use strict\';\n' +
'\treturn {};\n' +
'});\n');
});
});
});

View File

@@ -1,163 +0,0 @@
var assert = require('assert');
var fs = require('fs');
var PO = require('..');
function assertHasLine(str, line) {
var lines = str.split('\n');
var found = false;
for (var i = 0; i < lines.length; i++) {
if (lines[i].trim() === line) {
found = true;
break;
}
}
assert(found, 'Could not find line: ' + line);
}
function assertDoesntHaveLine(str, line) {
var lines = str.split('\n');
var found = false;
for (var i = 0; i < lines.length; i++) {
if (lines[i].trim() === line) {
found = true;
break;
}
}
assert(!found, 'Shouldn\'t have line: ' + line);
}
describe('Write', function () {
it('write flags', function () {
var input = fs.readFileSync(__dirname + '/fixtures/fuzzy.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
assertHasLine(str, '#, fuzzy');
});
it('write flags only when true', function () {
var input = fs.readFileSync(__dirname + '/fixtures/fuzzy.po', 'utf8');
var po = PO.parse(input);
// Flip flag
po.items[0].flags.fuzzy = false;
var str = po.toString();
assertDoesntHaveLine(str, '#, fuzzy');
});
it('write msgid', function () {
var input = fs.readFileSync(__dirname + '/fixtures/fuzzy.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
assertHasLine(str, 'msgid "Sources"');
});
it('write msgstr', function () {
var input = fs.readFileSync(__dirname + '/fixtures/fuzzy.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
assertHasLine(str, 'msgstr "Source"');
});
it('write translator comment', function () {
var input = fs.readFileSync(__dirname + '/fixtures/comment.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
assertHasLine(str, '# Translator comment');
});
it('write extracted comment', function () {
var input = fs.readFileSync(__dirname + '/fixtures/comment.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
assertHasLine(str, '#. extracted from test');
assertHasLine(str, '#. Extracted comment');
});
it('write obsolete items', function () {
var input = fs.readFileSync(__dirname + '/fixtures/commented.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
assertHasLine(str, '#~ msgid "Add order"');
assertHasLine(str, '#~ msgstr "Order toevoegen"');
});
it('write obsolete items with comment', function () {
var input = fs.readFileSync(__dirname + '/fixtures/commented.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
//this is what msgcat tool of gettext does: don't print #~ for comments
assertHasLine(str, '# commented obsolete item');
assertHasLine(str, '#, fuzzy');
//items made obsolete by commenting every keyword with #~
assertHasLine(str, '#~ msgid "Commented item"');
assertHasLine(str, '#~ msgstr "not sure"');
assertHasLine(str, '#~ msgid "Second commented item"');
assertHasLine(str, '#~ msgstr "also not sure"');
});
describe('C-Strings', function () {
it('should escape "', function () {
var item = new PO.Item();
item.msgid = '" should be written escaped';
assertHasLine(item.toString(), 'msgid "\\" should be written escaped"');
});
it('shoudl escape \\', function () {
var item = new PO.Item();
item.msgid = '\\ should be written escaped';
assertHasLine(item.toString(), 'msgid "\\\\ should be written escaped"');
});
it('should escape \\n', function () {
var item = new PO.Item();
item.msgid = '\n should be written escaped';
assertHasLine(item.toString(), 'msgid ""');
assertHasLine(item.toString(), '"\\n"');
assertHasLine(item.toString(), '" should be written escaped"');
});
it('should write identical file after parsing a file', function () {
var input = fs.readFileSync(__dirname + '/fixtures/c-strings.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
assert.equal(str, input);
});
});
describe('msgctxt', function () {
it('should write context field to file', function () {
var input = fs.readFileSync(__dirname + '/fixtures/big.po', 'utf8');
var po = PO.parse(input);
var str = po.toString();
assertHasLine(str, 'msgctxt "folder action"');
});
it('should ignore omitted context field', function () {
var po = new PO();
var item = new PO.Item();
po.items.push(item);
assert.ok(po.toString().indexOf('msgctxt') < 0);
});
it('should write empty context field', function () {
var po = new PO();
var item = new PO.Item();
item.msgctxt = '';
po.items.push(item);
assert.ok(po.toString().indexOf('msgctxt') >= 0);
});
});
});