locize-cli 11.0.0 → 12.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.
Files changed (108) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/LICENSE +1 -1
  3. package/README.md +1 -0
  4. package/dist/cjs/add.js +90 -0
  5. package/{bin/locize → dist/cjs/cli.js} +390 -670
  6. package/dist/cjs/combineSubkeyPreprocessor.js +155 -0
  7. package/dist/cjs/convertToDesiredFormat.js +205 -0
  8. package/dist/cjs/convertToFlatFormat.js +231 -0
  9. package/dist/cjs/copyVersion.js +60 -0
  10. package/dist/cjs/createBranch.js +59 -0
  11. package/dist/cjs/deleteBranch.js +89 -0
  12. package/dist/cjs/deleteNamespace.js +37 -0
  13. package/dist/cjs/download.js +376 -0
  14. package/dist/cjs/filterNamespaces.js +13 -0
  15. package/dist/cjs/format.js +156 -0
  16. package/dist/cjs/formats.js +33 -0
  17. package/dist/cjs/get.js +66 -0
  18. package/dist/cjs/getBranches.js +37 -0
  19. package/dist/cjs/getJob.js +37 -0
  20. package/dist/cjs/getProjectStats.js +37 -0
  21. package/dist/cjs/getRemoteLanguages.js +38 -0
  22. package/dist/cjs/getRemoteNamespace.js +125 -0
  23. package/dist/cjs/index.js +37 -0
  24. package/dist/cjs/isValidUuid.js +6 -0
  25. package/dist/cjs/lngs.js +215 -0
  26. package/dist/cjs/mapLimit.js +22 -0
  27. package/dist/cjs/mergeBranch.js +80 -0
  28. package/dist/cjs/migrate.js +239 -0
  29. package/dist/cjs/missing.js +162 -0
  30. package/dist/cjs/package.json +5 -0
  31. package/{parseLocalLanguage.js → dist/cjs/parseLocalLanguage.js} +135 -142
  32. package/dist/cjs/parseLocalLanguages.js +18 -0
  33. package/dist/cjs/parseLocalReference.js +11 -0
  34. package/dist/cjs/publishVersion.js +42 -0
  35. package/dist/cjs/removeUndefinedFromArrays.js +19 -0
  36. package/dist/cjs/removeVersion.js +42 -0
  37. package/dist/cjs/request.js +66 -0
  38. package/dist/cjs/shouldUnflatten.js +21 -0
  39. package/dist/cjs/sortFlatResources.js +13 -0
  40. package/dist/cjs/sync.js +772 -0
  41. package/dist/cjs/unflatten.js +81 -0
  42. package/dist/esm/add.js +88 -0
  43. package/dist/esm/cli.js +1020 -0
  44. package/{combineSubkeyPreprocessor.js → dist/esm/combineSubkeyPreprocessor.js} +70 -73
  45. package/dist/esm/convertToDesiredFormat.js +203 -0
  46. package/dist/esm/convertToFlatFormat.js +229 -0
  47. package/dist/esm/copyVersion.js +58 -0
  48. package/dist/esm/createBranch.js +57 -0
  49. package/dist/esm/deleteBranch.js +87 -0
  50. package/dist/esm/deleteNamespace.js +35 -0
  51. package/dist/esm/download.js +374 -0
  52. package/{filterNamespaces.js → dist/esm/filterNamespaces.js} +4 -4
  53. package/dist/esm/format.js +154 -0
  54. package/{formats.js → dist/esm/formats.js} +7 -11
  55. package/dist/esm/get.js +64 -0
  56. package/dist/esm/getBranches.js +35 -0
  57. package/dist/esm/getJob.js +35 -0
  58. package/dist/esm/getProjectStats.js +35 -0
  59. package/dist/esm/getRemoteLanguages.js +36 -0
  60. package/dist/esm/getRemoteNamespace.js +123 -0
  61. package/dist/esm/index.js +16 -0
  62. package/dist/esm/isValidUuid.js +4 -0
  63. package/dist/esm/lngs.js +213 -0
  64. package/dist/esm/mapLimit.js +20 -0
  65. package/dist/esm/mergeBranch.js +78 -0
  66. package/dist/esm/migrate.js +237 -0
  67. package/dist/esm/missing.js +160 -0
  68. package/dist/esm/parseLocalLanguage.js +194 -0
  69. package/dist/esm/parseLocalLanguages.js +16 -0
  70. package/dist/esm/parseLocalReference.js +9 -0
  71. package/dist/esm/publishVersion.js +40 -0
  72. package/{removeUndefinedFromArrays.js → dist/esm/removeUndefinedFromArrays.js} +5 -5
  73. package/dist/esm/removeVersion.js +40 -0
  74. package/dist/esm/request.js +64 -0
  75. package/{shouldUnflatten.js → dist/esm/shouldUnflatten.js} +7 -7
  76. package/dist/esm/sortFlatResources.js +11 -0
  77. package/dist/esm/sync.js +770 -0
  78. package/{unflatten.js → dist/esm/unflatten.js} +36 -34
  79. package/package.json +39 -18
  80. package/rollup.config.js +57 -0
  81. package/add.js +0 -105
  82. package/convertToDesiredFormat.js +0 -268
  83. package/convertToFlatFormat.js +0 -322
  84. package/copyVersion.js +0 -69
  85. package/createBranch.js +0 -61
  86. package/deleteBranch.js +0 -97
  87. package/deleteNamespace.js +0 -39
  88. package/download.js +0 -516
  89. package/format.js +0 -206
  90. package/get.js +0 -81
  91. package/getBranches.js +0 -40
  92. package/getJob.js +0 -40
  93. package/getProjectStats.js +0 -40
  94. package/getRemoteLanguages.js +0 -40
  95. package/getRemoteNamespace.js +0 -122
  96. package/index.js +0 -9
  97. package/isValidUuid.js +0 -2
  98. package/lngs.json +0 -211
  99. package/mergeBranch.js +0 -102
  100. package/migrate.js +0 -314
  101. package/missing.js +0 -169
  102. package/parseLocalLanguages.js +0 -22
  103. package/parseLocalReference.js +0 -10
  104. package/publishVersion.js +0 -64
  105. package/removeVersion.js +0 -64
  106. package/request.js +0 -64
  107. package/sortFlatResources.js +0 -9
  108. package/sync.js +0 -786
