@laisuk/opencc-fmmseg-wasm 0.3.8 → 0.3.9

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.
package/README.md CHANGED
@@ -1,731 +1,728 @@
1
- # opencc-fmmseg-wasm
2
-
3
- [![npm version](https://img.shields.io/npm/v/@laisuk/opencc-fmmseg-wasm)](https://www.npmjs.com/package/@laisuk/opencc-fmmseg-wasm)
4
- [![npm downloads](https://img.shields.io/npm/dm/@laisuk/opencc-fmmseg-wasm)](https://www.npmjs.com/package/@laisuk/opencc-fmmseg-wasm)
5
- [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
6
- [![WebAssembly](https://img.shields.io/badge/WebAssembly-enabled-blue)](https://webassembly.org/)
7
-
8
- OpenCC FMM segmentation WebAssembly bindings for browsers and JavaScript runtimes.
9
-
10
- This package provides high-quality Simplified Chinese ↔ Traditional Chinese conversion powered by the Rust [
11
- `opencc-fmmseg`](https://github.com/laisuk/opencc-fmmseg) engine.
12
-
13
- Features:
14
-
15
- * OpenCC-compatible conversion configs
16
- * Pure WebAssembly (no native binaries)
17
- * Browser-friendly
18
- * TypeScript-friendly APIs
19
- * Fast Rust backend
20
- * FMM-based phrase segmentation
21
- * Traditional Chinese regional variants
22
- * Japanese Shinjitai conversion support
23
- * Chinese script detection (`zho_check`)
24
- * Optional CJK Compatibility Ideograph normalization
25
- * In-memory Office / EPUB document conversion
26
- * Zero-dependency Node.js CLI
27
-
28
- Package profile:
29
-
30
- * 0 runtime dependencies
31
- * 1 WASM file
32
- * 18 conversion configs
33
- * 100% offline
34
-
35
- ---
36
-
37
- ## Installation
38
-
39
- ```bash
40
- npm install @laisuk/opencc-fmmseg-wasm
41
- ```
42
-
43
- ---
44
-
45
- ## Quick Start
46
-
47
- ```javascript
48
- import init, {
49
- OpenccWasm,
50
- DetofuLevelWasm
51
- } from "@laisuk/opencc-fmmseg-wasm";
52
-
53
- await init();
54
-
55
- const cc = new OpenccWasm("s2t");
56
-
57
- console.log(cc.convert("汉字", false));
58
- // 漢字
59
-
60
- console.log(cc.convertDetofu("儼驂騑於上路", false, DetofuLevelWasm.ExtB));
61
- // 俨骖騑于上路
62
- ```
63
-
64
- ---
65
-
66
- ## Using Config Enums
67
-
68
- ```javascript
69
- import init, {
70
- OpenccWasm,
71
- OpenccConfigWasm
72
- } from "@laisuk/opencc-fmmseg-wasm";
73
-
74
- await init();
75
-
76
- const cc = OpenccWasm.newWithEnum(
77
- OpenccConfigWasm.S2hkp
78
- );
79
-
80
- console.log(cc.convert("别随便录影侵犯个人隐私权", false));
81
- // 別隨便錄影侵犯個人私隱權
82
- ```
83
-
84
- ---
85
-
86
- ## Supported Configs
87
-
88
- | Config | Enum | Description |
89
- |---------|--------------------------|------------------------------------------------------|
90
- | `s2t` | `OpenccConfigWasm.S2t` | Simplified Chinese → Traditional Chinese |
91
- | `s2tw` | `OpenccConfigWasm.S2tw` | Simplified Chinese → Taiwan Traditional |
92
- | `s2twp` | `OpenccConfigWasm.S2twp` | Simplified Chinese → Taiwan Traditional (phrases) |
93
- | `s2hk` | `OpenccConfigWasm.S2hk` | Simplified Chinese → Hong Kong Traditional |
94
- | `s2hkp` | `OpenccConfigWasm.S2hkp` | Simplified Chinese → Hong Kong Traditional (phrases) |
95
- | `t2s` | `OpenccConfigWasm.T2s` | Traditional Chinese → Simplified Chinese |
96
- | `t2tw` | `OpenccConfigWasm.T2tw` | Traditional Chinese → Taiwan Traditional |
97
- | `t2twp` | `OpenccConfigWasm.T2twp` | Traditional Chinese → Taiwan Traditional (phrases) |
98
- | `t2hk` | `OpenccConfigWasm.T2hk` | Traditional Chinese → Hong Kong Traditional |
99
- | `t2hkp` | `OpenccConfigWasm.T2hkp` | Traditional Chinese → Hong Kong Traditional (phrases)|
100
- | `tw2s` | `OpenccConfigWasm.Tw2s` | Taiwan Traditional → Simplified Chinese |
101
- | `tw2sp` | `OpenccConfigWasm.Tw2sp` | Taiwan Traditional → Simplified Chinese (phrases) |
102
- | `tw2t` | `OpenccConfigWasm.Tw2t` | Taiwan Traditional → Traditional Chinese |
103
- | `tw2tp` | `OpenccConfigWasm.Tw2tp` | Taiwan Traditional → Traditional Chinese (phrases) |
104
- | `hk2s` | `OpenccConfigWasm.Hk2s` | Hong Kong Traditional → Simplified Chinese |
105
- | `hk2sp` | `OpenccConfigWasm.Hk2sp` | Hong Kong Traditional → Simplified Chinese (phrases) |
106
- | `hk2t` | `OpenccConfigWasm.Hk2t` | Hong Kong Traditional → Traditional Chinese |
107
- | `hk2tp` | `OpenccConfigWasm.Hk2tp` | Hong Kong Traditional → Traditional Chinese (phrases)|
108
- | `jp2t` | `OpenccConfigWasm.Jp2t` | Japanese Shinjitai → Traditional Chinese |
109
- | `t2jp` | `OpenccConfigWasm.T2jp` | Traditional Chinese → Japanese Shinjitai |
110
-
111
- The numeric enum values match the vendored Rust backend. Existing values are unchanged; `S2hkp = 17`, `Hk2sp = 18`, `T2hkp = 19`, and `Hk2tp = 20`.
112
-
113
- ---
114
-
115
- ## API
116
-
117
- ### Constructor
118
-
119
- ```javascript
120
- const cc = new OpenccWasm("s2t");
121
- ```
122
-
123
- Parameters:
124
-
125
- * `config` (optional): OpenCC config string
126
- * default: `"s2t"`
127
-
128
- Example:
129
-
130
- ```javascript
131
- const cc = new OpenccWasm("t2s");
132
- ```
133
-
134
- Hong Kong phrase config example:
135
-
136
- ```javascript
137
- const cc = new OpenccWasm("s2hkp");
138
-
139
- cc.convert("别随便录影侵犯个人隐私权", false);
140
- // 別隨便錄影侵犯個人私隱權
141
- ```
142
-
143
- ---
144
-
145
- ### convert
146
-
147
- ```javascript
148
- cc.convert(text, punctuation)
149
- ```
150
-
151
- Parameters:
152
-
153
- * `text`: input string
154
- * `punctuation`: whether to convert punctuation variants
155
-
156
- Returns:
157
-
158
- * converted string
159
-
160
- Example:
161
-
162
- ```javascript
163
- cc.convert("汉字", false);
164
- ```
165
-
166
- ---
167
-
168
- ### normalizeCompat
169
-
170
- Normalize Unicode CJK Compatibility Ideographs before conversion.
171
-
172
- ```javascript
173
- cc.normalizeCompat(text)
174
- ```
175
-
176
- Parameters:
177
-
178
- * `text`: input string
179
-
180
- Returns:
181
-
182
- * normalized string
183
-
184
- Example:
185
-
186
- ```javascript
187
- const cc = new OpenccWasm("t2s");
188
-
189
- const input = "天龍八部書裡的喬峰是契丹人";
190
- const normalized = cc.normalizeCompat(input);
191
-
192
- console.log(normalized);
193
- // 天龍八部書裡的喬峰是契丹人
194
-
195
- console.log(cc.convert(normalized, false));
196
- // 天龙八部书里的乔峰是契丹人
197
- ```
198
-
199
- This is an optional pre-conversion pass for text that contains compatibility ideographs from Unicode compatibility ranges. Unmapped characters are preserved unchanged. Normal OpenCC conversion does not automatically run this pass, so call it explicitly when compatibility normalization is desired.
200
-
201
- ---
202
-
203
- ### detofu
204
-
205
- Replace tofu-risk rare CJK extension characters with display-compatible fallbacks.
206
-
207
- ```javascript
208
- cc.detofu(text, level)
209
- ```
210
-
211
- Parameters:
212
-
213
- * `text`: input string
214
- * `level`: `DetofuLevelWasm` threshold for the CJK extension ranges to replace
215
-
216
- Returns:
217
-
218
- * detofu-safe string
219
-
220
- Supported levels:
221
-
222
- | Enum | CLI value |
223
- |------------------------|-----------|
224
- | `DetofuLevelWasm.ExtB` | `ext-b` |
225
- | `DetofuLevelWasm.ExtC` | `ext-c` |
226
- | `DetofuLevelWasm.ExtD` | `ext-d` |
227
- | `DetofuLevelWasm.ExtE` | `ext-e` |
228
- | `DetofuLevelWasm.ExtF` | `ext-f` |
229
- | `DetofuLevelWasm.ExtG` | `ext-g` |
230
- | `DetofuLevelWasm.ExtH` | `ext-h` |
231
- | `DetofuLevelWasm.ExtI` | `ext-i` |
232
-
233
- Example:
234
-
235
- ```javascript
236
- import init, {
237
- OpenccWasm,
238
- DetofuLevelWasm
239
- } from "@laisuk/opencc-fmmseg-wasm";
240
-
241
- await init();
242
-
243
- const cc = new OpenccWasm("t2s");
244
- const converted = cc.convert("儼驂騑於上路", false);
245
-
246
- console.log(converted);
247
- // 俨骖𬴂于上路
248
-
249
- console.log(cc.detofu(converted, DetofuLevelWasm.ExtB));
250
- // 俨骖騑于上路
251
- ```
252
-
253
- ---
254
-
255
- ### convertDetofu
256
-
257
- Convert text and apply detofu in one call.
258
-
259
- ```javascript
260
- cc.convertDetofu(text, punctuation, level)
261
- ```
262
-
263
- Parameters:
264
-
265
- * `text`: input string
266
- * `punctuation`: whether to convert punctuation variants
267
- * `level`: `DetofuLevelWasm` threshold for the CJK extension ranges to replace
268
-
269
- Returns:
270
-
271
- * converted detofu-safe string
272
-
273
- Example:
274
-
275
- ```javascript
276
- cc.convertDetofu("儼驂騑於上路", false, DetofuLevelWasm.ExtB);
277
- // 俨骖騑于上路
278
- ```
279
-
280
- ---
281
-
282
- ### setConfig
283
-
284
- ```javascript
285
- cc.setConfig("t2s");
286
- ```
287
-
288
- Returns:
289
-
290
- * `true` if valid
291
- * `false` if invalid
292
-
293
- ---
294
-
295
- ### getConfig
296
-
297
- ```javascript
298
- cc.getConfig();
299
- ```
300
-
301
- Returns current config string.
302
-
303
- ---
304
-
305
- ### isValidConfig
306
-
307
- ```javascript
308
- OpenccWasm.isValidConfig("s2t");
309
- ```
310
-
311
- ---
312
-
313
- ### getSupportedConfigs
314
-
315
- ```javascript
316
- OpenccWasm.getSupportedConfigs();
317
- ```
318
-
319
- Returns all supported config strings.
320
-
321
- Includes `s2hkp`, `hk2sp`, `t2hkp`, and `hk2tp`.
322
-
323
- ---
324
-
325
- ### zhoCheck
326
-
327
- Detect Chinese script type.
328
-
329
- ```javascript
330
- cc.zhoCheck(text);
331
- ```
332
-
333
- Returns:
334
-
335
- | Value | Meaning |
336
- |-------|---------------------|
337
- | `0` | Unknown / mixed |
338
- | `1` | Traditional Chinese |
339
- | `2` | Simplified Chinese |
340
-
341
- ---
342
-
343
- ### newWithCustomDicts
344
-
345
- Construct a converter with in-memory custom dictionary pairs.
346
-
347
- ```javascript
348
- const cc = OpenccWasm.newWithCustomDicts(config, specs);
349
- ```
350
-
351
- Parameters:
352
-
353
- * `config`: OpenCC config string, such as `"s2t"`
354
- * `specs`: array of custom dictionary specs
355
-
356
- TypeScript-style spec shape:
357
-
358
- ```typescript
359
- type WasmCustomDictSpec = {
360
- slot: string;
361
- mode?: "Append" | "Override";
362
- pairs: Array<[string, string]>;
363
- };
364
- ```
365
-
366
- `mode` defaults to `"Append"` when omitted.
367
-
368
- Each `pairs` entry is a `[source, target]` string tuple for the selected slot.
369
-
370
- TypeScript example:
371
-
372
- ```typescript
373
- import init, {OpenccWasm} from "@laisuk/opencc-fmmseg-wasm";
374
-
375
- await init();
376
-
377
- const specs: WasmCustomDictSpec[] = [
378
- {
379
- slot: "STPhrases",
380
- pairs: [
381
- ["云端", "雲端"]
382
- ]
383
- }
384
- ];
385
-
386
- const cc = OpenccWasm.newWithCustomDicts("s2t", specs);
387
- ```
388
-
389
- Practical example:
390
-
391
- ```javascript
392
- import init, {OpenccWasm} from "@laisuk/opencc-fmmseg-wasm";
393
-
394
- await init();
395
-
396
- const cc = OpenccWasm.newWithCustomDicts("s2t", [
397
- {
398
- slot: "STPhrases",
399
- mode: "Append",
400
- pairs: [
401
- ["帕兰蒂尔", "柏蘭蒂爾"],
402
- ["软件", "軟體"]
403
- ]
404
- }
405
- ]);
406
-
407
- console.log(cc.convert("帕兰蒂尔软件", false));
408
- // 柏蘭蒂爾軟體
409
- ```
410
-
411
- Override example:
412
-
413
- ```javascript
414
- const cc = OpenccWasm.newWithCustomDicts("s2t", [
415
- {
416
- slot: "STPhrases",
417
- mode: "Override",
418
- pairs: [
419
- ["软件", "軟體"]
420
- ]
421
- }
422
- ]);
423
- ```
424
-
425
- `Override` replaces the selected slot before inserting the provided pairs. It is powerful and should be used only when
426
- the caller intentionally wants to discard built-in entries for that slot.
427
-
428
- Custom dictionary specs identify the target dictionary slot by `DictSlot` name. Slot names are trimmed and normalized
429
- case-insensitively for the known slots, so `"stphrases"`, `" STPhrases "`, and `"STPhrases"` all select
430
- `STPhrases`. Canonical names are recommended in TypeScript code and docs:
431
-
432
- ```text
433
- STPhrases
434
- TSPhrases
435
- STCharacters
436
- TSCharacters
437
- TWPhrases
438
- TWPhrasesRev
439
- HKPhrases
440
- HKPhrasesRev
441
- TWVariants
442
- TWVariantsPhrases
443
- TWVariantsRev
444
- TWVariantsRevPhrases
445
- HKVariants
446
- HKVariantsPhrases
447
- HKVariantsRev
448
- HKVariantsRevPhrases
449
- JPSCharacters
450
- JPSCharactersRev
451
- JPSPhrases
452
- STPunctuations
453
- TSPunctuations
454
- ```
455
-
456
- Suffixes such as `.txt` are not accepted, even though case and surrounding whitespace are normalized. Use
457
- `"STPhrases"` or `"stphrases"`, not `"STPhrases.txt"`.
458
-
459
- Merge contract:
460
-
461
- * Custom dictionaries are loaded from in-memory pairs only; no file I/O is involved.
462
- * The embedded compressed CBOR dictionary is loaded first.
463
- * Custom specs are applied to `DictionaryMaxlength` before `OpenCC::from_dictionary(...)`.
464
- * Conversion hot paths remain immutable after construction.
465
- * `Append` mode merges into the selected slot.
466
- * Duplicate or conflicting keys use last-wins semantics.
467
- * `Override` mode clears the selected slot first, then inserts the provided custom pairs.
468
- * Multiple specs are applied in array order.
469
-
470
- This API is useful for browser apps, user-defined terminology, database-loaded terms, generated dictionaries,
471
- `localStorage` or `IndexedDB` terms, testing, and embedded WASM environments. Customization happens at construction
472
- time, not during conversion.
473
-
474
- ---
475
-
476
- ## Office / EPUB Conversion
477
-
478
- Office and EPUB conversion runs fully locally in the browser or Node.js. Files are passed in and returned as bytes;
479
- nothing is uploaded to a backend server.
480
-
481
- This is useful for converting text inside:
482
-
483
- ```text
484
- docx, xlsx, pptx, odt, ods, odp, epub
485
- ```
486
-
487
- File size is limited by available browser or Node.js memory, but there is no upload or server-side limit. Font
488
- preservation is supported with the `keepFont` option.
489
-
490
- Use the instance method when possible. It reuses the converter configuration and any custom dictionaries already held by
491
- the `OpenccWasm` instance.
492
-
493
- ```javascript
494
- cc.convertOfficeBytes(inputBytes, format, punctuation, keepFont)
495
- ```
496
-
497
- Parameters:
498
-
499
- * `inputBytes`: `Uint8Array` document bytes
500
- * `format`: `docx`, `xlsx`, `pptx`, `odt`, `ods`, `odp`, or `epub`
501
- * `punctuation`: whether to convert punctuation variants
502
- * `keepFont`: whether to preserve font declarations where supported
503
-
504
- Returns:
505
-
506
- * converted output bytes
507
-
508
- The older free function remains available for compatibility:
509
-
510
- ```javascript
511
- convert_office_bytes(inputBytes, format, config, punctuation, keepFont)
512
- ```
513
-
514
- ### Browser Office Example
515
-
516
- ```javascript
517
- import init, {OpenccWasm} from "@laisuk/opencc-fmmseg-wasm";
518
-
519
- await init();
520
-
521
- const cc = new OpenccWasm("s2t");
522
- const file = document.querySelector("input[type=file]").files[0];
523
- const inputBytes = new Uint8Array(await file.arrayBuffer());
524
-
525
- const outputBytes = cc.convertOfficeBytes(
526
- inputBytes,
527
- "docx",
528
- true,
529
- true
530
- );
531
-
532
- const blob = new Blob([outputBytes], {
533
- type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
534
- });
535
-
536
- const a = document.createElement("a");
537
- a.href = URL.createObjectURL(blob);
538
- a.download = "converted.docx";
539
- a.click();
540
- URL.revokeObjectURL(a.href);
541
- ```
542
-
543
- ### Node.js Office Example
544
-
545
- ```javascript
546
- import fs from "fs";
547
- import init, {OpenccWasm} from "@laisuk/opencc-fmmseg-wasm";
548
-
549
- await init();
550
-
551
- const cc = new OpenccWasm("s2t");
552
- const inputBytes = fs.readFileSync("input.docx");
553
-
554
- const outputBytes = cc.convertOfficeBytes(
555
- inputBytes,
556
- "docx",
557
- true,
558
- true
559
- );
560
-
561
- fs.writeFileSync("output.docx", outputBytes);
562
- ```
563
-
564
- ---
565
-
566
- ## Browser Example
567
-
568
- ```html
569
- <!DOCTYPE html>
570
- <html lang="en">
571
- <head>
572
- <meta charset="UTF-8">
573
- <title>OpenCC WASM Demo</title>
574
- </head>
575
- <body>
576
-
577
- <script type="module">
578
- import init, {
579
- OpenccWasm
580
- } from "./pkg/opencc_fmmseg_wasm.js";
581
-
582
- await init();
583
-
584
- const cc = new OpenccWasm("s2t");
585
-
586
- console.log(
587
- cc.convert("汉字", false)
588
- );
589
- </script>
590
-
591
- </body>
592
- </html>
593
- ```
594
-
595
- > **Note**
596
- >
597
- > Normally, `await init();` is sufficient when using the published npm package.
598
- >
599
- > When running directly from a local repository checkout (for example in tests
600
- > or development scripts), initialize using explicit WASM bytes:
601
- >
602
- > ```javascript
603
- > import fs from "fs";
604
- > import init from "../pkg/opencc_fmmseg_wasm.js";
605
- >
606
- > const wasmBytes = fs.readFileSync(
607
- > "../pkg/opencc_fmmseg_wasm_bg.wasm"
608
- > );
609
- >
610
- > await init({
611
- > module_or_path: wasmBytes
612
- > });
613
- > ```
614
-
615
- ---
616
-
617
- ## Node.js CLI
618
-
619
- The package includes a zero-dependency Node.js CLI:
620
-
621
- ```bash
622
- opencc-fmmseg convert -i input.txt -o output.txt -c s2t -p
623
- opencc-fmmseg convert -i input.txt -o output.txt -c t2s -p --detofu all
624
- echo "别随便录影侵犯个人隐私权" | opencc-fmmseg convert -c s2hkp
625
- echo "天龍八部書裡的喬峰是契丹人" | opencc-fmmseg convert -c t2s --norm-compat
626
- // 天龙八部书里的乔峰是契丹人
627
- echo "這個細路哥很靈活" | opencc-fmmseg convert -c hk2sp --custom-dict hkphrasesrev:append:my_hk_dict.txt
628
- // 这个小男孩很灵活
629
- ```
630
-
631
- my_hk_dict.txt:
632
-
633
- ```
634
- # Custom Dictionary
635
-
636
- 細路哥 小男孩
637
- ```
638
-
639
- ```bash
640
- opencc-fmmseg office -i input.docx -o output.docx -c s2t -p --keep-font
641
- ```
642
-
643
- ### Text Conversion Options
644
-
645
- ```text
646
- -i, --input <file> Input text file; stdin if omitted
647
- -o, --output <file> Output text file; stdout if omitted
648
- -c, --config <conversion> Conversion config (default: s2t)
649
- -p, --punct Enable punctuation conversion
650
- --detofu [level] Replace tofu-risk rare CJK extension chars after conversion
651
- level: all | ext-b | ext-c | ext-d | ext-e | ext-f | ext-g | ext-h | ext-i
652
- default when omitted value: all
653
- --keep-ids Preserve complete IDS expressions during conversion (default: false)
654
- -n, --norm-compat Normalize CJK Compatibility Ideographs before conversion (default: false)
655
- -D, --custom-dict <slot:mode:file>
656
- Load a custom dictionary.
657
- May be specified multiple times.
658
- Examples:
659
- --custom-dict hkphrasesrev:append:my_hk_dict.txt
660
- --custom-dict stphrases:override:terms.txt
661
- --in-enc <encoding> Input encoding (default: utf8)
662
- --out-enc <encoding> Output encoding (default: utf8)
663
- ```
664
-
665
- Supported conversion configs:
666
-
667
- ```text
668
- s2t, s2tw, s2twp, s2hk, s2hkp, t2s, t2tw, t2twp, t2hk, t2hkp,
669
- tw2s, tw2sp, tw2t, tw2tp, hk2s, hk2sp, hk2t, hk2tp, jp2t, t2jp
670
- ```
671
-
672
- ### Office / EPUB Options
673
-
674
- ```text
675
- -i, --input <file> Input Office / EPUB file
676
- -o, --output <file> Output file
677
- -c, --config <conversion> Conversion config (default: s2t)
678
- -p, --punct Enable punctuation conversion
679
- -f, --format <format> docx | xlsx | pptx | odt | ods | odp | epub
680
- -F, --convert-filename Convert generated output filename stem (default: false)
681
- --keep-font Preserve font-family information (default)
682
- --no-keep-font Do not preserve font-family information
683
- --custom-dict <slot:mode:file>
684
- Load a custom dictionary.
685
- May be specified multiple times.
686
- Examples:
687
- --custom-dict hkphrasesrev:append:my_hk_dict.txt
688
- --custom-dict stphrases:override:terms.txt
689
- ```
690
-
691
- For `office`, the format is inferred from the input file extension when `--format` is omitted.
692
-
693
- If `-o, --output` is omitted, `office` writes:
694
-
695
- ```text
696
- <input-name>_converted.<ext>
697
- ```
698
-
699
- ---
700
-
701
- ## TypeScript Support
702
-
703
- The package includes generated TypeScript definitions from `wasm-bindgen`.
704
-
705
- The WASM-facing enum is exported as `OpenccConfigWasm`, alongside `OpenccWasm`.
706
-
707
- `OpenccConfigWasm.S2hkp`, `OpenccConfigWasm.Hk2sp`, `OpenccConfigWasm.T2hkp`, and
708
- `OpenccConfigWasm.Hk2tp` are available for Hong Kong phrase conversions and map to backend config IDs `17` through `20`.
709
-
710
- ---
711
-
712
- ## Performance Notes
713
-
714
- * WebAssembly build disables Rayon parallelism by default.
715
- * Dictionaries are embedded into the WASM binary.
716
- * Browser caching significantly improves subsequent loads.
717
-
718
- ---
719
-
720
- ## Related Projects
721
-
722
- * Rust backend: https://github.com/laisuk/opencc-fmmseg
723
- * C API: https://github.com/laisuk/opencc-fmmseg/tree/master/capi/opencc-fmmseg-capi
724
- * .NET: https://github.com/laisuk/OpenccNet
725
- * Python: https://github.com/laisuk/opencc_purepy
726
-
727
- ---
728
-
729
- ## License
730
-
731
- MIT
1
+ # opencc-fmmseg-wasm
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@laisuk/opencc-fmmseg-wasm)](https://www.npmjs.com/package/@laisuk/opencc-fmmseg-wasm)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@laisuk/opencc-fmmseg-wasm)](https://www.npmjs.com/package/@laisuk/opencc-fmmseg-wasm)
5
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
6
+ [![WebAssembly](https://img.shields.io/badge/WebAssembly-enabled-blue)](https://webassembly.org/)
7
+
8
+ OpenCC FMM segmentation WebAssembly bindings for browsers and JavaScript runtimes.
9
+
10
+ This package provides high-quality Simplified Chinese ↔ Traditional Chinese conversion powered by the Rust [
11
+ `opencc-fmmseg`](https://github.com/laisuk/opencc-fmmseg) engine.
12
+
13
+ Features:
14
+
15
+ * OpenCC-compatible conversion configs
16
+ * Pure WebAssembly (no native binaries)
17
+ * Browser-friendly
18
+ * TypeScript-friendly APIs
19
+ * Fast Rust backend
20
+ * FMM-based phrase segmentation
21
+ * Traditional Chinese regional variants
22
+ * Japanese Shinjitai conversion support
23
+ * Chinese script detection (`zho_check`)
24
+ * Optional CJK Compatibility Ideograph normalization
25
+ * In-memory Office / EPUB document conversion
26
+ * Zero-dependency Node.js CLI
27
+
28
+ Package profile:
29
+
30
+ * 0 runtime dependencies
31
+ * 1 WASM file
32
+ * 18 conversion configs
33
+ * 100% offline
34
+
35
+ ---
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ npm install @laisuk/opencc-fmmseg-wasm
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Quick Start
46
+
47
+ ```javascript
48
+ import init, {
49
+ OpenccWasm,
50
+ DetofuLevelWasm
51
+ } from "@laisuk/opencc-fmmseg-wasm";
52
+
53
+ await init();
54
+
55
+ const cc = new OpenccWasm("s2t");
56
+
57
+ console.log(cc.convert("汉字", false));
58
+ // 漢字
59
+
60
+ console.log(cc.convertDetofu("儼驂騑於上路", false, DetofuLevelWasm.ExtB));
61
+ // 俨骖騑于上路
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Using Config Enums
67
+
68
+ ```javascript
69
+ import init, {
70
+ OpenccWasm,
71
+ OpenccConfigWasm
72
+ } from "@laisuk/opencc-fmmseg-wasm";
73
+
74
+ await init();
75
+
76
+ const cc = OpenccWasm.newWithEnum(
77
+ OpenccConfigWasm.S2hkp
78
+ );
79
+
80
+ console.log(cc.convert("别随便录影侵犯个人隐私权", false));
81
+ // 別隨便錄影侵犯個人私隱權
82
+ ```
83
+
84
+ ---
85
+
86
+ ## Supported Configs
87
+
88
+ | Config | Enum | Description |
89
+ |---------|--------------------------|-------------------------------------------------------|
90
+ | `s2t` | `OpenccConfigWasm.S2t` | Simplified Chinese → Traditional Chinese |
91
+ | `s2tw` | `OpenccConfigWasm.S2tw` | Simplified Chinese → Taiwan Traditional |
92
+ | `s2twp` | `OpenccConfigWasm.S2twp` | Simplified Chinese → Taiwan Traditional (phrases) |
93
+ | `s2hk` | `OpenccConfigWasm.S2hk` | Simplified Chinese → Hong Kong Traditional |
94
+ | `s2hkp` | `OpenccConfigWasm.S2hkp` | Simplified Chinese → Hong Kong Traditional (phrases) |
95
+ | `t2s` | `OpenccConfigWasm.T2s` | Traditional Chinese → Simplified Chinese |
96
+ | `t2tw` | `OpenccConfigWasm.T2tw` | Traditional Chinese → Taiwan Traditional |
97
+ | `t2twp` | `OpenccConfigWasm.T2twp` | Traditional Chinese → Taiwan Traditional (phrases) |
98
+ | `t2hk` | `OpenccConfigWasm.T2hk` | Traditional Chinese → Hong Kong Traditional |
99
+ | `t2hkp` | `OpenccConfigWasm.T2hkp` | Traditional Chinese → Hong Kong Traditional (phrases) |
100
+ | `tw2s` | `OpenccConfigWasm.Tw2s` | Taiwan Traditional → Simplified Chinese |
101
+ | `tw2sp` | `OpenccConfigWasm.Tw2sp` | Taiwan Traditional → Simplified Chinese (phrases) |
102
+ | `tw2t` | `OpenccConfigWasm.Tw2t` | Taiwan Traditional → Traditional Chinese |
103
+ | `tw2tp` | `OpenccConfigWasm.Tw2tp` | Taiwan Traditional → Traditional Chinese (phrases) |
104
+ | `hk2s` | `OpenccConfigWasm.Hk2s` | Hong Kong Traditional → Simplified Chinese |
105
+ | `hk2sp` | `OpenccConfigWasm.Hk2sp` | Hong Kong Traditional → Simplified Chinese (phrases) |
106
+ | `hk2t` | `OpenccConfigWasm.Hk2t` | Hong Kong Traditional → Traditional Chinese |
107
+ | `hk2tp` | `OpenccConfigWasm.Hk2tp` | Hong Kong Traditional → Traditional Chinese (phrases) |
108
+ | `jp2t` | `OpenccConfigWasm.Jp2t` | Japanese Shinjitai → Traditional Chinese |
109
+ | `t2jp` | `OpenccConfigWasm.T2jp` | Traditional Chinese → Japanese Shinjitai |
110
+
111
+ The numeric enum values match the vendored Rust backend. Existing values are unchanged; `S2hkp = 17`, `Hk2sp = 18`,
112
+ `T2hkp = 19`, and `Hk2tp = 20`.
113
+
114
+ ---
115
+
116
+ ## API
117
+
118
+ ### Constructor
119
+
120
+ ```javascript
121
+ const cc = new OpenccWasm("s2t");
122
+ ```
123
+
124
+ Parameters:
125
+
126
+ * `config` (optional): OpenCC config string
127
+ * default: `"s2t"`
128
+
129
+ Example:
130
+
131
+ ```javascript
132
+ const cc = new OpenccWasm("t2s");
133
+ ```
134
+
135
+ Hong Kong phrase config example:
136
+
137
+ ```javascript
138
+ const cc = new OpenccWasm("s2hkp");
139
+
140
+ cc.convert("别随便录影侵犯个人隐私权", false);
141
+ // 別隨便錄影侵犯個人私隱權
142
+ ```
143
+
144
+ ---
145
+
146
+ ### convert
147
+
148
+ ```javascript
149
+ cc.convert(text, punctuation)
150
+ ```
151
+
152
+ Parameters:
153
+
154
+ * `text`: input string
155
+ * `punctuation`: whether to convert punctuation variants
156
+
157
+ Returns:
158
+
159
+ * converted string
160
+
161
+ Example:
162
+
163
+ ```javascript
164
+ cc.convert("汉字", false);
165
+ ```
166
+
167
+ ---
168
+
169
+ ### normalizeCompat
170
+
171
+ Normalize Unicode CJK Compatibility Ideographs before conversion.
172
+
173
+ ```javascript
174
+ cc.normalizeCompat(text)
175
+ ```
176
+
177
+ Parameters:
178
+
179
+ * `text`: input string
180
+
181
+ Returns:
182
+
183
+ * normalized string
184
+
185
+ Example:
186
+
187
+ ```javascript
188
+ const cc = new OpenccWasm("t2s");
189
+
190
+ const input = "天龍八部書裡的喬峰是契丹人";
191
+ const normalized = cc.normalizeCompat(input);
192
+
193
+ console.log(normalized);
194
+ // 天龍八部書裡的喬峰是契丹人
195
+
196
+ console.log(cc.convert(normalized, false));
197
+ // 天龙八部书里的乔峰是契丹人
198
+ ```
199
+
200
+ This is an optional pre-conversion pass for text that contains compatibility ideographs from Unicode compatibility
201
+ ranges. Unmapped characters are preserved unchanged. Normal OpenCC conversion does not automatically run this pass, so
202
+ call it explicitly when compatibility normalization is desired.
203
+
204
+ ---
205
+
206
+ ### detofu
207
+
208
+ Replace tofu-risk rare CJK extension characters with display-compatible fallbacks.
209
+
210
+ ```javascript
211
+ cc.detofu(text, level)
212
+ ```
213
+
214
+ Parameters:
215
+
216
+ * `text`: input string
217
+ * `level`: `DetofuLevelWasm` threshold for the CJK extension ranges to replace
218
+
219
+ Returns:
220
+
221
+ * detofu-safe string
222
+
223
+ Supported levels:
224
+
225
+ | Enum | CLI value |
226
+ |------------------------|-----------|
227
+ | `DetofuLevelWasm.ExtB` | `ext-b` |
228
+ | `DetofuLevelWasm.ExtC` | `ext-c` |
229
+ | `DetofuLevelWasm.ExtD` | `ext-d` |
230
+ | `DetofuLevelWasm.ExtE` | `ext-e` |
231
+ | `DetofuLevelWasm.ExtF` | `ext-f` |
232
+ | `DetofuLevelWasm.ExtG` | `ext-g` |
233
+ | `DetofuLevelWasm.ExtH` | `ext-h` |
234
+ | `DetofuLevelWasm.ExtI` | `ext-i` |
235
+
236
+ Example:
237
+
238
+ ```javascript
239
+ import init, {
240
+ OpenccWasm,
241
+ DetofuLevelWasm
242
+ } from "@laisuk/opencc-fmmseg-wasm";
243
+
244
+ await init();
245
+
246
+ const cc = new OpenccWasm("t2s");
247
+ const converted = cc.convert("儼驂騑於上路", false);
248
+
249
+ console.log(converted);
250
+ // 俨骖𬴂于上路
251
+
252
+ console.log(cc.detofu(converted, DetofuLevelWasm.ExtB));
253
+ // 俨骖騑于上路
254
+ ```
255
+
256
+ ---
257
+
258
+ ### convertDetofu
259
+
260
+ Convert text and apply detofu in one call.
261
+
262
+ ```javascript
263
+ cc.convertDetofu(text, punctuation, level)
264
+ ```
265
+
266
+ Parameters:
267
+
268
+ * `text`: input string
269
+ * `punctuation`: whether to convert punctuation variants
270
+ * `level`: `DetofuLevelWasm` threshold for the CJK extension ranges to replace
271
+
272
+ Returns:
273
+
274
+ * converted detofu-safe string
275
+
276
+ Example:
277
+
278
+ ```javascript
279
+ cc.convertDetofu("儼驂騑於上路", false, DetofuLevelWasm.ExtB);
280
+ // 俨骖騑于上路
281
+ ```
282
+
283
+ ---
284
+
285
+ ### setConfig
286
+
287
+ ```javascript
288
+ cc.setConfig("t2s");
289
+ ```
290
+
291
+ Returns:
292
+
293
+ * `true` if valid
294
+ * `false` if invalid
295
+
296
+ ---
297
+
298
+ ### getConfig
299
+
300
+ ```javascript
301
+ cc.getConfig();
302
+ ```
303
+
304
+ Returns current config string.
305
+
306
+ ---
307
+
308
+ ### isValidConfig
309
+
310
+ ```javascript
311
+ OpenccWasm.isValidConfig("s2t");
312
+ ```
313
+
314
+ ---
315
+
316
+ ### getSupportedConfigs
317
+
318
+ ```javascript
319
+ OpenccWasm.getSupportedConfigs();
320
+ ```
321
+
322
+ Returns all supported config strings.
323
+
324
+ Includes `s2hkp`, `hk2sp`, `t2hkp`, and `hk2tp`.
325
+
326
+ ---
327
+
328
+ ### getAvailableSlots
329
+
330
+ ```javascript
331
+ const slots = OpenccWasm.getAvailableSlots();
332
+ ```
333
+
334
+ Returns all canonical dictionary slot names accepted by `newWithCustomDicts` as a string array. The list is sourced from
335
+ the core `DictSlot` definitions, so callers can use it to populate selectors or validate custom dictionary input without
336
+ maintaining their own slot list.
337
+
338
+ ```javascript
339
+ if (!OpenccWasm.getAvailableSlots().includes(slot)) {
340
+ throw new Error(`Unsupported dictionary slot: ${slot}`);
341
+ }
342
+ ```
343
+
344
+ ---
345
+
346
+ ### zhoCheck
347
+
348
+ Detect Chinese script type.
349
+
350
+ ```javascript
351
+ cc.zhoCheck(text);
352
+ ```
353
+
354
+ Returns:
355
+
356
+ | Value | Meaning |
357
+ |-------|---------------------|
358
+ | `0` | Unknown / mixed |
359
+ | `1` | Traditional Chinese |
360
+ | `2` | Simplified Chinese |
361
+
362
+ ---
363
+
364
+ ### newWithCustomDicts
365
+
366
+ Construct a converter with in-memory custom dictionary pairs.
367
+
368
+ ```javascript
369
+ const cc = OpenccWasm.newWithCustomDicts(config, specs);
370
+ ```
371
+
372
+ Parameters:
373
+
374
+ * `config`: OpenCC config string, such as `"s2t"`
375
+ * `specs`: array of custom dictionary specs
376
+
377
+ TypeScript-style spec shape:
378
+
379
+ ```typescript
380
+ type WasmCustomDictSpec = {
381
+ slot: string;
382
+ mode?: "Append" | "Override";
383
+ pairs: Array<[string, string]>;
384
+ };
385
+ ```
386
+
387
+ `mode` defaults to `"Append"` when omitted.
388
+
389
+ Each `pairs` entry is a `[source, target]` string tuple for the selected slot.
390
+
391
+ TypeScript example:
392
+
393
+ ```typescript
394
+ import init, {OpenccWasm} from "@laisuk/opencc-fmmseg-wasm";
395
+
396
+ await init();
397
+
398
+ const specs: WasmCustomDictSpec[] = [
399
+ {
400
+ slot: "STPhrases",
401
+ pairs: [
402
+ ["云端", "雲端"]
403
+ ]
404
+ }
405
+ ];
406
+
407
+ const cc = OpenccWasm.newWithCustomDicts("s2t", specs);
408
+ ```
409
+
410
+ Practical example:
411
+
412
+ ```javascript
413
+ import init, {OpenccWasm} from "@laisuk/opencc-fmmseg-wasm";
414
+
415
+ await init();
416
+
417
+ const cc = OpenccWasm.newWithCustomDicts("s2t", [
418
+ {
419
+ slot: "STPhrases",
420
+ mode: "Append",
421
+ pairs: [
422
+ ["帕兰蒂尔", "柏蘭蒂爾"],
423
+ ["软件", "軟體"]
424
+ ]
425
+ }
426
+ ]);
427
+
428
+ console.log(cc.convert("帕兰蒂尔软件", false));
429
+ // 柏蘭蒂爾軟體
430
+ ```
431
+
432
+ Override example:
433
+
434
+ ```javascript
435
+ const cc = OpenccWasm.newWithCustomDicts("s2t", [
436
+ {
437
+ slot: "STPhrases",
438
+ mode: "Override",
439
+ pairs: [
440
+ ["软件", "軟體"]
441
+ ]
442
+ }
443
+ ]);
444
+ ```
445
+
446
+ `Override` replaces the selected slot before inserting the provided pairs. It is powerful and should be used only when
447
+ the caller intentionally wants to discard built-in entries for that slot.
448
+
449
+ Custom dictionary specs identify the target dictionary slot by `DictSlot` name. Slot names are trimmed and matched
450
+ case-insensitively, so `"stphrases"`, `" STPhrases "`, and `"STPhrases"` all select `STPhrases`. Canonical names are
451
+ recommended in TypeScript code and docs; use `OpenccWasm.getAvailableSlots()` to retrieve the current list.
452
+
453
+ Suffixes such as `.txt` are not accepted, even though case and surrounding whitespace are normalized. Use
454
+ `"STPhrases"` or `"stphrases"`, not `"STPhrases.txt"`.
455
+
456
+ Merge contract:
457
+
458
+ * Custom dictionaries are loaded from in-memory pairs only; no file I/O is involved.
459
+ * The embedded compressed CBOR dictionary is loaded first.
460
+ * Custom specs are applied to `DictionaryMaxlength` before `OpenCC::from_dictionary(...)`.
461
+ * Conversion hot paths remain immutable after construction.
462
+ * `Append` mode merges into the selected slot.
463
+ * Duplicate or conflicting keys use last-wins semantics.
464
+ * `Override` mode clears the selected slot first, then inserts the provided custom pairs.
465
+ * Multiple specs are applied in array order.
466
+
467
+ This API is useful for browser apps, user-defined terminology, database-loaded terms, generated dictionaries,
468
+ `localStorage` or `IndexedDB` terms, testing, and embedded WASM environments. Customization happens at construction
469
+ time, not during conversion.
470
+
471
+ ---
472
+
473
+ ## Office / EPUB Conversion
474
+
475
+ Office and EPUB conversion runs fully locally in the browser or Node.js. Files are passed in and returned as bytes;
476
+ nothing is uploaded to a backend server.
477
+
478
+ This is useful for converting text inside:
479
+
480
+ ```text
481
+ docx, xlsx, pptx, odt, ods, odp, epub
482
+ ```
483
+
484
+ File size is limited by available browser or Node.js memory, but there is no upload or server-side limit. Font
485
+ preservation is supported with the `keepFont` option.
486
+
487
+ Use the instance method when possible. It reuses the converter configuration and any custom dictionaries already held by
488
+ the `OpenccWasm` instance.
489
+
490
+ ```javascript
491
+ cc.convertOfficeBytes(inputBytes, format, punctuation, keepFont)
492
+ ```
493
+
494
+ Parameters:
495
+
496
+ * `inputBytes`: `Uint8Array` document bytes
497
+ * `format`: `docx`, `xlsx`, `pptx`, `odt`, `ods`, `odp`, or `epub`
498
+ * `punctuation`: whether to convert punctuation variants
499
+ * `keepFont`: whether to preserve font declarations where supported
500
+
501
+ Returns:
502
+
503
+ * converted output bytes
504
+
505
+ The older free function remains available for compatibility:
506
+
507
+ ```javascript
508
+ convert_office_bytes(inputBytes, format, config, punctuation, keepFont)
509
+ ```
510
+
511
+ ### Browser Office Example
512
+
513
+ ```javascript
514
+ import init, {OpenccWasm} from "@laisuk/opencc-fmmseg-wasm";
515
+
516
+ await init();
517
+
518
+ const cc = new OpenccWasm("s2t");
519
+ const file = document.querySelector("input[type=file]").files[0];
520
+ const inputBytes = new Uint8Array(await file.arrayBuffer());
521
+
522
+ const outputBytes = cc.convertOfficeBytes(
523
+ inputBytes,
524
+ "docx",
525
+ true,
526
+ true
527
+ );
528
+
529
+ const blob = new Blob([outputBytes], {
530
+ type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
531
+ });
532
+
533
+ const a = document.createElement("a");
534
+ a.href = URL.createObjectURL(blob);
535
+ a.download = "converted.docx";
536
+ a.click();
537
+ URL.revokeObjectURL(a.href);
538
+ ```
539
+
540
+ ### Node.js Office Example
541
+
542
+ ```javascript
543
+ import fs from "fs";
544
+ import init, {OpenccWasm} from "@laisuk/opencc-fmmseg-wasm";
545
+
546
+ await init();
547
+
548
+ const cc = new OpenccWasm("s2t");
549
+ const inputBytes = fs.readFileSync("input.docx");
550
+
551
+ const outputBytes = cc.convertOfficeBytes(
552
+ inputBytes,
553
+ "docx",
554
+ true,
555
+ true
556
+ );
557
+
558
+ fs.writeFileSync("output.docx", outputBytes);
559
+ ```
560
+
561
+ ---
562
+
563
+ ## Browser Example
564
+
565
+ ```html
566
+ <!DOCTYPE html>
567
+ <html lang="en">
568
+ <head>
569
+ <meta charset="UTF-8">
570
+ <title>OpenCC WASM Demo</title>
571
+ </head>
572
+ <body>
573
+
574
+ <script type="module">
575
+ import init, {
576
+ OpenccWasm
577
+ } from "./pkg/opencc_fmmseg_wasm.js";
578
+
579
+ await init();
580
+
581
+ const cc = new OpenccWasm("s2t");
582
+
583
+ console.log(
584
+ cc.convert("汉字", false)
585
+ );
586
+ </script>
587
+
588
+ </body>
589
+ </html>
590
+ ```
591
+
592
+ > **Note**
593
+ >
594
+ > Normally, `await init();` is sufficient when using the published npm package.
595
+ >
596
+ > When running directly from a local repository checkout (for example in tests
597
+ > or development scripts), initialize using explicit WASM bytes:
598
+ >
599
+ > ```javascript
600
+ > import fs from "fs";
601
+ > import init from "../pkg/opencc_fmmseg_wasm.js";
602
+ >
603
+ > const wasmBytes = fs.readFileSync(
604
+ > "../pkg/opencc_fmmseg_wasm_bg.wasm"
605
+ > );
606
+ >
607
+ > await init({
608
+ > module_or_path: wasmBytes
609
+ > });
610
+ > ```
611
+
612
+ ---
613
+
614
+ ## Node.js CLI
615
+
616
+ The package includes a zero-dependency Node.js CLI:
617
+
618
+ ```bash
619
+ opencc-fmmseg convert -i input.txt -o output.txt -c s2t -p
620
+ opencc-fmmseg convert -i input.txt -o output.txt -c t2s -p --detofu all
621
+ echo "别随便录影侵犯个人隐私权" | opencc-fmmseg convert -c s2hkp
622
+ echo "天龍八部書裡的喬峰是契丹人" | opencc-fmmseg convert -c t2s --norm-compat
623
+ // 天龙八部书里的乔峰是契丹人
624
+ echo "這個細路哥很靈活" | opencc-fmmseg convert -c hk2sp --custom-dict hkphrasesrev:append:my_hk_dict.txt
625
+ // 这个小男孩很灵活
626
+ ```
627
+
628
+ my_hk_dict.txt:
629
+
630
+ ```
631
+ # Custom Dictionary
632
+
633
+ 細路哥 小男孩
634
+ ```
635
+
636
+ ```bash
637
+ opencc-fmmseg office -i input.docx -o output.docx -c s2t -p --keep-font
638
+ ```
639
+
640
+ ### Text Conversion Options
641
+
642
+ ```text
643
+ -i, --input <file> Input text file; stdin if omitted
644
+ -o, --output <file> Output text file; stdout if omitted
645
+ -c, --config <conversion> Conversion config (default: s2t)
646
+ -p, --punct Enable punctuation conversion
647
+ --detofu [level] Replace tofu-risk rare CJK extension chars after conversion
648
+ level: all | ext-b | ext-c | ext-d | ext-e | ext-f | ext-g | ext-h | ext-i
649
+ default when omitted value: all
650
+ --keep-ids Preserve complete IDS expressions during conversion (default: false)
651
+ -n, --norm-compat Normalize CJK Compatibility Ideographs before conversion (default: false)
652
+ -D, --custom-dict <slot:mode:file>
653
+ Load a custom dictionary.
654
+ May be specified multiple times.
655
+ Examples:
656
+ --custom-dict hkphrasesrev:append:my_hk_dict.txt
657
+ --custom-dict stphrases:override:terms.txt
658
+ --in-enc <encoding> Input encoding (default: utf8)
659
+ --out-enc <encoding> Output encoding (default: utf8)
660
+ ```
661
+
662
+ Supported conversion configs:
663
+
664
+ ```text
665
+ s2t, s2tw, s2twp, s2hk, s2hkp, t2s, t2tw, t2twp, t2hk, t2hkp,
666
+ tw2s, tw2sp, tw2t, tw2tp, hk2s, hk2sp, hk2t, hk2tp, jp2t, t2jp
667
+ ```
668
+
669
+ ### Office / EPUB Options
670
+
671
+ ```text
672
+ -i, --input <file> Input Office / EPUB file
673
+ -o, --output <file> Output file
674
+ -c, --config <conversion> Conversion config (default: s2t)
675
+ -p, --punct Enable punctuation conversion
676
+ -f, --format <format> docx | xlsx | pptx | odt | ods | odp | epub
677
+ -F, --convert-filename Convert generated output filename stem (default: false)
678
+ --keep-font Preserve font-family information (default)
679
+ --no-keep-font Do not preserve font-family information
680
+ --custom-dict <slot:mode:file>
681
+ Load a custom dictionary.
682
+ May be specified multiple times.
683
+ Examples:
684
+ --custom-dict hkphrasesrev:append:my_hk_dict.txt
685
+ --custom-dict stphrases:override:terms.txt
686
+ ```
687
+
688
+ For `office`, the format is inferred from the input file extension when `--format` is omitted.
689
+
690
+ If `-o, --output` is omitted, `office` writes:
691
+
692
+ ```text
693
+ <input-name>_converted.<ext>
694
+ ```
695
+
696
+ ---
697
+
698
+ ## TypeScript Support
699
+
700
+ The package includes generated TypeScript definitions from `wasm-bindgen`.
701
+
702
+ The WASM-facing enum is exported as `OpenccConfigWasm`, alongside `OpenccWasm`.
703
+
704
+ `OpenccConfigWasm.S2hkp`, `OpenccConfigWasm.Hk2sp`, `OpenccConfigWasm.T2hkp`, and
705
+ `OpenccConfigWasm.Hk2tp` are available for Hong Kong phrase conversions and map to backend config IDs `17` through `20`.
706
+
707
+ ---
708
+
709
+ ## Performance Notes
710
+
711
+ * WebAssembly build disables Rayon parallelism by default.
712
+ * Dictionaries are embedded into the WASM binary.
713
+ * Browser caching significantly improves subsequent loads.
714
+
715
+ ---
716
+
717
+ ## Related Projects
718
+
719
+ * Rust backend: https://github.com/laisuk/opencc-fmmseg
720
+ * C API: https://github.com/laisuk/opencc-fmmseg/tree/master/capi/opencc-fmmseg-capi
721
+ * .NET: https://github.com/laisuk/OpenccNet
722
+ * Python: https://github.com/laisuk/opencc_purepy
723
+
724
+ ---
725
+
726
+ ## License
727
+
728
+ MIT