@formatjs/cli-lib 5.1.8 → 5.1.11

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 (80) hide show
  1. package/index.d.ts +8 -0
  2. package/index.d.ts.map +1 -0
  3. package/index.js +12 -0
  4. package/main.d.ts +2 -0
  5. package/main.d.ts.map +1 -0
  6. package/main.js +3 -0
  7. package/package.json +1 -1
  8. package/src/cli.d.ts +3 -0
  9. package/src/cli.d.ts.map +1 -0
  10. package/src/cli.js +165 -0
  11. package/src/compile.d.ts +48 -0
  12. package/src/compile.d.ts.map +1 -0
  13. package/src/compile.js +97 -0
  14. package/src/compile_folder.d.ts +3 -0
  15. package/src/compile_folder.d.ts.map +1 -0
  16. package/src/compile_folder.js +11 -0
  17. package/src/console_utils.d.ts +10 -0
  18. package/src/console_utils.d.ts.map +1 -0
  19. package/src/console_utils.js +76 -0
  20. package/src/extract.d.ts +75 -0
  21. package/src/extract.d.ts.map +1 -0
  22. package/src/extract.js +177 -0
  23. package/src/formatters/crowdin.d.ts +8 -0
  24. package/src/formatters/crowdin.d.ts.map +1 -0
  25. package/src/formatters/crowdin.js +27 -0
  26. package/src/formatters/default.d.ts +6 -0
  27. package/src/formatters/default.d.ts.map +1 -0
  28. package/src/formatters/default.js +13 -0
  29. package/src/formatters/index.d.ts +9 -0
  30. package/src/formatters/index.d.ts.map +1 -0
  31. package/src/formatters/index.js +42 -0
  32. package/src/formatters/lokalise.d.ts +10 -0
  33. package/src/formatters/lokalise.d.ts.map +1 -0
  34. package/src/formatters/lokalise.js +24 -0
  35. package/src/formatters/simple.d.ts +5 -0
  36. package/src/formatters/simple.d.ts.map +1 -0
  37. package/src/formatters/simple.js +12 -0
  38. package/src/formatters/smartling.d.ts +24 -0
  39. package/src/formatters/smartling.d.ts.map +1 -0
  40. package/src/formatters/smartling.js +50 -0
  41. package/src/formatters/transifex.d.ts +10 -0
  42. package/src/formatters/transifex.d.ts.map +1 -0
  43. package/src/formatters/transifex.js +24 -0
  44. package/src/parse_script.d.ts +8 -0
  45. package/src/parse_script.d.ts.map +1 -0
  46. package/src/parse_script.js +51 -0
  47. package/src/pseudo_locale.d.ts +7 -0
  48. package/src/pseudo_locale.d.ts.map +1 -0
  49. package/src/pseudo_locale.js +100 -0
  50. package/src/vue_extractor.d.ts +3 -0
  51. package/src/vue_extractor.d.ts.map +1 -0
  52. package/src/vue_extractor.js +62 -0
  53. package/BUILD +0 -118
  54. package/CHANGELOG.md +0 -1147
  55. package/index.ts +0 -7
  56. package/main.ts +0 -5
  57. package/src/cli.ts +0 -240
  58. package/src/compile.ts +0 -141
  59. package/src/compile_folder.ts +0 -15
  60. package/src/console_utils.ts +0 -78
  61. package/src/extract.ts +0 -273
  62. package/src/formatters/crowdin.ts +0 -34
  63. package/src/formatters/default.ts +0 -19
  64. package/src/formatters/index.ts +0 -46
  65. package/src/formatters/lokalise.ts +0 -33
  66. package/src/formatters/simple.ts +0 -12
  67. package/src/formatters/smartling.ts +0 -73
  68. package/src/formatters/transifex.ts +0 -33
  69. package/src/parse_script.ts +0 -49
  70. package/src/pseudo_locale.ts +0 -113
  71. package/src/vue_extractor.ts +0 -96
  72. package/tests/unit/__snapshots__/pseudo_locale.test.ts.snap +0 -24
  73. package/tests/unit/__snapshots__/unit.test.ts.snap +0 -42
  74. package/tests/unit/__snapshots__/vue_extractor.test.ts.snap +0 -36
  75. package/tests/unit/fixtures/bind.vue +0 -46
  76. package/tests/unit/fixtures/comp.vue +0 -17
  77. package/tests/unit/pseudo_locale.test.ts +0 -7
  78. package/tests/unit/unit.test.ts +0 -44
  79. package/tests/unit/vue_extractor.test.ts +0 -38
  80. package/tsconfig.json +0 -5