@@ -1,65 +1,65 @@
1
- const yaml = require('yaml')
1
+ import yaml from 'yaml';
2
2
 
3
3
  const delimiter = {
4
4
  i18next: '_',
5
5
  i18njs: '.'
6
- }
6
+ };
7
7
 
8
8
  const detectFormat = (keys) => {
9
- const i18nextMatches = keys.filter((k) => k.indexOf(delimiter.i18next) > 0).length
10
- const i18njsMatches = keys.filter((k) => k.indexOf(delimiter.i18njs) > 0).length
9
+ const i18nextMatches = keys.filter((k) => k.indexOf(delimiter.i18next) > 0).length;
10
+ const i18njsMatches = keys.filter((k) => k.indexOf(delimiter.i18njs) > 0).length;
11
11
  if (i18nextMatches > i18njsMatches) {
12
12
  return 'i18next'
13
13
  }
14
14
  if (i18nextMatches < i18njsMatches) {
15
15
  return 'i18njs'
16
16
  }
17
- }
17
+ };
18
18
 
19
19
  const getBaseKey = (delimiter) => (k) => {
20
- const parts = k.split(delimiter)
21
- parts.pop()
22
- const baseKey = parts.join(delimiter)
20
+ const parts = k.split(delimiter);
21
+ parts.pop();
22
+ const baseKey = parts.join(delimiter);
23
23
  return baseKey
24
- }
24
+ };
25
25
 
26
- const uniq = (value, index, self) => self.indexOf(value) === index
26
+ const uniq = (value, index, self) => self.indexOf(value) === index;
27
27
 
28
28
  const stringify = (o) => {
29
- let str = yaml.stringify(o)
30
- const subKeys = Object.keys(o)
29
+ let str = yaml.stringify(o);
30
+ const subKeys = Object.keys(o);
31
31
  subKeys.forEach((sk) => {
32
32
  if (isNaN(sk)) {
33
- str = str.replace(new RegExp(`^(?:${sk}: )+`, 'm'), `{${sk}}: `)
33
+ str = str.replace(new RegExp(`^(?:${sk}: )+`, 'm'), `{${sk}}: `);
34
34
  } else {
35
- str = str.replace(new RegExp(`^(?:'${sk}': )+`, 'm'), `{${sk}}: `)
35
+ str = str.replace(new RegExp(`^(?:'${sk}': )+`, 'm'), `{${sk}}: `);
36
36
  }
37
- })
37
+ });
38
38
  return str
39
- }
39
+ };
40
40
 
