Skip to content

Commit 3023831

Browse files
committed
Implement po compiler
1 parent b34a5af commit 3023831

File tree

11 files changed

+418
-78
lines changed

11 files changed

+418
-78
lines changed

README.md

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,7 @@
11
# Dart gettext mo/po parser
22

33
Parse and compile gettext po and mo files with dart.
4-
Port of npm package [gettext-parser](https://github.com/smhg/gettext-parser).
5-
6-
## Readiness
7-
8-
- [x] Mo parse
9-
- [ ] Mo compile
10-
- [x] Po parse
11-
- [ ] Po compile
4+
Ported [gettext-parser](https://github.com/smhg/gettext-parser) npm package to dartlang.
125

136
## Usage
147

@@ -23,27 +16,42 @@ Import library:
2316
import 'package:gettext_parser/gettext_parser.dart' as gettextParser;
2417
```
2518

26-
### Parse Mo Files:
19+
### Parse .po files:
20+
```dart
21+
Map translateTable = gettextParser.po.parse(
22+
file.readAsStringSync(),
23+
);
24+
```
25+
26+
### Parse .mo files:
2727
```dart
2828
Map translateTable = gettextParser.mo.parse(
2929
file.readAsBytesSync(),
3030
);
3131
```
3232

33-
### Parse Po Files:
33+
### Compile .po files:
3434
```dart
35-
Map translateTable = gettextParser.po.parse(
36-
file.readAsStringSync(),
35+
String data = gettextParser.po.compile(
36+
translateTable,
37+
);
38+
```
39+
40+
### Compile .mo files:
41+
```dart
42+
UInt8List data = gettextParser.mo.compile(
43+
translateTable,
3744
);
3845
```
3946

4047
## Encoding
41-
`gettext_parser` use `Encoding` interface for encoding and decoding charsets from `dart:convert` package with utf8, base64, latin1 built-in encoders. If you need other encoding you could implement `Encoding` interface by your own.
48+
`gettext_parser` use `Encoding` interface for encoding and decoding charsets from `dart:convert` package with utf8, base64, latin1 built-in encoders.
49+
If you need other encoding you could implement `Encoding` interface by your own.
4250

4351
Example:
4452
```
4553
gettextParser.mo.parse(buffer, encoding: latin1);
46-
gettextParser.po.parseRaw(buffer, encoding: latin1);
54+
gettextParser.po.parse(buffer, encoding: latin1);
4755
```
4856

4957
## Data structure of parsed mo/po files
@@ -103,7 +111,10 @@ Example
103111
}
104112
```
105113

106-
Notice that the structure has both a `headers` object and a `""` translation with the header string. When compiling the structure to a *mo* or a *po* file, the `headers` object is used to define the header. Header string in the `""` translation is just for reference (includes the original unmodified data) but will not be used when compiling. So if you need to add or alter header values, use only the `headers` object.
114+
Notice that the structure has both a `headers` object and a `""` translation with the header string.
115+
When compiling the structure to a *mo* or a *po* file, the `headers` object is used to define the header.
116+
Header string in the `""` translation is just for reference (includes the original unmodified data) but
117+
will not be used when compiling. So if you need to add or alter header values, use only the `headers` object.
107118

108119
## License
109120

lib/gettext_parser.dart

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
library mo_parser;
1+
library gettext_parser;
22

33
import 'dart:convert';
4+
import 'dart:typed_data';
45

56
import './src/mo/parser.dart';
67
import './src/mo/compiler.dart';
78
import './src/po/parser.dart';
9+
import './src/po/compiler.dart';
810

911
const mo = const _Mo();
1012
const po = const _Po();
@@ -13,15 +15,24 @@ class _Mo {
1315
const _Mo();
1416

1517
/// Parse mo file data with encoding
16-
Map parse(List<int> buffer, {Encoding encoding: utf8}) {
17-
final parser = new MoParser(buffer, encoding: encoding);
18+
Map<String, dynamic> parse(ByteData data, {Encoding encoding: utf8}) {
19+
final parser = MoParser(data, encoding: encoding);
1820
return parser.parse();
1921
}
2022

21-
/// Exposes general compiler function. Takes a translation
22-
/// Map as a parameter and returns binary MO object
23-
List<int> compile(Map table) {
24-
final compiler = new MoCompiler(table);
23+
/// Parse mo file data with encoding
24+
Map<String, dynamic> parseBytes(List<int> data, {Encoding encoding: utf8}) {
25+
final parser = MoParser(
26+
ByteData.view(Uint8List.fromList(data).buffer),
27+
encoding: encoding,
28+
);
29+
30+
return parser.parse();
31+
}
32+
33+
/// Converts [table] to a binary MO object
34+
Uint8List compile(Map table) {
35+
final compiler = MoCompiler(table);
2536
return compiler.compile();
2637
}
2738
}
@@ -30,14 +41,20 @@ class _Po {
3041
const _Po();
3142

3243
/// Parse po data file with encoding
33-
Map parseBytes(List<int> data, {Encoding encoding: utf8}) {
34-
final parser = new PoParser(encoding.decode(data));
44+
Map<String, dynamic> parseBytes(List<int> data, {Encoding encoding: utf8}) {
45+
final parser = PoParser(encoding.decode(data));
3546
return parser.parse(charset: encoding.name);
3647
}
3748

3849
/// Parse po file string
39-
Map parse(String text) {
40-
final parser = new PoParser(text);
50+
Map<String, dynamic> parse(String text) {
51+
final parser = PoParser(text);
4152
return parser.parse(charset: utf8.name);
4253
}
54+
55+
/// Converts [table] to a PO object
56+
String compile(Map table) {
57+
final compiler = PoCompiler(table);
58+
return compiler.compile();
59+
}
4360
}

lib/src/mo/compiler.dart

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,33 @@ import '../models/table.dart';
44
import '../models/translation.dart';
55
import '../models/sizeOfData.dart';
66

7-
/// Creates a MO compiler object.
7+
/// Converts table to mo file.
88
class MoCompiler {
99
Table _table;
1010
Endian _endian = Endian.little;
1111

12-
// Magic bytes for the generated binary data
12+
/// Magic bytes for the generated binary data
1313
static const _MAGIC = 0x950412de;
1414

1515
MoCompiler(Map table) {
1616
_table = Table(table);
1717
}
1818

19-
List<int> compile () {
19+
Uint8List compile() {
2020
final List<TranslationInterface> list = _generateList();
2121
final SizeOfData size = SizeOfData(list);
2222

2323
// sort by msgid
24-
list.sort((a, b) => utf8.decode(a.msgid.asUint8List()).compareTo(utf8.decode(b.msgid.asUint8List())));
24+
list.sort((a, b) => utf8
25+
.decode(a.msgid.asUint8List())
26+
.compareTo(utf8.decode(b.msgid.asUint8List())));
2527

2628
return this._build(list, size);
2729
}
2830

29-
// Generates an List of translation strings
30-
// in the form of [TranslationInterface, ...]
31-
List<TranslationInterface> _generateList () {
31+
/// Generates an List of translation strings
32+
/// in the form of [TranslationInterface, ...]
33+
List<TranslationInterface> _generateList() {
3234
List<TranslationInterface> list = [];
3335

3436
list.add(HeaderTranslation(this._table.headers));
@@ -46,7 +48,8 @@ class MoCompiler {
4648
return;
4749
}
4850

49-
String msgidPlural = this._table.translations[msgctxt][msgid]['msgid_plural'];
51+
String msgidPlural =
52+
this._table.translations[msgctxt][msgid]['msgid_plural'];
5053
String key = msgid;
5154
String value;
5255
List msgstr = this._table.translations[msgctxt][msgid]['msgstr'] ?? [];
@@ -68,7 +71,7 @@ class MoCompiler {
6871
return list;
6972
}
7073

71-
List<int> _build (List<TranslationInterface> list, SizeOfData size) {
74+
Uint8List _build(List<TranslationInterface> list, SizeOfData size) {
7275
ByteData returnBuffer = ByteData.view(Uint8List(size.total).buffer);
7376
int currentPosition = 0;
7477

@@ -85,23 +88,25 @@ class MoCompiler {
8588
returnBuffer.setUint32(12, 28, _endian);
8689

8790
// translation string table offset
88-
returnBuffer.setUint32(16, 28 + (4 + 4)*list.length, _endian);
91+
returnBuffer.setUint32(16, 28 + (4 + 4) * list.length, _endian);
8992

9093
// hash table size
9194
returnBuffer.setUint32(20, 0, _endian);
9295

9396
// hash table offset
94-
returnBuffer.setUint32(24, 28 + (4 + 4)*list.length*2, _endian);
97+
returnBuffer.setUint32(24, 28 + (4 + 4) * list.length * 2, _endian);
9598

9699
// build originals table
97-
currentPosition = 28 + 2*(4 + 4)*list.length;
100+
currentPosition = 28 + 2 * (4 + 4) * list.length;
98101
for (int i = 0, len = list.length; i < len; i++) {
99102
final Uint8List copy = list[i].msgid.asUint8List();
100103

101-
returnBuffer.buffer.asUint8List().setRange(currentPosition, currentPosition + copy.length, copy);
104+
returnBuffer.buffer
105+
.asUint8List()
106+
.setRange(currentPosition, currentPosition + copy.length, copy);
102107

103-
returnBuffer.setUint32(28 + i*8, copy.length, _endian);
104-
returnBuffer.setUint32(28 + i*8 + 4, currentPosition, _endian);
108+
returnBuffer.setUint32(28 + i * 8, copy.length, _endian);
109+
returnBuffer.setUint32(28 + i * 8 + 4, currentPosition, _endian);
105110
returnBuffer.setUint8(currentPosition + copy.length, 0x00);
106111

107112
currentPosition += copy.length + 1;
@@ -111,15 +116,19 @@ class MoCompiler {
111116
for (int i = 0, len = list.length; i < len; i++) {
112117
final Uint8List copy = list[i].msgstr.asUint8List();
113118

114-
returnBuffer.buffer.asUint8List().setRange(currentPosition, currentPosition + copy.length, copy);
119+
returnBuffer.buffer
120+
.asUint8List()
121+
.setRange(currentPosition, currentPosition + copy.length, copy);
115122

116-
returnBuffer.setUint32(28 + (4 + 4)*list.length + i*8, copy.length, _endian);
117-
returnBuffer.setUint32(28 + (4 + 4)*list.length + i*8 + 4, currentPosition, _endian);
123+
returnBuffer.setUint32(
124+
28 + (4 + 4) * list.length + i * 8, copy.length, _endian);
125+
returnBuffer.setUint32(
126+
28 + (4 + 4) * list.length + i * 8 + 4, currentPosition, _endian);
118127
returnBuffer.setUint8(currentPosition + copy.length, 0x00);
119128

120129
currentPosition += copy.length + 1;
121130
}
122131

123132
return returnBuffer.buffer.asUint8List();
124133
}
125-
}
134+
}

lib/src/mo/parser.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@ class MoParser {
2323
int _offsetTranslations;
2424

2525
// GetText revision nr, usually 0
26-
int _revision;
26+
int _revision; // ignore: unused_field
2727

2828
// Total count of translated strings
2929
int _total;
3030

31-
MoParser(List<int> fileContent, {Encoding encoding}) {
31+
MoParser(this._fileContents, {Encoding encoding}) {
3232
this.encoding = encoding ?? utf8;
33-
this._fileContents = ByteData.view(Uint8List.fromList(fileContent).buffer);
3433

3534
this._table = Table.fromCharset(charset: encoding.name);
3635
}
@@ -107,7 +106,7 @@ class MoParser {
107106
}
108107

109108
/// Parses the MO object and returns translation table
110-
Map parse() {
109+
Map<String, dynamic> parse() {
111110
if (!this._checkMagick()) {
112111
return null;
113112
}

lib/src/models/table.dart

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
class Table {
2-
String charset;
3-
String contentType;
4-
Map headers;
5-
Map translations;
2+
Map<String, String> headers = {};
3+
Map<String, Map<String, dynamic>> translations = {};
4+
String charset = "";
5+
String contentType = 'utf-8';
66

77
Table(Map table) {
8-
this.headers = table['headers'] ?? {};
9-
this.translations = table['translations'] ?? {};
8+
assert(table["headers"] is Map &&
9+
table["headers"].values.every((value) => value is String));
10+
assert(table['translations'] is Map &&
11+
table['translations'].values.every((value) => value is Map));
12+
13+
headers = Map.castFrom(table["headers"]);
14+
translations = Map.castFrom(table['translations']);
1015

1116
_handleCharset(table);
1217
}
1318

1419
Table.fromCharset({String charset = 'utf-8'}) {
1520
this.charset = charset;
16-
this.translations = {};
1721
}
1822

1923
// Handles header values, replaces or adds (if needed) a charset property
2024
void _handleCharset(Map table) {
21-
final List<String> parts = (headers['content-type'] ?? 'text/plain').split(';');
25+
final List<String> parts =
26+
(headers['content-type'] ?? 'text/plain').split(';');
2227
final String contentType = parts.first;
2328
parts.removeAt(0);
2429
// Support only utf-8 encoding
@@ -82,4 +87,4 @@ class Table {
8287
'translations': this.translations,
8388
};
8489
}
85-
}
90+
}

0 commit comments

Comments
 (0)