@l10nmonster/helpers-java 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -0
- package/filter.js +56 -0
- package/index.js +51 -0
- package/package.json +17 -0
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# L10n Monster Java Helpers
|
|
2
|
+
|
|
3
|
+
|Module|Export|Description|
|
|
4
|
+
|---|---|---|
|
|
5
|
+
|`helpers-java`|`escapesDecoder`|Decoder for escaped chars like `\n` and `\u00a0`.|
|
|
6
|
+
|`helpers-java`|`MFQuotesDecoder`|Decoder for dealing with quotes in MessageFormat strings.|
|
|
7
|
+
|`helpers-java`|`escapesEncoder`|Encoder for escaped chars like `\n`.|
|
|
8
|
+
|`helpers-java`|`MFQuotesEncoder`|Encoder for dealing with quotes in MessageFormat strings.|
|
|
9
|
+
|
|
10
|
+
### Java Properties Filter
|
|
11
|
+
|
|
12
|
+
```js
|
|
13
|
+
this.resourceFilter = new filters.JavaPropertiesFilter();
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
A filter for properties files used as defined by the Java resource bundle specification.
|
|
17
|
+
|
|
18
|
+
* [TODO] it needs an option to make it stricter to deal with technically invalid files.
|
package/filter.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const { parseToEntries, stringifyFromEntries } = require('@js.properties/properties');
|
|
2
|
+
|
|
3
|
+
module.exports = class JavaPropertiesFilter {
|
|
4
|
+
async parseResource({ resource }) {
|
|
5
|
+
const parsedResource = parseToEntries(resource, { sep: true, eol: true, all: true, original: true, location: true });
|
|
6
|
+
const segments = [];
|
|
7
|
+
let previousComments = [];
|
|
8
|
+
for (const e of parsedResource) {
|
|
9
|
+
if (e.key && e.sep.trim() === '=') {
|
|
10
|
+
const location = {startLine: e.location.start.line, endLine: e.location.end.line}
|
|
11
|
+
const seg = {
|
|
12
|
+
sid: e.key,
|
|
13
|
+
str: e.element,
|
|
14
|
+
location
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
if (previousComments.length > 0) {
|
|
18
|
+
const notes = previousComments.join('\n');
|
|
19
|
+
if (notes.indexOf('DO_NOT_TRANSLATE') === -1) {
|
|
20
|
+
segments.push({
|
|
21
|
+
...seg,
|
|
22
|
+
notes,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
previousComments = [];
|
|
26
|
+
} else {
|
|
27
|
+
segments.push(seg);
|
|
28
|
+
}
|
|
29
|
+
} else {
|
|
30
|
+
e.original.trim().length > 0 && previousComments.push(e.original);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
segments,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async translateResource({ resource, translator }) {
|
|
39
|
+
const parsedResource = parseToEntries(resource, { sep: true, eol: true, all: true, original: true });
|
|
40
|
+
const translatedEntries = [];
|
|
41
|
+
for (const entry of parsedResource) {
|
|
42
|
+
if (entry.key) {
|
|
43
|
+
const translation = await translator(entry.key, entry.element);
|
|
44
|
+
if (translation !== undefined) {
|
|
45
|
+
// eslint-disable-next-line no-unused-vars
|
|
46
|
+
const { original, element, ...rest } = entry;
|
|
47
|
+
translatedEntries.push({
|
|
48
|
+
...rest,
|
|
49
|
+
element: translation,
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return stringifyFromEntries(translatedEntries);
|
|
55
|
+
}
|
|
56
|
+
}
|
package/index.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const { regex } = require('@l10nmonster/helpers');
|
|
2
|
+
|
|
3
|
+
exports.PropertiesFilter = require('./filter');
|
|
4
|
+
|
|
5
|
+
const javaControlCharsToDecode = {
|
|
6
|
+
t: '\t',
|
|
7
|
+
b: '\b',
|
|
8
|
+
n: '\n',
|
|
9
|
+
r: '\r',
|
|
10
|
+
f: '\f',
|
|
11
|
+
};
|
|
12
|
+
exports.escapesDecoder = regex.decoderMaker(
|
|
13
|
+
'javaEscapesDecoder',
|
|
14
|
+
/(?<node>\\(?<escapedChar>['"\\])|\\(?<escapedControl>[tbnrf])|\\u(?<codePoint>[0-9A-Za-z]{4}))/g,
|
|
15
|
+
(groups) => (groups.escapedChar ??
|
|
16
|
+
(groups.escapedControl ?
|
|
17
|
+
(javaControlCharsToDecode[groups.escapedControl] ?? `\\${groups.escapedControl}`) :
|
|
18
|
+
String.fromCharCode(parseInt(groups.codePoint, 16))
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
// TODO: do we need to escape also those escapedChar that we decoded?
|
|
24
|
+
exports.escapesEncoder = regex.encoderMaker(
|
|
25
|
+
'javaEscapesEncoder',
|
|
26
|
+
// eslint-disable-next-line prefer-named-capture-group
|
|
27
|
+
/(\t)|(\n)|(\r)|(\f)|(\u00a0)/g,
|
|
28
|
+
{
|
|
29
|
+
'\t': '\\t',
|
|
30
|
+
'\n': '\\n',
|
|
31
|
+
'\r': '\\r',
|
|
32
|
+
'\f': '\\f',
|
|
33
|
+
'\u00a0': '\\u00a0',
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
exports.MFQuotesDecoder = regex.decoderMaker(
|
|
38
|
+
'javaMFQuotesDecoder',
|
|
39
|
+
/(?:(?<quote>')'|(?:'(?<quoted>[^']+)'))/g,
|
|
40
|
+
groups => groups.quote ?? groups.quoted
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// need to be smart about detecting whether MessageFormat was used or not based on presence of {vars}
|
|
44
|
+
exports.MFQuotesEncoder = regex.encoderMaker(
|
|
45
|
+
'javaMFQuotesEncoder',
|
|
46
|
+
// eslint-disable-next-line prefer-named-capture-group
|
|
47
|
+
/(')/g,
|
|
48
|
+
{
|
|
49
|
+
"'": "''",
|
|
50
|
+
}
|
|
51
|
+
);
|
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@l10nmonster/helpers-java",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Helpers to deal with Java file formats",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"author": "Diego Lagunas",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@js.properties/properties": "^0.5.4"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"@l10nmonster/helpers": "^1"
|
|
16
|
+
}
|
|
17
|
+
}
|