@@ -2,11 +2,30 @@ import encoding from 'encoding';
22import { HEADERS , formatCharset , generateHeader , compareMsgid } from './shared.js' ;
33import contentType from 'content-type' ;
44
5+ /**
6+ * @typedef {import('node:stream').Transform } Transform
7+ * @typedef {import('./types.js').GetTextTranslation } GetTextTranslation
8+ * @typedef {import('./types.js').GetTextTranslations } GetTextTranslations
9+ * @typedef {import('./types.js').Translations } Translations
10+ * @typedef {import('./types.js').WriteFunc } WriteFunc
11+ */
12+
13+ /**
14+ * @typedef {Object } Size Data about the size of the compiled MO object.
15+ * @property {number } msgid The size of the msgid section.
16+ * @property {number } msgstr The size of the msgstr section.
17+ * @property {number } total The total size of the compiled MO object.
18+ */
19+
20+ /**
21+ * @typedef {{ msgid: Buffer, msgstr: Buffer } } TranslationBuffers A translation object partially parsed.
22+ */
23+
524/**
625 * Exposes general compiler function. Takes a translation
726 * object as a parameter and returns binary MO object
827 *
9- * @param {import('./index.d.ts'). GetTextTranslations } table Translation object
28+ * @param {GetTextTranslations } table Translation object
1029 * @return {Buffer } Compiled binary MO object
1130 */
1231export default function ( table ) {
@@ -16,66 +35,85 @@ export default function (table) {
1635}
1736
1837/**
19- * Creates a MO compiler object.
20- *
21- * @constructor
22- * @param {import('./index.d.ts').GetTextTranslations } table Translation table as defined in the README
23- * @return {import('./index.d.ts').Compiler } Compiler
38+ * Prepare the header object to be compatible with MO compiler
39+ * @param {Record<string, string> } headers the headers
40+ * @return {Record<string, string> } The prepared header
2441 */
25- function Compiler ( table = { } ) {
26- this . _table = table ;
27-
28- let { headers = { } , translations = { } } = this . _table ;
29-
30- headers = Object . keys ( headers ) . reduce ( ( result , key ) => {
42+ function prepareMoHeaders ( headers ) {
43+ return Object . keys ( headers ) . reduce ( ( result , key ) => {
3144 const lowerKey = key . toLowerCase ( ) ;
3245
3346 if ( HEADERS . has ( lowerKey ) ) {
3447 // POT-Creation-Date is removed in MO (see https://savannah.gnu.org/bugs/?49654)
3548 if ( lowerKey !== 'pot-creation-date' ) {
36- result [ HEADERS . get ( lowerKey ) ] = headers [ key ] ;
49+ const value = HEADERS . get ( lowerKey ) ;
50+ if ( value ) {
51+ result [ value ] = headers [ key ] ;
52+ }
3753 }
3854 } else {
3955 result [ key ] = headers [ key ] ;
4056 }
4157
4258 return result ;
43- } , { } ) ;
59+ } , /** @type {Record<string, string> } */ ( { } ) ) ;
60+ }
4461
45- // filter out empty translations
46- translations = Object . keys ( translations ) . reduce ( ( result , msgctxt ) => {
62+ /**
63+ * Prepare the translation object to be compatible with MO compiler
64+ * @param {Translations } translations
65+ * @return {Translations }
66+ */
67+ function prepareTranslations ( translations ) {
68+ return Object . keys ( translations ) . reduce ( ( result , msgctxt ) => {
4769 const context = translations [ msgctxt ] ;
4870 const msgs = Object . keys ( context ) . reduce ( ( result , msgid ) => {
49- const hasTranslation = context [ msgid ] . msgstr . some ( item => ! ! item . length ) ;
71+ const TranslationMsgstr = context [ msgid ] . msgstr ;
72+ const hasTranslation = TranslationMsgstr . some ( item => ! ! item . length ) ;
5073
5174 if ( hasTranslation ) {
5275 result [ msgid ] = context [ msgid ] ;
5376 }
5477
5578 return result ;
56- } , { } ) ;
79+ } , /** @type { Record<string, GetTextTranslation> } */ ( { } ) ) ;
5780
5881 if ( Object . keys ( msgs ) . length ) {
5982 result [ msgctxt ] = msgs ;
6083 }
6184
6285 return result ;
63- } , { } ) ;
86+ } , /** @type {Translations } */ ( { } ) ) ;
87+ }
6488
65- this . _table . translations = translations ;
66- this . _table . headers = headers ;
89+ /**
90+ * Creates a MO compiler object.
91+ * @this {Compiler & Transform}
92+ *
93+ * @param {GetTextTranslations } [table] Translation table as defined in the README
94+ */
95+ function Compiler ( table ) {
96+ /** @type {GetTextTranslations } _table The translation table */
97+ this . _table = {
98+ charset : undefined ,
99+ translations : prepareTranslations ( table ?. translations ?? { } ) ,
100+ headers : prepareMoHeaders ( table ?. headers ?? { } )
101+ } ;
67102
68103 this . _translations = [ ] ;
69-
104+ /**
105+ * @type {WriteFunc }
106+ */
70107 this . _writeFunc = 'writeUInt32LE' ;
71108
72109 this . _handleCharset ( ) ;
73- }
74110
75- /**
76- * Magic bytes for the generated binary data
77- */
78- Compiler . prototype . MAGIC = 0x950412de ;
111+ /**
112+ * Magic bytes for the generated binary data
113+ * @type {number } MAGIC file header magic value of mo file
114+ */
115+ this . MAGIC = 0x950412de ;
116+ }
79117
80118/**
81119 * Handles header values, replaces or adds (if needed) a charset property
@@ -96,17 +134,19 @@ Compiler.prototype._handleCharset = function () {
96134
97135/**
98136 * Generates an array of translation strings
99- * in the form of [{msgid:... , msgstr:...}]
137+ * in the form of [{msgid:..., msgstr: ...}]
100138 *
101- * @return {Array } Translation strings array
102139 */
103140Compiler . prototype . _generateList = function ( ) {
141+ /** @type {TranslationBuffers[] } */
104142 const list = [ ] ;
105143
106- list . push ( {
107- msgid : Buffer . alloc ( 0 ) ,
108- msgstr : encoding . convert ( generateHeader ( this . _table . headers ) , this . _table . charset )
109- } ) ;
144+ if ( 'headers' in this . _table ) {
145+ list . push ( {
146+ msgid : Buffer . alloc ( 0 ) ,
147+ msgstr : encoding . convert ( generateHeader ( this . _table . headers ) , this . _table . charset )
148+ } ) ;
149+ }
110150
111151 Object . keys ( this . _table . translations ) . forEach ( msgctxt => {
112152 if ( typeof this . _table . translations [ msgctxt ] !== 'object' ) {
@@ -133,7 +173,7 @@ Compiler.prototype._generateList = function () {
133173 key += '\u0000' + msgidPlural ;
134174 }
135175
136- const value = [ ] . concat ( this . _table . translations [ msgctxt ] [ msgid ] . msgstr || [ ] ) . join ( '\u0000' ) ;
176+ const value = /** @type { string[] } */ ( [ ] ) . concat ( this . _table . translations [ msgctxt ] [ msgid ] . msgstr ?? [ ] ) . join ( '\u0000' ) ;
137177
138178 list . push ( {
139179 msgid : encoding . convert ( key , this . _table . charset ) ,
@@ -148,20 +188,19 @@ Compiler.prototype._generateList = function () {
148188/**
149189 * Calculate buffer size for the final binary object
150190 *
151- * @param {import('./index.d.ts').GetTextTranslations } list An array of translation strings from _generateList
152- * @return {Object } Size data of {msgid, msgstr, total}
191+ * @param {TranslationBuffers[] } list An array of translation strings from _generateList
192+ * @return {Size } Size data of {msgid, msgstr, total}
153193 */
154194Compiler . prototype . _calculateSize = function ( list ) {
155195 let msgidLength = 0 ;
156196 let msgstrLength = 0 ;
157- let totalLength = 0 ;
158197
159198 list . forEach ( translation => {
160199 msgidLength += translation . msgid . length + 1 ; // + extra 0x00
161200 msgstrLength += translation . msgstr . length + 1 ; // + extra 0x00
162201 } ) ;
163202
164- totalLength = 4 + // magic number
203+ const totalLength = 4 + // magic number
165204 4 + // revision
166205 4 + // string count
167206 4 + // original string table offset
@@ -183,9 +222,9 @@ Compiler.prototype._calculateSize = function (list) {
183222/**
184223 * Generates the binary MO object from the translation list
185224 *
186- * @param {import('./index.d.ts').GetTextTranslations } list translation list
187- * @param {Object } size Byte size information
188- * @return {Buffer } Compiled MO object
225+ * @param {TranslationBuffers[] } list translation list
226+ * @param {Size } size Byte size information
227+ * @return {Buffer } Compiled MO object
189228 */
190229Compiler . prototype . _build = function ( list , size ) {
191230 const returnBuffer = Buffer . alloc ( size . total ) ;
@@ -214,21 +253,23 @@ Compiler.prototype._build = function (list, size) {
214253 // hash table offset
215254 returnBuffer [ this . _writeFunc ] ( 28 + ( 4 + 4 ) * list . length * 2 , 24 ) ;
216255
217- // build originals table
256+ // Build original table
218257 curPosition = 28 + 2 * ( 4 + 4 ) * list . length ;
219258 for ( i = 0 , len = list . length ; i < len ; i ++ ) {
220- list [ i ] . msgid . copy ( returnBuffer , curPosition ) ;
221- returnBuffer [ this . _writeFunc ] ( list [ i ] . msgid . length , 28 + i * 8 ) ;
222- returnBuffer [ this . _writeFunc ] ( curPosition , 28 + i * 8 + 4 ) ;
259+ const msgidLength = /** @type {Buffer } */ ( /** @type {unknown } */ ( list [ i ] . msgid ) ) ;
260+ msgidLength . copy ( returnBuffer , curPosition ) ;
261+ returnBuffer . writeUInt32LE ( list [ i ] . msgid . length , 28 + i * 8 ) ;
262+ returnBuffer . writeUInt32LE ( curPosition , 28 + i * 8 + 4 ) ;
223263 returnBuffer [ curPosition + list [ i ] . msgid . length ] = 0x00 ;
224264 curPosition += list [ i ] . msgid . length + 1 ;
225265 }
226266
227- // build translations table
267+ // build translation table
228268 for ( i = 0 , len = list . length ; i < len ; i ++ ) {
229- list [ i ] . msgstr . copy ( returnBuffer , curPosition ) ;
230- returnBuffer [ this . _writeFunc ] ( list [ i ] . msgstr . length , 28 + ( 4 + 4 ) * list . length + i * 8 ) ;
231- returnBuffer [ this . _writeFunc ] ( curPosition , 28 + ( 4 + 4 ) * list . length + i * 8 + 4 ) ;
269+ const msgstrLength = /** @type {Buffer } */ ( /** @type {unknown } */ ( list [ i ] . msgstr ) ) ;
270+ msgstrLength . copy ( returnBuffer , curPosition ) ;
271+ returnBuffer . writeUInt32LE ( list [ i ] . msgstr . length , 28 + ( 4 + 4 ) * list . length + i * 8 ) ;
272+ returnBuffer . writeUInt32LE ( curPosition , 28 + ( 4 + 4 ) * list . length + i * 8 + 4 ) ;
232273 returnBuffer [ curPosition + list [ i ] . msgstr . length ] = 0x00 ;
233274 curPosition += list [ i ] . msgstr . length + 1 ;
234275 }
@@ -237,8 +278,9 @@ Compiler.prototype._build = function (list, size) {
237278} ;
238279
239280/**
240- * Compiles translation object into a binary MO object
281+ * Compiles a translation object into a binary MO object
241282 *
283+ * @interface
242284 * @return {Buffer } Compiled MO object
243285 */
244286Compiler . prototype . compile = function ( ) {
0 commit comments