41
41
  const transformKeys = (segments, baseKeys, toMerge, deli) => {
42
42
  baseKeys.forEach((bk) => {
43
43
  const asObj = toMerge[bk].reduce((mem, k) => {
44
- const subKey = k.substring((bk + deli).length)
44
+ const subKey = k.substring((bk + deli).length);
45
45
  // special handling for i18next v3
46
46
  if (deli === delimiter.i18next && subKey === 'plural' && segments[bk]) {
47
- mem['__'] = segments[bk]
48
- delete segments[bk]
47
+ mem['__'] = segments[bk];
48
+ delete segments[bk];
49
49
  }
50
- mem[subKey] = segments[k]
50
+ mem[subKey] = segments[k];
51
51
  return mem
52
- }, {})
52
+ }, {});
53
53
  if (Object.keys(asObj).length > 0) {
54
- const value = stringify(asObj)
55
- segments[`${bk}__#locize.com/combinedSubkey`] = value
54
+ const value = stringify(asObj);
55
+ segments[`${bk}__#locize.com/combinedSubkey`] = value;
56
56
  toMerge[bk].forEach((k) => {
57
- delete segments[k]
58
- })
57
+ delete segments[k];
58
+ });
59
59
  }
60
- })
60
+ });
61
61
  return segments
62
- }
62
+ };
63
63
 
64
64
  // CLDR
65
65
  const pluralForms = [
@@ -69,87 +69,84 @@ const pluralForms = [
69
69
  'few',
70
70
  'many',
71
71
  'other'
72
- ]
72
+ ];
73
73
 
74
- const endsWithPluralForm = (k) => !!pluralForms.find((f) => k.endsWith(`.${f}`)) || !!pluralForms.find((f) => k.endsWith(`_${f}`)) || /_\d+$/.test(k) || k.endsWith('_plural')
74
+ const endsWithPluralForm = (k) => !!pluralForms.find((f) => k.endsWith(`.${f}`)) || !!pluralForms.find((f) => k.endsWith(`_${f}`)) || /_\d+$/.test(k) || k.endsWith('_plural');
75
75
 
76
76
  const prepareExport = (refRes, trgRes) => {
77
- const refLngKeys = Object.keys(refRes)
78
- const trgLngKeys = Object.keys(trgRes)
77
+ const refLngKeys = Object.keys(refRes);
78
+ const trgLngKeys = Object.keys(trgRes);
79
79
 
80
- const nonMatchInRef = refLngKeys.filter((k) => trgLngKeys.indexOf(k) < 0 && endsWithPluralForm(k))
81
- const nonMatchInTrg = trgLngKeys.filter((k) => refLngKeys.indexOf(k) < 0 && endsWithPluralForm(k))
80
+ const nonMatchInRef = refLngKeys.filter((k) => trgLngKeys.indexOf(k) < 0 && endsWithPluralForm(k));
81
+ const nonMatchInTrg = trgLngKeys.filter((k) => refLngKeys.indexOf(k) < 0 && endsWithPluralForm(k));
82
82
 
83
- const allMatches = nonMatchInRef.concat(nonMatchInTrg)
83
+ const allMatches = nonMatchInRef.concat(nonMatchInTrg);
84
84
 
85
- const format = detectFormat(allMatches)
85
+ const format = detectFormat(allMatches);
86
86
  if (!format) return { ref: refRes, trg: trgRes }
87
87
 
88
- const nonMatchBaseKeysInRef = nonMatchInRef.map(getBaseKey(delimiter[format])).filter(uniq)
89
- const nonMatchBaseKeysInTrg = nonMatchInTrg.map(getBaseKey(delimiter[format])).filter(uniq)
90
- const nonMatchBaseKeys = nonMatchBaseKeysInRef.concat(nonMatchBaseKeysInTrg).filter(uniq)
88
+ const nonMatchBaseKeysInRef = nonMatchInRef.map(getBaseKey(delimiter[format])).filter(uniq);
89
+ const nonMatchBaseKeysInTrg = nonMatchInTrg.map(getBaseKey(delimiter[format])).filter(uniq);
90
+ const nonMatchBaseKeys = nonMatchBaseKeysInRef.concat(nonMatchBaseKeysInTrg).filter(uniq);
91
91
 
92
92
  const toMergeInRef = nonMatchBaseKeys.reduce((mem, bk) => {
93
- mem[bk] = refLngKeys.filter((k) => k.indexOf(bk + delimiter[format]) === 0)
93
+ mem[bk] = refLngKeys.filter((k) => k.indexOf(bk + delimiter[format]) === 0);
94
94
  return mem
95
- }, {})
95
+ }, {});
96
96
  const toMergeInTrg = nonMatchBaseKeys.reduce((mem, bk) => {
97
- mem[bk] = trgLngKeys.filter((k) => k.indexOf(bk + delimiter[format]) === 0)
97
+ mem[bk] = trgLngKeys.filter((k) => k.indexOf(bk + delimiter[format]) === 0);
98
98
  return mem
99
- }, {})
99
+ }, {});
100
100
 
