forked from akameco/extract-react-intl-messages
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
148 lines (120 loc) · 4.33 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
'use strict'
const path = require('path')
const fs = require('fs')
const mkdirp = require('mkdirp')
const pick = require('lodash.pick')
const yaml = require('js-yaml')
const pify = require('pify')
const { flatten, unflatten } = require('flat')
const loadJsonFile = require('load-json-file')
const writeJsonFile = require('write-json-file')
const extractReactIntl = require('extract-react-intl')
const sortKeys = require('sort-keys')
const writeJson = (outputPath, obj) => {
return writeJsonFile(`${outputPath}.json`, obj, { indent: 2 })
}
const writeYaml = (outputPath, obj) => {
return pify(fs.writeFile)(`${outputPath}.yml`, yaml.safeDump(obj), 'utf8')
}
const isJson = ext => ext === 'json'
function loadLocaleFiles(locales, buildDir, ext, delimiter) {
const oldLocaleMaps = {}
try {
mkdirp.sync(buildDir)
} catch (error) {}
for (const locale of locales) {
const file = path.resolve(buildDir, `${locale}.${ext}`)
// Initialize json file
try {
const output = isJson(ext) ? JSON.stringify({}) : yaml.safeDump({})
fs.writeFileSync(file, output, { flag: 'wx' })
} catch (error) {
if (error.code !== 'EEXIST') {
throw error
}
}
let messages = isJson(ext)
? loadJsonFile.sync(file)
: yaml.safeLoad(fs.readFileSync(file, 'utf8'), { json: true })
messages = flatten(messages, { delimiter })
oldLocaleMaps[locale] = {}
for (const messageKey of Object.keys(messages)) {
const message = messages[messageKey]
if (message && typeof message === 'string' && message !== '') {
oldLocaleMaps[locale][messageKey] = messages[messageKey]
}
}
}
return oldLocaleMaps
}
module.exports = async (locales, pattern, buildDir, opts) => {
if (!Array.isArray(locales)) {
throw new TypeError(`Expected a Array, got ${typeof locales}`)
}
if (typeof pattern !== 'string') {
throw new TypeError(`Expected a string, got ${typeof pattern}`)
}
if (typeof buildDir !== 'string') {
throw new TypeError(`Expected a string, got ${typeof buildDir}`)
}
const jsonOpts = { format: 'json', flat: true }
const yamlOpts = { format: 'yaml', flat: false }
const defaultOpts =
opts && opts.format && !isJson(opts.format) ? yamlOpts : jsonOpts
opts = { defaultLocale: 'en', ...defaultOpts, ...opts }
const ext = isJson(opts.format) ? 'json' : 'yml'
const { defaultLocale, moduleName, babelConfig, validateOnly } = opts
const delimiter = opts.delimiter ? opts.delimiter : '.'
const oldLocaleMaps = loadLocaleFiles(locales, buildDir, ext, delimiter)
const extractorOptions = { defaultLocale }
if (moduleName) {
extractorOptions.moduleSourceName = moduleName
}
if (babelConfig) {
extractorOptions.babelConfig = babelConfig
}
const newLocaleMaps = await extractReactIntl(
locales,
pattern,
extractorOptions
)
if (validateOnly) {
locales.forEach(locale => {
const newLocaleMessageIds = Object.keys(newLocaleMaps[locale])
newLocaleMessageIds.sort()
const oldLocaleMessageIds = Object.keys(oldLocaleMaps[locale])
oldLocaleMessageIds.sort()
if (
newLocaleMessageIds.length !== oldLocaleMessageIds.length ||
!newLocaleMessageIds.every(
(_, index) =>
newLocaleMessageIds[index] === oldLocaleMessageIds[index]
)
) {
const invalidMessageIdsError = new Error(
'Message IDs in message files are not up to date with extracted IDs'
)
invalidMessageIdsError.code = 'EMSGID'
throw invalidMessageIdsError
}
})
return Promise.resolve()
}
return Promise.all(
locales.map(locale => {
// If the default locale, overwrite the origin file
let localeMap =
locale === defaultLocale
? // Create a clone so we can use only current valid messages below
{ ...oldLocaleMaps[locale], ...newLocaleMaps[locale] }
: { ...newLocaleMaps[locale], ...oldLocaleMaps[locale] }
// Only keep existing keys
localeMap = pick(localeMap, Object.keys(newLocaleMaps[locale]))
const formattedLocaleMap = opts.flat
? sortKeys(localeMap, { deep: true })
: unflatten(sortKeys(localeMap), { delimiter, object: true })
const fn = isJson(opts.format) ? writeJson : writeYaml
return fn(path.resolve(buildDir, locale), formattedLocaleMap)
})
)
}