package/src/extract.ts DELETED
@@ -1,273 +0,0 @@
1
- import {warn, getStdinAsString, debug, writeStdout} from './console_utils'
2
- import {readFile, outputFile} from 'fs-extra'
3
- import {
4
- interpolateName,
5
- Opts,
6
- MessageDescriptor,
7
- } from '@formatjs/ts-transformer'
8
-
9
- import {resolveBuiltinFormatter, Formatter} from './formatters'
10
- import stringify from 'json-stable-stringify'
11
- import {parseScript} from './parse_script'
12
- import {printAST} from '@formatjs/icu-messageformat-parser/printer'
13
- import {hoistSelectors} from '@formatjs/icu-messageformat-parser/manipulator'
14
- import {parse} from '@formatjs/icu-messageformat-parser'
15
- export interface ExtractionResult<M = Record<string, string>> {
16
- /**
17
- * List of extracted messages
18
- */
19
- messages: MessageDescriptor[]
20
- /**
21
- * Metadata extracted w/ `pragma`
22
- */
23
- meta?: M
24
- }
25
-
26
- export interface ExtractedMessageDescriptor extends MessageDescriptor {
27
- /**
28
- * Line number
29
- */
30
- line?: number
31
- /**
32
- * Column number
33
- */
34
- col?: number
35
- /**
36
- * Metadata extracted from pragma
37
- */
38
- meta?: Record<string, string>
39
- }
40
-
41
- export type ExtractCLIOptions = Omit<
42
- ExtractOpts,
43
- 'overrideIdFn' | 'onMsgExtracted' | 'onMetaExtracted'
44
- > & {
45
- /**
46
- * Output File
47
- */
48
- outFile?: string
49
- /**
50
- * Ignore file glob pattern
51
- */
52
- ignore?: string[]
53
- }
54
-
55
- export type ExtractOpts = Opts & {
56
- /**
57
- * Whether to throw an error if we had any issues with
58
- * 1 of the source files
59
- */
60
- throws?: boolean
61
- /**
62
- * Message ID interpolation pattern
63
- */
64
- idInterpolationPattern?: string
65
- /**
66
- * Whether we read from stdin instead of a file
67
- */
68
- readFromStdin?: boolean
69
- /**
70
- * Path to a formatter file that controls the shape of JSON file from `outFile`.
71
- */
72
- format?: string | Formatter
73
- /**
74
- * Whether to hoist selectors & flatten sentences
75
- */
76
- flatten?: boolean
77
- } & Pick<Opts, 'onMsgExtracted' | 'onMetaExtracted'>
78
-
79
- function calculateLineColFromOffset(
80
- text: string,
81
- start?: number
82
- ): Pick<ExtractedMessageDescriptor, 'line' | 'col'> {
83
- if (!start) {
84
- return {line: 1, col: 1}
85
- }
86
- const chunk = text.slice(0, start)
87
- const lines = chunk.split('\n')
88
- const lastLine = lines[lines.length - 1]
89
- return {line: lines.length, col: lastLine.length}
90
- }
91
-
92
- async function processFile(
93
- source: string,
94
- fn: string,
95
- {idInterpolationPattern, ...opts}: Opts & {idInterpolationPattern?: string}
96
- ) {
97
- let messages: ExtractedMessageDescriptor[] = []
98
- let meta: Record<string, string> | undefined
99
-
100
- opts = {
101
- ...opts,
102
- additionalComponentNames: [
103
- '$formatMessage',
104
- ...(opts.additionalComponentNames || []),
105
- ],
106
- onMsgExtracted(_, msgs) {
107
- if (opts.extractSourceLocation) {
108
- msgs = msgs.map(msg => ({
109
- ...msg,
110
- ...calculateLineColFromOffset(source, msg.start),
111
- }))
112
- }
113
- messages = messages.concat(msgs)
114
- },
115
- onMetaExtracted(_, m) {
116
- meta = m
117
- },
118
- }
119
-
120
- if (!opts.overrideIdFn && idInterpolationPattern) {
121
- opts = {
122
- ...opts,
123
- overrideIdFn: (id, defaultMessage, description, fileName) =>
124
- id ||
125
- interpolateName(
126
- {
127
- resourcePath: fileName,
128
- } as any,
129
- idInterpolationPattern,
130
- {
131
- content: description
132
- ? `${defaultMessage}#${
133
- typeof description === 'string'
134
- ? description
135
- : stringify(description)
136
- }`
137
- : defaultMessage,
138
- }
139
- ),
140
- }
141
- }
142
-
143
- debug('Processing opts for %s: %s', fn, opts)
144
-
145
- const scriptParseFn = parseScript(opts, fn)
146
- if (fn.endsWith('.vue')) {
147
- debug('Processing %s using vue extractor', fn)
148
- const {parseFile} = await import('./vue_extractor')
149
- parseFile(source, fn, scriptParseFn)
150
- } else {
151
- debug('Processing %s using typescript extractor', fn)
152
- scriptParseFn(source)
153
- }
154
- debug('Done extracting %s messages: %s', fn, messages)
155
- if (meta) {
156
- debug('Extracted meta:', meta)
157
- messages.forEach(m => (m.meta = meta))
158
- }
159
- return {messages, meta}
160
- }
161
-
162
- /**
163
- * Extract strings from source files
164
- * @param files list of files
165
- * @param extractOpts extract options
166
- * @returns messages serialized as JSON string since key order
167
- * matters for some `format`
168
- */
169
- export async function extract(
170
- files: readonly string[],
171
- extractOpts: ExtractOpts
172
- ) {
173
- const {throws, readFromStdin, flatten, ...opts} = extractOpts
174
- let rawResults: Array<ExtractionResult | undefined>
175
- if (readFromStdin) {
176
- debug(`Reading input from stdin`)
177
- // Read from stdin
178
- if (process.stdin.isTTY) {
179
- warn('Reading source file from TTY.')
180
- }
181
- const stdinSource = await getStdinAsString()
182
- rawResults = [await processFile(stdinSource, 'dummy', opts)]
183
- } else {
184
- rawResults = await Promise.all(
185
- files.map(async fn => {
186
- debug('Extracting file:', fn)
187
- try {
188
- const source = await readFile(fn, 'utf8')
189
- return processFile(source, fn, opts)
190
- } catch (e) {
191
- if (throws) {
192
- throw e
193
- } else {
194
- warn(String(e))
195
- }
196
- }
197
- })
198
- )
199
- }
200
-
201
- const formatter = await resolveBuiltinFormatter(opts.format)
202
- const extractionResults = rawResults.filter((r): r is ExtractionResult => !!r)
203
-
204
- const extractedMessages = new Map<string, MessageDescriptor>()
205
-
206
- for (const {messages} of extractionResults) {
207
- for (const message of messages) {
208
- const {id, description, defaultMessage} = message
209
- if (!id) {
210
- const error = new Error(
211
- `[FormatJS CLI] Missing message id for message:
212
- ${JSON.stringify(message, undefined, 2)}`
213
- )
214
- if (throws) {
215
- throw error
216
- } else {
217
- warn(error.message)
218
- }
219
- continue
220
- }
221
-
222
- if (extractedMessages.has(id)) {
223
- const existing = extractedMessages.get(id)!
224
- if (
225
- stringify(description) !== stringify(existing.description) ||
226
- defaultMessage !== existing.defaultMessage
227
- ) {
228
- const error = new Error(
229
- `[FormatJS CLI] Duplicate message id: "${id}", ` +
230
- 'but the `description` and/or `defaultMessage` are different.'
231
- )
232
- if (throws) {
233
- throw error
234
- } else {
235
- warn(error.message)
236
- }
237
- }
238
- }
239
- extractedMessages.set(id, message)
240
- }
241
- }
242
- const results: Record<string, Omit<MessageDescriptor, 'id'>> = {}
243
- const messages = Array.from(extractedMessages.values())
244
- for (const {id, ...msg} of messages) {
245
- if (flatten && msg.defaultMessage) {
246
- msg.defaultMessage = printAST(hoistSelectors(parse(msg.defaultMessage)))
247
- }
248
- results[id] = msg
249
- }
250
- return stringify(formatter.format(results), {
251
- space: 2,
252
- cmp: formatter.compareMessages || undefined,
253
- })
254
- }
255
-
256
- /**
257
- * Extract strings from source files, also writes to a file.
258
- * @param files list of files
259
- * @param extractOpts extract options
260
- * @returns A Promise that resolves if output file was written successfully
261
- */
262
- export default async function extractAndWrite(
263
- files: readonly string[],
264
- extractOpts: ExtractCLIOptions
265
- ) {
266
- const {outFile, ...opts} = extractOpts
267
- const serializedResult = (await extract(files, opts)) + '\n'
268
- if (outFile) {
269
- debug('Writing output file:', outFile)
270
- return outputFile(outFile, serializedResult)
271
- }
272
- await writeStdout(serializedResult)
273
- }
@@ -1,34 +0,0 @@
1
- import {CompileFn, FormatFn} from './default'
2
-
3
- export type SmartlingJson = Record<
4
- string,
5
- {
6
- message: string
7
- description?: string
8
- }
9
- >
10
-
11
- export const format: FormatFn<SmartlingJson> = msgs => {
12
- const results: SmartlingJson = {}
13
- for (const [id, msg] of Object.entries(msgs)) {
14
- results[id] = {
15
- message: msg.defaultMessage!,
16
- description:
17
- typeof msg.description === 'string'
18
- ? msg.description
19
- : JSON.stringify(msg.description),
20
- }
21
- }
22
- return results
23
- }
24
-
25
- export const compile: CompileFn<SmartlingJson> = msgs => {
26
- const results: Record<string, string> = {}
27
- for (const [id, msg] of Object.entries(msgs)) {
28
- if (id === 'smartling') {
29
- continue
30
- }
31
- results[id] = msg.message
32
- }
33
- return results
34
- }
@@ -1,19 +0,0 @@
1
- import {MessageDescriptor} from '@formatjs/ts-transformer'
2
-
3
- export type FormatFn<T = Record<string, MessageDescriptor>> = (
4
- msgs: Record<string, MessageDescriptor>
5
- ) => T
6
-
7
- export type CompileFn<T = Record<string, MessageDescriptor>> = (
8
- msgs: T
9
- ) => Record<string, string>
10
-
11
- export const format: FormatFn = msgs => msgs
12
-
13
- export const compile: CompileFn = msgs => {
14
- const results: Record<string, string> = {}
15
- for (const k in msgs) {
16
- results[k] = msgs[k].defaultMessage!
17
- }
18
- return results
19
- }
@@ -1,46 +0,0 @@
1
- import * as defaultFormatter from './default'
2
- import {FormatFn, CompileFn} from './default'
3
- import * as transifex from './transifex'
4
- import * as smartling from './smartling'
5
- import * as simple from './simple'
6
- import * as lokalise from './lokalise'
7
- import * as crowdin from './crowdin'
8
- import {Comparator} from 'json-stable-stringify'
9
- import {resolve} from 'path'
10
- import {pathToFileURL} from 'url'
11
-
12
- export interface Formatter {
13
- format: FormatFn
14
- compile: CompileFn
15
- compareMessages?: Comparator
16
- }
17
-
18
- export async function resolveBuiltinFormatter(
19
- format?: string | Formatter
20
- ): Promise<any> {
21
- if (!format) {
22
- return defaultFormatter
23
- }
24
- if (typeof format !== 'string') {
25
- return format
26
- }
27
- switch (format) {
28
- case 'transifex':
29
- return transifex
30
- case 'smartling':
31
- return smartling
32
- case 'simple':
33
- return simple
34
- case 'lokalise':
35
- return lokalise
36
- case 'crowdin':
37
- return crowdin
38
- }
39
- try {
40
- // eslint-disable-next-line import/dynamic-import-chunkname
41
- return import(pathToFileURL(resolve(process.cwd(), format)).href)
42
- } catch (e) {
43
- console.error(`Cannot resolve formatter ${format}`)
44
- throw e
45
- }
46
- }
@@ -1,33 +0,0 @@
1
- import {CompileFn, FormatFn} from './default'
2
-
3
- export type StructuredJson = Record<
4
- string,
5
- {
6
- translation: string
7
- notes?: string
8
- context?: string
9
- limit?: string
10
- }
11
- >
12
-
13
- export const format: FormatFn<StructuredJson> = msgs => {
14
- const results: StructuredJson = {}
15
- for (const [id, msg] of Object.entries(msgs)) {
16
- results[id] = {
17
- translation: msg.defaultMessage!,
18
- notes:
19
- typeof msg.description === 'string'
20
- ? msg.description
21
- : JSON.stringify(msg.description),
22
- }
23
- }
24
- return results
25
- }
26
-
27
- export const compile: CompileFn<StructuredJson> = msgs => {
28
- const results: Record<string, string> = {}
29
- for (const [id, msg] of Object.entries(msgs)) {
30
- results[id] = msg.translation
31
- }
32
- return results
33
- }
@@ -1,12 +0,0 @@
1
- import {CompileFn, FormatFn} from './default'
2
-
3
- export type PhraseJson = Record<string, string>
4
-
5
- export const format: FormatFn<PhraseJson> = msgs => {
6
- return Object.keys(msgs).reduce((all: PhraseJson, k) => {
7
- all[k] = msgs[k].defaultMessage!
8
- return all
9
- }, {})
10
- }
11
-
12
- export const compile: CompileFn<PhraseJson> = msgs => msgs
@@ -1,73 +0,0 @@
1
- import {Comparator} from 'json-stable-stringify'
2
- import {CompileFn, FormatFn} from './default'
3
-
4
- export interface SmartlingDirectives {
5
- translate_paths: [
6
- {
7
- path: string
8
- key: string
9
- instruction: string
10
- }
11
- ]
12
- variants_enabled: boolean
13
- string_format: string
14
- [k: string]: any
15
- }
16
-
17
- export type SmartlingJson = {
18
- smartling: SmartlingDirectives
19
- } & Record<
20
- string,
21
- {
22
- message: string
23
- description?: string
24
- }
25
- >
26
-
27
- export const format: FormatFn<SmartlingJson> = msgs => {
28
- const results: SmartlingJson = {
29
- smartling: {
30
- translate_paths: [
31
- {
32
- path: '*/message',
33
- key: '{*}/message',
34
- instruction: '*/description',
35
- },
36
- ],
37
- variants_enabled: true,
38
- string_format: 'icu',
39
- },
40
- } as any
41
- for (const [id, msg] of Object.entries(msgs)) {
42
- results[id] = {
43
- message: msg.defaultMessage!,
44
- description:
45
- typeof msg.description === 'string'
46
- ? msg.description
47
- : JSON.stringify(msg.description),
48
- }
49
- }
50
- return results
51
- }
52
-
53
- export const compareMessages: Comparator = (el1, el2) => {
54
- // `smartling` has to be the 1st key
55
- if (el1.key === 'smartling') {
56
- return -1
57
- }
58
- if (el2.key === 'smartling') {
59
- return 1
60
- }
61
- return el1.key < el2.key ? -1 : el1.key === el2.key ? 0 : 1
62
- }
63
-
64
- export const compile: CompileFn<SmartlingJson> = msgs => {
65
- const results: Record<string, string> = {}
66
- for (const [id, msg] of Object.entries(msgs)) {
67
- if (id === 'smartling') {
68
- continue
69
- }
70
- results[id] = msg.message
71
- }
72
- return results
73
- }
@@ -1,33 +0,0 @@
1
- import {CompileFn, FormatFn} from './default'
2
-
3
- export type StructuredJson = Record<
4
- string,
5
- {
6
- string: string
7
- developer_comment?: string
8
- context?: string
9
- character_limit?: string
10
- }
11
- >
12
-
13
- export const format: FormatFn<StructuredJson> = msgs => {
14
- const results: StructuredJson = {}
15
- for (const [id, msg] of Object.entries(msgs)) {
16
- results[id] = {
17
- string: msg.defaultMessage!,
18
- developer_comment:
19
- typeof msg.description === 'string'
20
- ? msg.description
21
- : JSON.stringify(msg.description),
22
- }
23
- }
24
- return results
25
- }
26
-
27
- export const compile: CompileFn<StructuredJson> = msgs => {
28
- const results: Record<string, string> = {}
29
- for (const [id, msg] of Object.entries(msgs)) {
30
- results[id] = msg.string
31
- }
32
- return results
33
- }
@@ -1,49 +0,0 @@
1
- import {Opts, transformWithTs} from '@formatjs/ts-transformer'
2
- import ts from 'typescript'
3
- import {debug} from './console_utils'
4
- /**
5
- * Invoid TypeScript module transpilation with our TS transformer
6
- * @param opts Formatjs TS Transformer opt
7
- * @param fn filename
8
- */
9
- export function parseScript(opts: Opts, fn?: string) {
10
- return (source: string) => {
11
- let output
12
- try {
13
- debug('Using TS compiler to process file', fn)
14
- output = ts.transpileModule(source, {
15
- compilerOptions: {
16
- allowJs: true,
17
- target: ts.ScriptTarget.ESNext,
18
- noEmit: true,
19
- experimentalDecorators: true,
20
- },
21
- reportDiagnostics: true,
22
- fileName: fn,
23
- transformers: {
24
- before: [transformWithTs(ts, opts)],
25
- },
26
- })
27
- } catch (e) {
28
- if (e instanceof Error) {
29
- e.message = `Error processing file ${fn}
30
- ${e.message || ''}`
31
- }
32
- throw e
33
- }
34
- if (output.diagnostics) {
35
- const errs = output.diagnostics.filter(
36
- d => d.category === ts.DiagnosticCategory.Error
37
- )
38
- if (errs.length) {
39
- throw new Error(
40
- ts.formatDiagnosticsWithColorAndContext(errs, {
41
- getCanonicalFileName: fileName => fileName,
42
- getCurrentDirectory: () => process.cwd(),
43
- getNewLine: () => ts.sys.newLine,
44
- })
45
- )
46
- }
47
- }
48
- }
49
- }
@@ -1,113 +0,0 @@
1
- import {
2
- parse,
3
- MessageFormatElement,
4
- TYPE,
5
- isLiteralElement,
6
- isPluralElement,
7
- isSelectElement,
8
- isTagElement,
9
- } from '@formatjs/icu-messageformat-parser'
10
-
11
- export function generateXXLS(
12
- msg: string | MessageFormatElement[]
13
- ): MessageFormatElement[] {
14
- const ast = typeof msg === 'string' ? parse(msg) : msg
15
- const lastChunk = ast[ast.length - 1]
16
- if (lastChunk && isLiteralElement(lastChunk)) {
17
- lastChunk.value += 'SSSSSSSSSSSSSSSSSSSSSSSSS'
18
- return ast
19
- }
20
- return [...ast, {type: TYPE.literal, value: 'SSSSSSSSSSSSSSSSSSSSSSSSS'}]
21
- }
22
-
23
- export function generateXXAC(
24
- msg: string | MessageFormatElement[]
25
- ): MessageFormatElement[] {
26
- const ast = typeof msg === 'string' ? parse(msg) : msg
27
- ast.forEach(el => {
28
- if (isLiteralElement(el)) {
29
- el.value = el.value.toUpperCase()
30
- } else if (isPluralElement(el) || isSelectElement(el)) {
31
- for (const opt of Object.values(el.options)) {
32
- generateXXAC(opt.value)
33
- }
34
- } else if (isTagElement(el)) {
35
- generateXXAC(el.children)
36
- }
37
- })
38
- return ast
39
- }
40
-
41
- export function generateXXHA(
42
- msg: string | MessageFormatElement[]
43
- ): MessageFormatElement[] {
44
- const ast = typeof msg === 'string' ? parse(msg) : msg
45
- const firstChunk = ast.shift()
46
- if (firstChunk && isLiteralElement(firstChunk)) {
47
- firstChunk.value = '[javascript]' + firstChunk.value
48
- return [firstChunk, ...ast]
49
- }
50
- return [{type: TYPE.literal, value: '[javascript]'}, ...ast]
51
- }
52
-
53
- const ASCII = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
54
- const ACCENTED_ASCII = 'âḃćḋèḟĝḫíĵǩĺṁńŏṗɋŕśṭůṿẘẋẏẓḀḂḈḊḔḞḠḢḬĴḴĻḾŊÕṔɊŔṠṮŨṼẄẌŸƵ'
55
-
56
- export function generateENXA(
57
- msg: string | MessageFormatElement[]
58
- ): MessageFormatElement[] {
59
- const ast = typeof msg === 'string' ? parse(msg) : msg
60
- ast.forEach(el => {
61
- if (isLiteralElement(el)) {
62
- el.value = el.value
63
- .split('')
64
- .map(c => {
65
- const i = ASCII.indexOf(c)
66
- if (i < 0) {
67
- return c
68
- }
69
- return ACCENTED_ASCII[i]
70
- })
71
- .join('')
72
- } else if (isPluralElement(el) || isSelectElement(el)) {
73
- for (const opt of Object.values(el.options)) {
74
- generateENXA(opt.value)
75
- }
76
- } else if (isTagElement(el)) {
77
- generateENXA(el.children)
78
- }
79
- })
80
- return ast
81
- }
82
-
83
- export function generateENXB(
84
- msg: string | MessageFormatElement[]
85
- ): MessageFormatElement[] {
86
- const ast = typeof msg === 'string' ? parse(msg) : msg
87
- ast.forEach(el => {
88
- if (isLiteralElement(el)) {
89
- const pseudoString = el.value
90
- .split('')
91
- .map((c, index) => {
92
- const i = ASCII.indexOf(c)
93
- const canPad = (index + 1) % 3 === 0
94
-
95
- if (i < 0) {
96
- return c
97
- }
98
-
99
- return canPad ? ACCENTED_ASCII[i].repeat(3) : ACCENTED_ASCII[i]
100
- })
101
- .join('')
102
-
103
- el.value = `[!! ${pseudoString} !!]`
104
- } else if (isPluralElement(el) || isSelectElement(el)) {
105
- for (const opt of Object.values(el.options)) {
106
- generateENXB(opt.value)
107
- }
108
- } else if (isTagElement(el)) {
109
- generateENXB(el.children)
110
- }
111
- })
112
- return ast
113
- }