101
- let falseFlags = nonMatchBaseKeysInRef.filter((k) => toMergeInRef[k].length < 2 && (!toMergeInTrg[k] || toMergeInTrg[k].length < 2))
102
- falseFlags = falseFlags.concat(nonMatchBaseKeysInTrg.filter((k) => toMergeInTrg[k].length < 2 && (!toMergeInRef[k] || toMergeInRef[k].length < 2)))
101
+ let falseFlags = nonMatchBaseKeysInRef.filter((k) => toMergeInRef[k].length < 2 && (!toMergeInTrg[k] || toMergeInTrg[k].length < 2));
102
+ falseFlags = falseFlags.concat(nonMatchBaseKeysInTrg.filter((k) => toMergeInTrg[k].length < 2 && (!toMergeInRef[k] || toMergeInRef[k].length < 2)));
103
103
  falseFlags.forEach((k) => {
104
- delete toMergeInRef[k]
105
- delete toMergeInTrg[k]
106
- nonMatchBaseKeys.splice(nonMatchBaseKeys.indexOf(k), 1)
107
- })
104
+ delete toMergeInRef[k];
105
+ delete toMergeInTrg[k];
106
+ nonMatchBaseKeys.splice(nonMatchBaseKeys.indexOf(k), 1);
107
+ });
108
108
 
109
- const transformedRef = transformKeys(refRes, nonMatchBaseKeys, toMergeInRef, delimiter[format])
110
- const transformedTrg = transformKeys(trgRes, nonMatchBaseKeys, toMergeInTrg, delimiter[format])
109
+ const transformedRef = transformKeys(refRes, nonMatchBaseKeys, toMergeInRef, delimiter[format]);
110
+ const transformedTrg = transformKeys(trgRes, nonMatchBaseKeys, toMergeInTrg, delimiter[format]);
111
111
  return { ref: transformedRef, trg: transformedTrg }
112
- }
112
+ };
113
113
 
114
114
  // eslint-disable-next-line prefer-regex-literals
115
- const skRegex = new RegExp('^(?:{(.+)})+', 'gm')
115
+ const skRegex = new RegExp('^(?:{(.+)})+', 'gm');
116
116
  const parse = (s) => {
117
- let matchArray
117
+ let matchArray;
118
118
  while ((matchArray = skRegex.exec(s)) !== null) {
119
- const [match, sk] = matchArray
119
+ const [match, sk] = matchArray;
120
120
  if (isNaN(sk)) {
121
- s = s.replace(new RegExp(`^(?:${match}: )+`, 'm'), `${sk}: `)
121
+ s = s.replace(new RegExp(`^(?:${match}: )+`, 'm'), `${sk}: `);
122
122
  } else {
123
- const escapedMatch = match.replace('{', '\\{').replace('}', '\\}')
124
- s = s.replace(new RegExp(`^(?:${escapedMatch}: )+`, 'm'), `${sk}: `)
123
+ const escapedMatch = match.replace('{', '\\{').replace('}', '\\}');
124
+ s = s.replace(new RegExp(`^(?:${escapedMatch}: )+`, 'm'), `${sk}: `);
125
125
  }
126
126
  }
127
127
  return yaml.parse(s)
128
- }
128
+ };
129
129
 
130
130
  const prepareImport = (resources) => {
131
- const keys = Object.keys(resources)
131
+ const keys = Object.keys(resources);
132
132
  keys.forEach((k) => {
133
133
  if (k.indexOf('__#locize.com/combinedSubkey') > -1) {
134
- const baseKey = k.substring(0, k.indexOf('__#locize.com/combinedSubkey'))
134
+ const baseKey = k.substring(0, k.indexOf('__#locize.com/combinedSubkey'));
135
135
  if (resources[k]) {
136
- const parsed = parse(resources[k])
136
+ const parsed = parse(resources[k]);
137
137
  Object.keys(parsed).forEach((sk) => {
138
- const skVal = parsed[sk]
139
- resources[`${baseKey}_${sk}`] = skVal
138
+ const skVal = parsed[sk];
139
+ resources[`${baseKey}_${sk}`] = skVal;
140
140
  if (sk === '__') {
141
- resources[baseKey] = resources[`${baseKey}_${sk}`]
142
- delete resources[`${baseKey}_${sk}`]
141
+ resources[baseKey] = resources[`${baseKey}_${sk}`];
142
+ delete resources[`${baseKey}_${sk}`];
143
143
  }
144
- })
145
- delete resources[k]
144
+ });
145
+ delete resources[k];
146
146
  }
147
147
  }
148
- })
148
+ });
149
149
  return resources
150
- }
150
+ };
151
151
 
152
- module.exports = {
153
- prepareExport,
154
- prepareImport
155
- }
152
+ export { prepareExport, prepareImport };
@@ -0,0 +1,203 @@
1
+ import flatten from 'flat';
2
+ import i18next2po from 'gettext-converter/i18next2po';
3
+ import csv from 'fast-csv';
4
+ import xlsx from 'xlsx';
5
+ import yaml from 'yaml';
6
+ import js2asr from 'android-string-resource/js2asr';
7
+ import stringsFile from 'strings-file';
8
+ import createxliff from 'xliff/createxliff';
9
+ import createxliff12 from 'xliff/createxliff12';
10
+ import js2resx from 'resx/js2resx';
11
+ import js2ftl from 'fluent_conv/js2ftl';
12
+ import js2tmx from 'tmexchange/js2tmx';
13
+ import js2laravel from 'laravelphp/js2laravel';
14
+ import javaProperties from '@js.properties/properties';
15
+ import unflatten from './unflatten.js';
16
+ import getRemoteNamespace from './getRemoteNamespace.js';
17
+ import removeUndefinedFromArrays from './removeUndefinedFromArrays.js';
18
+ import shouldUnflatten from './shouldUnflatten.js';
19
+ import { prepareExport } from './combineSubkeyPreprocessor.js';
20
+
21
+ const convertToDesiredFormat = async (
22
+ opt,
23
+ namespace,
24
+ lng,
25
+ data,
26
+ lastModified
27
+ ) => {
28
+ opt.getNamespace = opt.getNamespace || getRemoteNamespace;
29
+ const isEmpty = !data || Object.keys(data).length === 0;
30
+ if (opt.format === 'json') {
31
+ try {
32
+ data = unflatten(data, true);
33
+ } catch (err) {}
34
+ return JSON.stringify(data, null, 2)
35
+ }
36
+ if (opt.format === 'nested') {
37
+ try {
38
+ data = unflatten(data);
39
+ } catch (err) {}
40
+ return JSON.stringify(data, null, 2)
41
+ }
42
+ if (opt.format === 'flat') {
43
+ return JSON.stringify(flatten(data), null, 2)
44
+ }
45
+ if (opt.format === 'po' || opt.format === 'gettext') {
46
+ const flatData = flatten(data);
47
+ const gettextOpt = {
48
+ project: 'locize',
49
+ language: lng,
50
+ potCreationDate: lastModified,
51
+ poRevisionDate: lastModified,
52
+ ctxSeparator: '_ is default but we set it to something that is never found!!!',
53
+ persistMsgIdPlural: true
54
+ };
55
+ return i18next2po(lng, flatData, gettextOpt)
56
+ }
57
+ if (opt.format === 'po_i18next' || opt.format === 'gettext_i18next') {
58
+ const flatData = flatten(data);
59
+ const compatibilityJSON = !!Object.keys(flatData).find((k) => /_(zero|one|two|few|many|other)/.test(k)) && 'v4';
60
+ const gettextOpt = {
61
+ project: 'locize',
62
+ language: lng,
63
+ potCreationDate: lastModified,
64
+ poRevisionDate: lastModified,
65
+ compatibilityJSON
66
+ };
67
+ return i18next2po(lng, flatData, gettextOpt)
68
+ }
69
+ if (opt.format === 'csv') {
70
+ const refNs = await opt.getNamespace(opt, opt.referenceLanguage, namespace);
71
+ const js2CsvData = Object.keys(flatten(data)).reduce((mem, k) => {
72
+ const value = data[k] || '';
73
+ const line = {
74
+ key: k,
75
+ [opt.referenceLanguage]: refNs[k] || '',
76
+ [lng]: value
77
+ };
78
+ mem.push(line);
79
+ return mem
80
+ }, []);
81
+ return `\ufeff${await csv.writeToString(js2CsvData, { headers: true, quoteColumns: true })}`
82
+ }
83
+ if (opt.format === 'xlsx') {
84
+ const refNs = await opt.getNamespace(opt, opt.referenceLanguage, namespace);
85
+ const js2XlsxData = Object.keys(flatten(data)).reduce((mem, k) => {
86
+ const value = data[k] || '';
87
+ const line = {
88
+ key: k,
89
+ [opt.referenceLanguage]: refNs[k] || '',
90
+ [lng]: value
91
+ };
92
+ mem.push(line);
93
+ return mem
94
+ }, []);
95
+ const worksheet = xlsx.utils.json_to_sheet(js2XlsxData);
96
+ const workbook = xlsx.utils.book_new();
97
+ let workSheetName = namespace;
98
+ if (workSheetName.length > 31) workSheetName = workSheetName.substring(0, 31);
99
+ workbook.SheetNames.push(workSheetName);
100
+ workbook.Sheets[workSheetName] = worksheet;
101
+ return xlsx.write(workbook, { type: 'buffer' })
102
+ }
103
+ if (
104
+ opt.format === 'yaml' ||
105
+ opt.format === 'yml'
106
+ ) {
107
+ if (isEmpty) return ''
108
+ return yaml.stringify(flatten(data))
109
+ }
110
+ if (
111
+ opt.format === 'yaml-nested' ||
112
+ opt.format === 'yml-nested'
113
+ ) {
114
+ if (isEmpty) return ''
115
+ return yaml.stringify(shouldUnflatten(data) ? unflatten(data) : data)
116
+ }
117
+ if (
118
+ opt.format === 'yaml-rails' ||
119
+ opt.format === 'yml-rails'
120
+ ) {
121
+ if (isEmpty) return ''
122
+ const newData = {};
123
+ newData[lng] = shouldUnflatten(data) ? unflatten(data) : data;
124
+ return yaml.stringify(removeUndefinedFromArrays(newData))
125
+ }
126
+ if (
127
+ opt.format === 'yaml-rails-ns' ||
128
+ opt.format === 'yml-rails-ns'
129
+ ) {
130
+ if (isEmpty) return ''
131
+ const newDataNs = {};
132
+ newDataNs[lng] = {};
133
+ newDataNs[lng][namespace] = shouldUnflatten(data) ? unflatten(data) : data;
134
+ return yaml.stringify(removeUndefinedFromArrays(newDataNs))
135
+ }
136
+ if (opt.format === 'android') {
137
+ return await js2asr(flatten(data))
138
+ }
139
+ if (opt.format === 'strings') {
140
+ Object.keys(data).forEach((k) => {
141
+ if (data[k] === null) delete data[k];
142
+ });
143
+ return stringsFile.compile(data)
144
+ }
145
+ if (
146
+ opt.format === 'xliff2' ||
147
+ opt.format === 'xliff12' ||
148
+ opt.format === 'xlf2' ||
149
+ opt.format === 'xlf12'
150
+ ) {
151
+ const fn =
152
+ opt.format === 'xliff12' || opt.format === 'xlf12'
153
+ ? createxliff12
154
+ : createxliff;
155
+ const refNs = await opt.getNamespace(opt, opt.referenceLanguage, namespace);
156
+ const prepared = prepareExport(refNs, flatten(data));
157
+ return await fn(opt.referenceLanguage, lng, prepared.ref, prepared.trg, namespace)
158
+ }
159
+ if (opt.format === 'resx') {
160
+ return await js2resx(flatten(data))
161
+ }
162
+ if (opt.format === 'fluent') {
163
+ Object.keys(data).forEach((k) => {
164
+ if (!data[k] || data[k] === '') delete data[k];
165
+ data[k] = data[k].replace(
166
+ new RegExp(String.fromCharCode(160), 'g'),
167
+ String.fromCharCode(32)
168
+ );
169
+ });
170
+ return js2ftl(unflatten(data))
171
+ }
172
+ if (opt.format === 'tmx') {
173
+ const refNs = await opt.getNamespace(opt, opt.referenceLanguage, namespace);
174
+ const js = flatten(data);
175
+ const js2TmxData = Object.keys(js).reduce(
176
+ (mem, k) => {
177
+ const refItem = refNs[k];
178
+ if (!refItem) return mem
179
+ const value = js[k] || '';
180
+ mem.resources[namespace][k] = {};
181
+ mem.resources[namespace][k][opt.referenceLanguage] = refItem;
182
+ mem.resources[namespace][k][lng] = value;
183
+ return mem
184
+ },
185
+ {
186
+ resources: {
187
+ [namespace]: {}
188
+ },
189
+ sourceLanguage: opt.referenceLanguage
190
+ }
191
+ );
192
+ return await js2tmx(js2TmxData)
193
+ }
194
+ if (opt.format === 'laravel') {
195
+ return await js2laravel(unflatten(data))
196
+ }
197
+ if (opt.format === 'properties') {
198
+ return javaProperties.stringifyFromProperties(data, { eol: '\n' })
199
+ }
200
+ throw new Error(`${opt.format} is not a valid format!`)
201
+ };
202
+
203
+ export { convertToDesiredFormat as default };
@@ -0,0 +1,229 @@
1
+ import po2i18next from 'gettext-converter/po2i18next';
2
+ import csv from 'fast-csv';
3
+ import xlsx from 'xlsx';
4
+ import yaml from 'yaml';
5
+ import asr2js from 'android-string-resource/asr2js';
6
+ import stringsFile from 'strings-file';
7
+ import xliff2js from 'xliff/xliff2js';
8
+ import xliff12ToJs from 'xliff/xliff12ToJs';
9
+ import targetOfjs from 'xliff/targetOfjs';
10
+ import sourceOfjs from 'xliff/sourceOfjs';
11
+ import resx2js from 'resx/resx2js';
12
+ import ftl2js from 'fluent_conv/ftl2js';
13
+ import tmx2js from 'tmexchange/tmx2js';
14
+ import laravel2js from 'laravelphp/laravel2js';
15
+ import javaProperties from '@js.properties/properties';
16
+ import xcstrings2locize from 'locize-xcstrings/xcstrings2locize';
17
+ import flatten from 'flat';
18
+ import { prepareImport } from './combineSubkeyPreprocessor.js';
19
+
20
+ const convertToFlatFormat = async (opt, data, lng) => {
21
+ if (lng && typeof lng !== 'string') lng = undefined;
22
+ if (opt.format === 'json' || opt.format === 'nested' || opt.format === 'flat') {
23
+ const dataString = data.toString().trim();
24
+ if (dataString[0] !== '{' && dataString[0] !== '[') {
25
+ throw new Error(`Not a valid json file: Content starts with "${dataString[0]}" but should start with "{"`)
26
+ }
27
+ const jsonParsed = JSON.parse(dataString);
28
+ return flatten(jsonParsed)
29
+ }
30
+ if (opt.format === 'po' || opt.format === 'gettext') {
31
+ const ret = po2i18next(data.toString(), {
32
+ persistMsgIdPlural: true,
33
+ ignoreCtx: true
34
+ });
35
+ return flatten(ret)
36
+ }
37
+ if (opt.format === 'po_i18next' || opt.format === 'gettext_i18next') {
38
+ const potxt = data.toString();
39
+ const compatibilityJSON = /msgctxt "(zero|one|two|few|many|other)"/.test(potxt) && 'v4';
40
+ const ret = po2i18next(potxt, { compatibilityJSON });
41
+ return flatten(ret)
42
+ }
43
+ if (opt.format === 'csv') {
44
+ // CRLF => LF
45
+ const text = data.toString().replace(/\r\n/g, '\n');
46
+ const rows = await csv.parseString(text, { headers: true, ignoreEmpty: true }).promise();
47
+ const result = rows.reduce((mem, entry) => {
48
+ if (entry.key && typeof entry[opt.referenceLanguage] === 'string') {
49
+ mem[entry.key] = entry[opt.referenceLanguage];
50
+ }
51
+ return mem
52
+ }, {});
53
+ return result
54
+ }
55
+ if (opt.format === 'xlsx') {
56
+ const wb = xlsx.read(data, { type: 'buffer' });
57
+ const jsonData = xlsx.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
58
+ const result = jsonData.reduce((mem, entry) => {
59
+ if (entry.key && typeof entry[opt.referenceLanguage] === 'string') {
60
+ mem[entry.key] = entry[opt.referenceLanguage];
61
+ }
62
+ return mem
63
+ }, {});
64
+ return result
65
+ }
66
+ if (
67
+ opt.format === 'yaml' ||
68
+ opt.format === 'yml'
69
+ ) {
70
+ const d = data.toString();
71
+ if (!d || d === '' || d === '\n') return {}
72
+ return flatten(yaml.parse(d))
73
+ }
74
+ if (
75
+ opt.format === 'yaml-nested' ||
76
+ opt.format === 'yml-nested'
77
+ ) {
78
+ const d = data.toString();
79
+ if (!d || d === '' || d === '\n') return {}
80
+ return flatten(yaml.parse(d))
81
+ }
82
+ if (
83
+ opt.format === 'yaml-rails' ||
84
+ opt.format === 'yml-rails'
85
+ ) {
86
+ const d = data.toString();
87
+ if (!d || d.trim() === '') return {}
88
+ const jsObj = yaml.parse(d);
89
+ return flatten(jsObj[Object.keys(jsObj)[0]])
90
+ }
91
+ if (
92
+ opt.format === 'yaml-rails-ns' ||
93
+ opt.format === 'yml-rails-ns'
94
+ ) {
95
+ const dn = data.toString();
96
+ if (!dn || dn.trim() === '') return {}
97
+ const jsObjn = yaml.parse(dn);
98
+ return flatten(jsObjn[Object.keys(jsObjn)[0]][Object.keys(jsObjn[Object.keys(jsObjn)[0]])[0]])
99
+ }
100
+ if (opt.format === 'android') {
101
+ const res = await asr2js(data.toString(), { comment: 'right' });
102
+ Object.keys(res).forEach((k) => {
103
+ if (res[k] !== 'string' && typeof res[k].comment === 'string') {
104
+ res[k] = {
105
+ value: res[k].value,
106
+ context: {
107
+ text: res[k].comment,
108
+ },
109
+ };
110
+ } else {
111
+ res[k] = { value: res[k].value || res[k] };
112
+ }
113
+ });
114
+ return res
115
+ }
116
+ if (opt.format === 'strings') {
117
+ // CRLF => LF
118
+ return stringsFile.parse(data.toString().replace(/\r\n/g, '\n'), false)
119
+ }
120
+ if (
121
+ opt.format === 'xliff2' ||
122
+ opt.format === 'xliff12' ||
123
+ opt.format === 'xlf2' ||
124
+ opt.format === 'xlf12'
125
+ ) {
126
+ const fn =
127
+ opt.format === 'xliff12' || opt.format === 'xlf12'
128
+ ? xliff12ToJs
129
+ : xliff2js;
130
+ const res = await fn(data.toString());
131
+ res.resources = res.resources || {};
132
+ const ns = Object.keys(res.resources)[0];
133
+ const orgRes = res.resources[ns] || res.resources;
134
+ function checkForPostProcessing (nsRes) {
135
+ Object.keys(nsRes).forEach((k) => {
136
+ if (orgRes[k].note && (typeof nsRes[k] === 'string' || !nsRes[k])) {
137
+ nsRes[k] = {
138
+ value: nsRes[k],
139
+ context: {
140
+ text: orgRes[k].note,
141
+ }
142
+ };
143
+ }
144
+ });
145
+ return prepareImport(nsRes)
146
+ }
147
+ if (!res.targetLanguage) {
148
+ const ret = await sourceOfjs(res);
149
+ return checkForPostProcessing(ret)
150
+ } else {
151
+ let ret = targetOfjs(res);
152
+ if (lng !== opt.referenceLanguage) return checkForPostProcessing(ret)
153
+ ret = ret || {};
154
+ const keys = Object.keys(ret);
155
+ if (keys.length === 0) return checkForPostProcessing(ret)
156
+ const allEmpty = keys.filter((k) => ret[k] !== '').length === 0;
157
+ if (!allEmpty) return checkForPostProcessing(ret)
158
+ ret = await sourceOfjs(res);
159
+ return checkForPostProcessing(ret)
160
+ }
161
+ }
162
+ if (opt.format === 'resx') {
163
+ let res = await resx2js(data.toString());
164
+ res = Object.keys(res).reduce((mem, k) => {
165
+ const value = res[k];
166
+ if (typeof value === 'string') {
167
+ mem[k] = value;
168
+ } else if (value.value) {
169
+ mem[k] = {
170
+ value: value.value,
171
+ context: value.comment ? { text: value.comment } : null,
172
+ };
173
+ }
174
+ return mem
175
+ }, {});
176
+ return res
177
+ }
178
+ if (opt.format === 'fluent') {
179
+ const fluentJS = ftl2js(
180
+ data
181
+ .toString()
182
+ .replace(
183
+ new RegExp(String.fromCharCode(160), 'g'),
184
+ String.fromCharCode(32)
185
+ )
186
+ );
187
+ const comments = {};
188
+ Object.keys(fluentJS).forEach((prop) => {
189
+ if (fluentJS[prop] && fluentJS[prop].comment) {
190
+ comments[prop] = fluentJS[prop].comment;
191
+ delete fluentJS[prop].comment;
192
+ }
193
+ });
194
+ const res = flatten(fluentJS);
195
+ if (res && comments) {
196
+ Object.keys(comments).forEach((prop) => {
197
+ res[`${prop}.val`] = {
198
+ value: res[`${prop}.val`],
199
+ context: comments[prop] ? { text: comments[prop] } : null,
200
+ };
201
+ });
202
+ }
203
+ return res
204
+ }
205
+ if (opt.format === 'tmx') {
206
+ const jsonData = await tmx2js(data.toString());
207
+ const tmxJsRes = jsonData.resources[Object.keys(jsonData.resources)[0]];
208
+ const res = {};
209
+ if (tmxJsRes) {
210
+ Object.keys(tmxJsRes).forEach((k) => {
211
+ res[k] = tmxJsRes[k][opt.referenceLanguage];
212
+ });
213
+ }
214
+ return res
215
+ }
216
+ if (opt.format === 'laravel') {
217
+ const res = await laravel2js(data.toString());
218
+ return flatten(res)
219
+ }
220
+ if (opt.format === 'properties') {
221
+ return javaProperties.parseToProperties(data.toString())
222
+ }
223
+ if (opt.format === 'xcstrings') {
224
+ return xcstrings2locize(data.toString())
225
+ }
226
+ throw new Error(`${opt.format} is not a valid format!`)
227
+ };
228
+
229
+ export { convertToFlatFormat as default };