lyric-romanizer 0.2.0 → 0.3.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.
- package/CHANGELOG.md +40 -0
- package/README.md +97 -31
- package/dist/detector.d.ts +74 -0
- package/dist/detector.d.ts.map +1 -1
- package/dist/detector.js +73 -23
- package/dist/detector.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/romanizer.d.ts +7 -2
- package/dist/romanizer.d.ts.map +1 -1
- package/dist/romanizer.js +173 -115
- package/dist/romanizer.js.map +1 -1
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/docs/README.hi.md +296 -0
- package/docs/README.ja.md +296 -0
- package/docs/README.ko.md +296 -0
- package/docs/README.ru.md +296 -0
- package/docs/README.ta.md +296 -0
- package/docs/README.th.md +296 -0
- package/docs/README.zh-CN.md +296 -0
- package/docs/README.zh-yue.md +306 -0
- package/docs/adr/0001-outputs-are-a-contract.md +21 -0
- package/docs/adr/0002-whole-array-script-pinning.md +26 -0
- package/docs/adr/0003-zero-api-default-injectable-engines.md +22 -0
- package/docs/adr/0004-no-unified-variant-seam.md +23 -0
- package/docs/adr/0005-always-latest-dependencies.md +23 -0
- package/package.json +13 -6
- package/src/detector.ts +127 -0
- package/src/index.ts +18 -0
- package/src/romanizer.ts +240 -0
- package/src/shims.d.ts +3 -0
- package/src/types.ts +75 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.3.0 — 2026-07-25
|
|
4
|
+
|
|
5
|
+
Architecture pass: every piece of per-script knowledge now lives in one table per side of the light/heavy packaging seam, engines are lazy and injectable, and the universal fallback is observable. Public interface changes are **additive**; the two deliberate output-behavior changes are listed below with their rationale.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Engine adapters** — `createRomanizer({ engines })` overrides any built-in engine or plugs an adapter for externally-romanized scripts (`arabic`, `hebrew`, `malayalam`, `bengali`, `other`). The library still performs zero network I/O by default; `UnsupportedRomanizationError` is now precisely "no engine for this script".
|
|
10
|
+
- **`RomanizeResult.fallbacks`** — per-line flags, `true` where the script engine failed and the line was universally transliterated as a last resort. Previously this degradation was silent and indistinguishable from success.
|
|
11
|
+
- **`requiresExternalRomanization` on the detector subpath** — pure classification moved to the light, engine-free side; `lyric-romanizer/detector` can now answer the full pre-romanization triage (which script → is it latin → needs external) with zero engine payload. Still re-exported from the main entry.
|
|
12
|
+
- **`RomanizeEngine`, `RomanizeEngineContext`, `ExternalScript`** exported types.
|
|
13
|
+
- **Plain Node ESM support** — `import 'lyric-romanizer'` previously crashed outside bundlers (`@romanize/korean` named-export interop); engines now load through interop-safe dynamic imports.
|
|
14
|
+
- **Lazy engine loading** — every engine loads on first use. Importing the main entry no longer executes any engine package; a Korean-only consumer never loads pinyin-pro or kuroshiro. Failed loads retry on the next call and degrade to the universal fallback (flagged) rather than crashing playback.
|
|
15
|
+
|
|
16
|
+
### Changed — deliberate output-behavior changes
|
|
17
|
+
|
|
18
|
+
1. **Latin guard under a pinned script.** `romanizeLines` pins one script for the whole array; lines with ASCII letters and no character of any detectable script are now returned unchanged instead of being fed to the pinned engine. Before: `romanizeLines(['Hello', '世界'])` → `['H e l l o', 'shì jiè']` (pinyin-pro spaces out Latin text). After: `['Hello', 'shì jiè']`. Rationale: the engine cannot romanize what isn't its script; the old output was mangled.
|
|
19
|
+
2. **Out-of-contract script strings throw.** Untyped callers pinning a string outside `ScriptType` (e.g. `{ script: 'greek' }`) now get `UnsupportedRomanizationError` instead of a silent universal transliteration. This includes names inherited from `Object.prototype`: `{ script: 'toString' }` previously resolved to the inherited method and returned `'[object Undefined]'`. Unaffected: auto-detected scripts (detection only ever returns `ScriptType` members), and empty or letterless lines, which short-circuit to a no-op before any script is consulted — as they always did.
|
|
20
|
+
|
|
21
|
+
All romanized output strings are byte-identical to 0.2.0 apart from those two cases, verified against a golden corpus across every supported script, dialect, preset, and error path. Two further notes for anyone diffing behavior:
|
|
22
|
+
|
|
23
|
+
- `romanizeLine` with an engineless pinned script (e.g. `{ script: 'arabic' }`) still throws even when the line is pure Latin — the engine check precedes the latin guard, matching `romanizeLines`, which rejects such a script before looking at any line.
|
|
24
|
+
- `NON_LATIN_SCRIPT_RE` is now derived from the range table, so its `.source` text changed: ranges are emitted in ascending code-point order, and the adjacent Hebrew and Arabic ranges collapse into one (8 groups → 7). The matching contract is unchanged — `.flags` is still `''` and `.test()` agrees with the old literal for every code point in the BMP, asserted by a test sweep. Only a consumer that snapshots, hashes, or string-compares the pattern text is affected; one that uses it as a matcher is not.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- README Quick Start example was impossible: `romanizeLines(['你好世界', 'こんにちは'])` returns `{ script: 'japanese' }` (kana is definitive), not `{ script: 'chinese' }` as documented. The example and the detection-granularity contract are now documented accurately.
|
|
29
|
+
- Documented romanization outputs corrected against the actual engines (in all nine READMEs): Thai `สวัสดี` → `swasdi` (was `sawatdi`), Gurmukhi `ਨਮਸਤੇ` → `namasate` (was `namaste`; standard Punjabi spelling has no virama, so both consonants keep the inherent vowel), and the Kannada sample is now the correctly-spelled `ನಮಸ್ತೇ` → `namaste`. The feature list said "7 Indic scripts"; there are 6.
|
|
30
|
+
- Dead defensive throws in the Sanscript branch (unreachable behind the catch-all fallback) removed; the silent `default:` switch arm is gone — the engine table is total over the script union, so a forgotten engine row is a **compile error** instead of silent garbage.
|
|
31
|
+
- `NON_LATIN_SCRIPT_RE` is now derived from the same per-script range table that drives detection (previously a hand-maintained duplicate with a "keep aligned" comment). Verified byte-for-byte identical across the BMP.
|
|
32
|
+
|
|
33
|
+
### Internal
|
|
34
|
+
|
|
35
|
+
- Per-script knowledge concentrated: detection ranges + external classification in `SCRIPT_METADATA` (detector side), engine bindings in one total record (romanizer side). Adding a script is one row per side, compiler-enforced.
|
|
36
|
+
- `selectCyrillicPreset` extracted as a pure, unit-tested function (the Ukrainian-detection headline feature previously had zero coverage).
|
|
37
|
+
- Dependencies updated to latest (TypeScript 7, vitest 4.1.10, pinyin-pro 3.28.2). CI, Dependabot (daily, grouped), and a weekly latest-deps canary keep every engine on its newest release.
|
|
38
|
+
- Test suite grew from 19 to 44 tests: injection seam, fallback observability, lazy-init retry, preset selection, latin guard, regex-derivation equivalence, tie-break regression, BMP-range invariant.
|
|
39
|
+
- `pnpm run smoke` (`scripts/smoke.mjs`) exercises the built package under plain Node ESM: every engine's interop chain, the fallback path, both entry points, and an assertion that `dist/detector.js` imports nothing. Runs in CI and in the canary; `pnpm run verify` chains typecheck + build + test + smoke.
|
|
40
|
+
- `package.json` declares `"sideEffects": false` (safe now that engines are lazy) and ships `src` so the published source maps resolve.
|
package/README.md
CHANGED
|
@@ -3,10 +3,28 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/lyric-romanizer)
|
|
4
4
|
[](https://github.com/thedavidweng/lyric-romanizer/blob/main/LICENSE)
|
|
5
5
|
|
|
6
|
+
[English](https://github.com/thedavidweng/lyric-romanizer#readme) | [日本語](https://github.com/thedavidweng/lyric-romanizer/blob/main/docs/README.ja.md) | [中文(简体)](https://github.com/thedavidweng/lyric-romanizer/blob/main/docs/README.zh-CN.md) | [中文(粵語)](https://github.com/thedavidweng/lyric-romanizer/blob/main/docs/README.zh-yue.md) | [한국어](https://github.com/thedavidweng/lyric-romanizer/blob/main/docs/README.ko.md) | [Русский](https://github.com/thedavidweng/lyric-romanizer/blob/main/docs/README.ru.md) | [हिन्दी](https://github.com/thedavidweng/lyric-romanizer/blob/main/docs/README.hi.md) | [தமிழ்](https://github.com/thedavidweng/lyric-romanizer/blob/main/docs/README.ta.md) | [ไทย](https://github.com/thedavidweng/lyric-romanizer/blob/main/docs/README.th.md)
|
|
7
|
+
|
|
8
|
+
> **Philosophy: Don't reinvent the wheel.**
|
|
9
|
+
> This project deliberately avoids building romanization logic from scratch. Instead, it composes best-in-class, community-maintained libraries — one for each script — and focuses on the orchestration layer: script detection, engine routing, dialect handling, and a unified API. Every romanization engine in the dependency list is a dedicated, battle-tested library maintained by domain experts. That's the point.
|
|
10
|
+
|
|
6
11
|
Script detection and local romanization engine for lyrics. Supports 12 scripts across Japanese, Chinese (Mandarin and Cantonese), Korean, Cyrillic, Indic, Tamil, and Thai — all running locally with zero API calls.
|
|
7
12
|
|
|
8
13
|
Extracted from [Spotify Karaoke](https://github.com/haroldalan/spotify-karaoke). Used by [OpenKara](https://github.com/thedavidweng/openkara).
|
|
9
14
|
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Zero API calls** — all romanization runs locally
|
|
18
|
+
- **Auto script detection** — pass in text, get back the detected script
|
|
19
|
+
- **12+ scripts** — Japanese, Chinese, Korean, Cyrillic, 6 Indic scripts, Tamil, Thai
|
|
20
|
+
- **Cantonese support** — Jyutping alongside default Mandarin Pinyin
|
|
21
|
+
- **Lightweight detector subpath** — import only script detection (and external-script classification) without pulling in romanization engines
|
|
22
|
+
- **Lazy engines** — every engine loads on first use; importing the main entry costs nothing until you romanize
|
|
23
|
+
- **Pluggable engines** — override any built-in engine, or plug your own adapter for externally-romanized scripts
|
|
24
|
+
- **Observable fallbacks** — per-line flags tell you when an engine failed and a line was transliterated as a last resort
|
|
25
|
+
- **Ukrainian-aware Cyrillic** — auto-detects Ukrainian-specific characters and applies the correct transliteration preset
|
|
26
|
+
- **Runs in plain Node ESM** — no bundler required
|
|
27
|
+
|
|
10
28
|
## Installation
|
|
11
29
|
|
|
12
30
|
```bash
|
|
@@ -29,14 +47,16 @@ import { createRomanizer, detectScript } from 'lyric-romanizer';
|
|
|
29
47
|
const romanizer = createRomanizer();
|
|
30
48
|
|
|
31
49
|
// Auto-detect script and romanize
|
|
32
|
-
const result = await romanizer.romanizeLines(['你好世界', '
|
|
33
|
-
// { script: 'chinese', lines: ['nǐ hǎo shì jiè', '
|
|
50
|
+
const result = await romanizer.romanizeLines(['你好世界', '很高兴认识你']);
|
|
51
|
+
// { script: 'chinese', lines: ['nǐ hǎo shì jiè', 'hěn gāo xìng rèn shi nǐ'], fallbacks: [false, false] }
|
|
34
52
|
|
|
35
53
|
// Romanize a single line
|
|
36
54
|
const line = await romanizer.romanizeLine('안녕하세요');
|
|
37
55
|
// 'annyeonghaseyo'
|
|
38
56
|
```
|
|
39
57
|
|
|
58
|
+
> **Detection granularity** — `romanizeLines` detects the dominant script **once across all lines** and pins it for every line (deliberate: kanji-only lines inside a Japanese song must reach the Japanese engine, and any kana in the array pins `japanese`). Calling `romanizeLine` in a loop instead detects **per line** and may route each line to a different engine. Pure-Latin lines under a pinned script are returned unchanged. See [Mixed-script arrays](#mixed-script-arrays).
|
|
59
|
+
|
|
40
60
|
## API
|
|
41
61
|
|
|
42
62
|
### Imports
|
|
@@ -52,7 +72,12 @@ import {
|
|
|
52
72
|
} from 'lyric-romanizer';
|
|
53
73
|
|
|
54
74
|
// Detector-only subpath — lightweight, no romanization dependencies
|
|
55
|
-
import {
|
|
75
|
+
import {
|
|
76
|
+
detectScript,
|
|
77
|
+
isLatinScript,
|
|
78
|
+
requiresExternalRomanization,
|
|
79
|
+
NON_LATIN_SCRIPT_RE,
|
|
80
|
+
} from 'lyric-romanizer/detector';
|
|
56
81
|
```
|
|
57
82
|
|
|
58
83
|
### Types
|
|
@@ -63,23 +88,33 @@ type ScriptType =
|
|
|
63
88
|
| 'devanagari' | 'gujarati' | 'gurmukhi' | 'telugu'
|
|
64
89
|
| 'kannada' | 'odia' | 'tamil' | 'malayalam'
|
|
65
90
|
| 'bengali' | 'arabic' | 'hebrew' | 'thai'
|
|
66
|
-
| 'other';
|
|
91
|
+
| 'latin' | 'other';
|
|
67
92
|
|
|
68
93
|
interface Romanizer {
|
|
69
94
|
romanizeLine(line: string, options?: RomanizeOptions): Promise<string>;
|
|
70
95
|
romanizeLines(lines: readonly string[], options?: RomanizeOptions): Promise<RomanizeResult>;
|
|
71
96
|
}
|
|
72
97
|
|
|
98
|
+
// `dialect` is only honored for 'chinese'; every other script ignores it.
|
|
73
99
|
type RomanizeOptions = { script?: ScriptType; dialect?: 'mandarin' | 'cantonese' };
|
|
74
|
-
type RomanizeResult = { script: ScriptType; lines: string[] };
|
|
75
|
-
type RomanizerOptions = { japaneseDictPath?: string };
|
|
76
|
-
```
|
|
77
100
|
|
|
78
|
-
|
|
101
|
+
// `fallbacks` is aligned with `lines`: true where the engine failed and the
|
|
102
|
+
// line was universally transliterated as a last resort.
|
|
103
|
+
type RomanizeResult = { script: ScriptType; lines: string[]; fallbacks?: boolean[] };
|
|
79
104
|
|
|
80
|
-
|
|
105
|
+
// An engine adapter: romanizes one line of its script. Throwing (or
|
|
106
|
+
// rejecting) triggers the universal transliteration fallback.
|
|
107
|
+
type RomanizeEngine = (line: string, context: { dialect: 'mandarin' | 'cantonese' }) => string | Promise<string>;
|
|
81
108
|
|
|
82
|
-
|
|
109
|
+
type RomanizerOptions = {
|
|
110
|
+
japaneseDictPath?: string;
|
|
111
|
+
engines?: Partial<Record<ScriptType, RomanizeEngine>>;
|
|
112
|
+
};
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `createRomanizer(options?)`
|
|
116
|
+
|
|
117
|
+
Factory that returns a `Romanizer` instance. Every engine is lazily loaded on first use and cached — a failed load retries on the next call.
|
|
83
118
|
|
|
84
119
|
```ts
|
|
85
120
|
const romanizer = createRomanizer();
|
|
@@ -90,7 +125,27 @@ const romanizer = createRomanizer({
|
|
|
90
125
|
});
|
|
91
126
|
```
|
|
92
127
|
|
|
93
|
-
####
|
|
128
|
+
#### Engine adapters
|
|
129
|
+
|
|
130
|
+
`options.engines` overrides the built-in engine for a script — or plugs an engine into a script that has none built in (`arabic`, `hebrew`, `malayalam`, `bengali`, `other`), so `romanizeLines` can handle every script through one interface. By default the library performs **zero network I/O**; plugging a remote adapter is an explicit caller decision.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
const romanizer = createRomanizer({
|
|
134
|
+
engines: {
|
|
135
|
+
// Bring your own external romanization for scripts without a local engine.
|
|
136
|
+
arabic: async (line) => myTransliterationApi(line),
|
|
137
|
+
// Or replace a built-in engine (e.g. with a fake in tests).
|
|
138
|
+
korean: (line) => myKoreanRomanizer(line),
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
await romanizer.romanizeLines(['مرحبا']);
|
|
143
|
+
// { script: 'arabic', lines: [...], fallbacks: [false] } — no longer throws
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Scripts without an engine — built-in or injected — still throw `UnsupportedRomanizationError`.
|
|
147
|
+
|
|
148
|
+
### `detectScript(lines)`
|
|
94
149
|
|
|
95
150
|
Detects the dominant script in the given text lines. Checks for Japanese kana first (definitive), then scores all other scripts by character count.
|
|
96
151
|
|
|
@@ -102,7 +157,7 @@ detectScript(['Hello world']); // 'latin'
|
|
|
102
157
|
detectScript(['123 ???']); // 'other'
|
|
103
158
|
```
|
|
104
159
|
|
|
105
|
-
|
|
160
|
+
### `isLatinScript(lines)`
|
|
106
161
|
|
|
107
162
|
Fast check — returns `true` if the text contains only Latin letters (no CJK, Cyrillic, Indic, etc.). Useful for skipping romanization entirely.
|
|
108
163
|
|
|
@@ -112,9 +167,9 @@ isLatinScript(['안녕하세요']); // false
|
|
|
112
167
|
isLatinScript(['♪♪♪']); // false (no letters)
|
|
113
168
|
```
|
|
114
169
|
|
|
115
|
-
|
|
170
|
+
### `requiresExternalRomanization(script)`
|
|
116
171
|
|
|
117
|
-
Returns `true` for scripts that
|
|
172
|
+
Returns `true` for scripts that have no built-in engine and require an external API. Importable from the lightweight `lyric-romanizer/detector` subpath, so answering "should I branch to an external service?" costs zero engine payload.
|
|
118
173
|
|
|
119
174
|
```ts
|
|
120
175
|
requiresExternalRomanization('chinese'); // false
|
|
@@ -122,15 +177,13 @@ requiresExternalRomanization('arabic'); // true
|
|
|
122
177
|
requiresExternalRomanization('malayalam'); // true
|
|
123
178
|
```
|
|
124
179
|
|
|
125
|
-
### `
|
|
126
|
-
|
|
127
|
-
#### `romanizer.romanizeLine(line, options?)`
|
|
180
|
+
### `romanizer.romanizeLine(line, options?)`
|
|
128
181
|
|
|
129
|
-
Romanizes a single line. If `script` is omitted, it is auto-detected via `detectScript
|
|
182
|
+
Romanizes a single line. If `script` is omitted, it is auto-detected **per line** via `detectScript` — looping over `romanizeLine` may route each line to a different engine, unlike `romanizeLines`, which pins one script for the whole array. Returns the original line unchanged for Latin text or non-letter content.
|
|
130
183
|
|
|
131
|
-
For Chinese text, the `dialect` option controls the romanization system: `'mandarin'` (default) uses Pinyin, `'cantonese'` uses [Jyutping](https://github.com/CanCLID/to-jyutping).
|
|
184
|
+
For Chinese text, the `dialect` option controls the romanization system: `'mandarin'` (default) uses Pinyin, `'cantonese'` uses [Jyutping](https://github.com/CanCLID/to-jyutping). Other scripts ignore `dialect`.
|
|
132
185
|
|
|
133
|
-
**Throws** `UnsupportedRomanizationError` for
|
|
186
|
+
**Throws** `UnsupportedRomanizationError` for scripts without an engine (built-in or injected).
|
|
134
187
|
|
|
135
188
|
```ts
|
|
136
189
|
await romanizer.romanizeLine('你好世界');
|
|
@@ -149,21 +202,21 @@ await romanizer.romanizeLine('مرحبا');
|
|
|
149
202
|
// throws UnsupportedRomanizationError { script: 'arabic' }
|
|
150
203
|
```
|
|
151
204
|
|
|
152
|
-
|
|
205
|
+
### `romanizer.romanizeLines(lines, options?)`
|
|
153
206
|
|
|
154
|
-
Romanizes multiple lines in parallel.
|
|
207
|
+
Romanizes multiple lines in parallel. Detects the dominant script **once across all lines** and pins it for every line (see [Mixed-script arrays](#mixed-script-arrays)). Returns the script, the romanized lines, and per-line `fallbacks` flags — `true` where the engine failed and the line was universally transliterated as a last resort.
|
|
155
208
|
|
|
156
209
|
```ts
|
|
157
|
-
const { script, lines } = await romanizer.romanizeLines([
|
|
210
|
+
const { script, lines, fallbacks } = await romanizer.romanizeLines([
|
|
158
211
|
'สวัสดี',
|
|
159
212
|
'ชาวโลก',
|
|
160
213
|
]);
|
|
161
|
-
// { script: 'thai', lines: ['
|
|
214
|
+
// { script: 'thai', lines: ['swasdi', 'chaolok'], fallbacks: [false, false] }
|
|
162
215
|
```
|
|
163
216
|
|
|
164
217
|
### `UnsupportedRomanizationError`
|
|
165
218
|
|
|
166
|
-
Thrown when attempting to romanize a script that
|
|
219
|
+
Thrown when attempting to romanize a script that has no engine — built in or injected via `options.engines`. Has a `script` property for programmatic handling.
|
|
167
220
|
|
|
168
221
|
```ts
|
|
169
222
|
try {
|
|
@@ -190,12 +243,12 @@ try {
|
|
|
190
243
|
| Cyrillic | [cyrillic-to-translit-js](https://github.com/greybax/CyrillicToTranslitJS) | `Привет` → `Privet` |
|
|
191
244
|
| Devanagari | [sanscript](https://github.com/indic-transliteration/sanscript) | `नमस्ते` → `namaste` |
|
|
192
245
|
| Gujarati | [sanscript](https://github.com/indic-transliteration/sanscript) | `નમસ્તે` → `namaste` |
|
|
193
|
-
| Gurmukhi | [sanscript](https://github.com/indic-transliteration/sanscript) | `ਨਮਸਤੇ` → `
|
|
246
|
+
| Gurmukhi | [sanscript](https://github.com/indic-transliteration/sanscript) | `ਨਮਸਤੇ` → `namasate` |
|
|
194
247
|
| Telugu | [sanscript](https://github.com/indic-transliteration/sanscript) | `నమస్తే` → `namaste` |
|
|
195
|
-
| Kannada | [sanscript](https://github.com/indic-transliteration/sanscript) |
|
|
248
|
+
| Kannada | [sanscript](https://github.com/indic-transliteration/sanscript) | `ನಮಸ್ತೇ` → `namaste` |
|
|
196
249
|
| Odia | [sanscript](https://github.com/indic-transliteration/sanscript) | `ନମସ୍ତେ` → `namaste` |
|
|
197
250
|
| Tamil | [tamil-romanizer](https://github.com/haroldalan/tamil-romanizer) | `வணக்கம்` → `vanakkam` |
|
|
198
|
-
| Thai | [@dehoist/romanize-thai](https://github.com/Dehoist/Open-Source) | `สวัสดี` → `
|
|
251
|
+
| Thai | [@dehoist/romanize-thai](https://github.com/Dehoist/Open-Source) | `สวัสดี` → `swasdi` |
|
|
199
252
|
|
|
200
253
|
### External (requires API)
|
|
201
254
|
|
|
@@ -207,13 +260,26 @@ try {
|
|
|
207
260
|
| Hebrew | Google Translate `dt=rm` |
|
|
208
261
|
| Other | Google Translate `dt=rm` |
|
|
209
262
|
|
|
210
|
-
Use `requiresExternalRomanization()` to detect these and branch to your preferred API.
|
|
263
|
+
Use `requiresExternalRomanization()` to detect these and branch to your preferred API — or plug the API in once as an [engine adapter](#engine-adapters) and let `romanizeLines` handle every script.
|
|
264
|
+
|
|
265
|
+
## Script-Specific Notes
|
|
266
|
+
|
|
267
|
+
### Mixed-script arrays
|
|
268
|
+
|
|
269
|
+
`romanizeLines` pins the **dominant** script of the whole array to every line. This is deliberate: a kanji-only line inside a Japanese song is indistinguishable from Chinese on its own (kanji and hanzi share the same Unicode block), so only whole-array context routes it to the right engine. Consequences worth knowing:
|
|
270
|
+
|
|
271
|
+
- Any kana anywhere in the array pins the whole array to `japanese` — kana is definitive proof.
|
|
272
|
+
- A line of a *different* non-Latin script inside the array is still fed to the pinned engine.
|
|
273
|
+
- Pure-Latin lines (an English chorus inside a CJK song) are **returned unchanged** instead of being fed to the pinned engine.
|
|
274
|
+
- Per-line `fallbacks` flags report when an engine failed and a line degraded to universal transliteration.
|
|
275
|
+
|
|
276
|
+
If you need true per-line engine routing, call `romanizeLine` in a loop — it detects per line.
|
|
211
277
|
|
|
212
|
-
|
|
278
|
+
### Cyrillic Detection
|
|
213
279
|
|
|
214
280
|
Cyrillic auto-detects Ukrainian-specific characters (`і`, `ї`, `є`, `ґ`) and applies the Ukrainian transliteration preset. All other Cyrillic text defaults to Russian.
|
|
215
281
|
|
|
216
|
-
|
|
282
|
+
### Cantonese Support
|
|
217
283
|
|
|
218
284
|
Chinese text defaults to Mandarin (Pinyin). Pass `dialect: 'cantonese'` in `RomanizeOptions` to romanize Chinese text to [Jyutping](https://github.com/CanCLID/to-jyutping) instead.
|
|
219
285
|
|
package/dist/detector.d.ts
CHANGED
|
@@ -1,5 +1,79 @@
|
|
|
1
1
|
import type { ScriptType } from './types.js';
|
|
2
|
+
declare const SCRIPT_METADATA: {
|
|
3
|
+
readonly japanese: {
|
|
4
|
+
readonly ranges: readonly [readonly [12352, 12543]];
|
|
5
|
+
readonly definitive: true;
|
|
6
|
+
};
|
|
7
|
+
readonly chinese: {
|
|
8
|
+
readonly ranges: readonly [readonly [19968, 40959]];
|
|
9
|
+
};
|
|
10
|
+
readonly korean: {
|
|
11
|
+
readonly ranges: readonly [readonly [44032, 55215]];
|
|
12
|
+
};
|
|
13
|
+
readonly cyrillic: {
|
|
14
|
+
readonly ranges: readonly [readonly [1024, 1279]];
|
|
15
|
+
};
|
|
16
|
+
readonly devanagari: {
|
|
17
|
+
readonly ranges: readonly [readonly [2304, 2431]];
|
|
18
|
+
};
|
|
19
|
+
readonly gujarati: {
|
|
20
|
+
readonly ranges: readonly [readonly [2688, 2815]];
|
|
21
|
+
};
|
|
22
|
+
readonly gurmukhi: {
|
|
23
|
+
readonly ranges: readonly [readonly [2560, 2687]];
|
|
24
|
+
};
|
|
25
|
+
readonly telugu: {
|
|
26
|
+
readonly ranges: readonly [readonly [3072, 3199]];
|
|
27
|
+
};
|
|
28
|
+
readonly kannada: {
|
|
29
|
+
readonly ranges: readonly [readonly [3200, 3327]];
|
|
30
|
+
};
|
|
31
|
+
readonly odia: {
|
|
32
|
+
readonly ranges: readonly [readonly [2816, 2943]];
|
|
33
|
+
};
|
|
34
|
+
readonly tamil: {
|
|
35
|
+
readonly ranges: readonly [readonly [2944, 3071]];
|
|
36
|
+
};
|
|
37
|
+
readonly malayalam: {
|
|
38
|
+
readonly ranges: readonly [readonly [3328, 3455]];
|
|
39
|
+
readonly external: true;
|
|
40
|
+
};
|
|
41
|
+
readonly bengali: {
|
|
42
|
+
readonly ranges: readonly [readonly [2432, 2559]];
|
|
43
|
+
readonly external: true;
|
|
44
|
+
};
|
|
45
|
+
readonly arabic: {
|
|
46
|
+
readonly ranges: readonly [readonly [1536, 1791]];
|
|
47
|
+
readonly external: true;
|
|
48
|
+
};
|
|
49
|
+
readonly hebrew: {
|
|
50
|
+
readonly ranges: readonly [readonly [1424, 1535]];
|
|
51
|
+
readonly external: true;
|
|
52
|
+
};
|
|
53
|
+
readonly thai: {
|
|
54
|
+
readonly ranges: readonly [readonly [3584, 3711]];
|
|
55
|
+
};
|
|
56
|
+
readonly latin: {
|
|
57
|
+
readonly ranges: readonly [];
|
|
58
|
+
};
|
|
59
|
+
readonly other: {
|
|
60
|
+
readonly ranges: readonly [];
|
|
61
|
+
readonly external: true;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Scripts classified as external in SCRIPT_METADATA. The engine table in
|
|
66
|
+
* romanizer.ts excludes exactly these members, so reclassifying a script here
|
|
67
|
+
* surfaces as a compile error there.
|
|
68
|
+
*/
|
|
69
|
+
export type ExternalScript = {
|
|
70
|
+
[K in ScriptType]: (typeof SCRIPT_METADATA)[K] extends {
|
|
71
|
+
external: true;
|
|
72
|
+
} ? K : never;
|
|
73
|
+
}[ScriptType];
|
|
2
74
|
export declare const NON_LATIN_SCRIPT_RE: RegExp;
|
|
3
75
|
export declare function isLatinScript(lines: readonly string[]): boolean;
|
|
4
76
|
export declare function detectScript(lines: readonly string[]): ScriptType;
|
|
77
|
+
export declare function requiresExternalRomanization(script: ScriptType): boolean;
|
|
78
|
+
export {};
|
|
5
79
|
//# sourceMappingURL=detector.d.ts.map
|
package/dist/detector.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwB7C,eAAO,MAAM,mBAAmB,
|
|
1
|
+
{"version":3,"file":"detector.d.ts","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAwB7C,QAAA,MAAM,eAAe;;iBAGP,MAAM;iBAAsB,UAAU;;;iBACvC,MAAM;;;iBACP,MAAM;;;iBACJ,MAAM;;;iBACJ,MAAM;;;iBACR,MAAM;;;iBACN,MAAM;;;iBACR,MAAM;;;iBACL,MAAM;;;iBACT,MAAM;;;iBACL,MAAM;;;iBACF,MAAM;iBAAsB,QAAQ;;;iBACtC,MAAM;iBAAsB,QAAQ;;;iBACrC,MAAM;iBAAsB,QAAQ;;;iBACpC,MAAM;iBAAsB,QAAQ;;;iBACtC,MAAM;;;iBACL,MAAM;;;iBACN,MAAM;iBAAM,QAAQ;;CACoB,CAAC;AAEpD;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;KAC1B,CAAC,IAAI,UAAU,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS;QAAE,QAAQ,EAAE,IAAI,CAAA;KAAE,GAAG,CAAC,GAAG,KAAK;CACtF,CAAC,UAAU,CAAC,CAAC;AAwCd,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AAEF,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAG/D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAejE;AAED,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAMxE"}
|
package/dist/detector.js
CHANGED
|
@@ -1,33 +1,75 @@
|
|
|
1
1
|
const LETTER_RE = /\p{L}/u;
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
[
|
|
15
|
-
[
|
|
16
|
-
[
|
|
17
|
-
[
|
|
18
|
-
]
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
2
|
+
// Single source of truth for per-script knowledge on the light (engine-free)
|
|
3
|
+
// side of the packaging seam: detection ranges and local/external
|
|
4
|
+
// classification. SCRIPT_SCORES, NON_LATIN_SCRIPT_RE, and
|
|
5
|
+
// requiresExternalRomanization are all derived from this table, and the
|
|
6
|
+
// engine table in romanizer.ts is compile-time checked against the
|
|
7
|
+
// classification, so adding a script here is the single detector-side edit.
|
|
8
|
+
//
|
|
9
|
+
// Entry order is load-bearing: it is the tie-break priority of detectScript —
|
|
10
|
+
// on an equal character count, the earlier entry wins.
|
|
11
|
+
const SCRIPT_METADATA = {
|
|
12
|
+
// Kana is definitive: kanji shares the Han block with chinese, so any kana
|
|
13
|
+
// must decide 'japanese' before Han scoring runs.
|
|
14
|
+
japanese: { ranges: [[0x3040, 0x30ff]], definitive: true },
|
|
15
|
+
chinese: { ranges: [[0x4e00, 0x9fff]] },
|
|
16
|
+
korean: { ranges: [[0xac00, 0xd7af]] },
|
|
17
|
+
cyrillic: { ranges: [[0x0400, 0x04ff]] },
|
|
18
|
+
devanagari: { ranges: [[0x0900, 0x097f]] },
|
|
19
|
+
gujarati: { ranges: [[0x0a80, 0x0aff]] },
|
|
20
|
+
gurmukhi: { ranges: [[0x0a00, 0x0a7f]] },
|
|
21
|
+
telugu: { ranges: [[0x0c00, 0x0c7f]] },
|
|
22
|
+
kannada: { ranges: [[0x0c80, 0x0cff]] },
|
|
23
|
+
odia: { ranges: [[0x0b00, 0x0b7f]] },
|
|
24
|
+
tamil: { ranges: [[0x0b80, 0x0bff]] },
|
|
25
|
+
malayalam: { ranges: [[0x0d00, 0x0d7f]], external: true },
|
|
26
|
+
bengali: { ranges: [[0x0980, 0x09ff]], external: true },
|
|
27
|
+
arabic: { ranges: [[0x0600, 0x06ff]], external: true },
|
|
28
|
+
hebrew: { ranges: [[0x0590, 0x05ff]], external: true },
|
|
29
|
+
thai: { ranges: [[0x0e00, 0x0e7f]] },
|
|
30
|
+
latin: { ranges: [] },
|
|
31
|
+
other: { ranges: [], external: true },
|
|
32
|
+
};
|
|
33
|
+
function escapeCodePoint(codePoint) {
|
|
34
|
+
return `\\u${codePoint.toString(16).toUpperCase().padStart(4, '0')}`;
|
|
35
|
+
}
|
|
36
|
+
function characterClass(ranges) {
|
|
37
|
+
return ranges
|
|
38
|
+
.map(([start, end]) => (start === end ? escapeCodePoint(start) : `${escapeCodePoint(start)}-${escapeCodePoint(end)}`))
|
|
39
|
+
.join('');
|
|
40
|
+
}
|
|
41
|
+
function mergeRanges(ranges) {
|
|
42
|
+
const sorted = [...ranges].sort((a, b) => a[0] - b[0]);
|
|
43
|
+
const merged = [];
|
|
44
|
+
for (const [start, end] of sorted) {
|
|
45
|
+
const last = merged[merged.length - 1];
|
|
46
|
+
if (last && start <= last[1] + 1) {
|
|
47
|
+
last[1] = Math.max(last[1], end);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
merged.push([start, end]);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return merged;
|
|
54
|
+
}
|
|
55
|
+
const METADATA_ENTRIES = Object.entries(SCRIPT_METADATA);
|
|
56
|
+
const DEFINITIVE_SCRIPTS = METADATA_ENTRIES.filter(([, meta]) => meta.definitive).map(([script, meta]) => [script, new RegExp(`[${characterClass(meta.ranges)}]`)]);
|
|
57
|
+
const SCRIPT_SCORES = METADATA_ENTRIES.filter(([, meta]) => meta.ranges.length > 0 && !meta.definitive).map(([script, meta]) => [script, new RegExp(`[${characterClass(meta.ranges)}]`, 'g')]);
|
|
58
|
+
// Derived union of every detectable range. Also consumed by the extension
|
|
59
|
+
// content script's "latin fast path" during mode switching — deriving it from
|
|
60
|
+
// SCRIPT_METADATA keeps it aligned with detection structurally instead of by
|
|
61
|
+
// comment.
|
|
62
|
+
export const NON_LATIN_SCRIPT_RE = new RegExp(`[${characterClass(mergeRanges(METADATA_ENTRIES.flatMap(([, meta]) => meta.ranges)))}]`);
|
|
22
63
|
export function isLatinScript(lines) {
|
|
23
64
|
const text = lines.join('');
|
|
24
65
|
return !NON_LATIN_SCRIPT_RE.test(text) && LETTER_RE.test(text);
|
|
25
66
|
}
|
|
26
67
|
export function detectScript(lines) {
|
|
27
68
|
const text = lines.join('');
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
69
|
+
for (const [script, pattern] of DEFINITIVE_SCRIPTS) {
|
|
70
|
+
if (pattern.test(text))
|
|
71
|
+
return script;
|
|
72
|
+
}
|
|
31
73
|
let best = ['other', 0];
|
|
32
74
|
for (const [script, pattern] of SCRIPT_SCORES) {
|
|
33
75
|
const score = (text.match(pattern) ?? []).length;
|
|
@@ -38,4 +80,12 @@ export function detectScript(lines) {
|
|
|
38
80
|
return best[0];
|
|
39
81
|
return LETTER_RE.test(text) ? 'latin' : 'other';
|
|
40
82
|
}
|
|
83
|
+
export function requiresExternalRomanization(script) {
|
|
84
|
+
// Own-property check so an out-of-contract string from untyped callers
|
|
85
|
+
// (including inherited names like 'toString') returns false rather than
|
|
86
|
+
// resolving up the prototype chain.
|
|
87
|
+
if (!Object.hasOwn(SCRIPT_METADATA, script))
|
|
88
|
+
return false;
|
|
89
|
+
return SCRIPT_METADATA[script].external === true;
|
|
90
|
+
}
|
|
41
91
|
//# sourceMappingURL=detector.js.map
|
package/dist/detector.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"AAEA,MAAM,SAAS,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../src/detector.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { detectScript, isLatinScript, NON_LATIN_SCRIPT_RE } from './detector.js';
|
|
2
|
-
export { createRomanizer
|
|
3
|
-
export { UnsupportedRomanizationError, type RomanizeOptions, type RomanizeResult, type Romanizer, type RomanizerOptions, type ScriptType, } from './types.js';
|
|
1
|
+
export { detectScript, isLatinScript, requiresExternalRomanization, NON_LATIN_SCRIPT_RE, type ExternalScript, } from './detector.js';
|
|
2
|
+
export { createRomanizer } from './romanizer.js';
|
|
3
|
+
export { UnsupportedRomanizationError, type RomanizeEngine, type RomanizeEngineContext, type RomanizeOptions, type RomanizeResult, type Romanizer, type RomanizerOptions, type ScriptType, } from './types.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,4BAA4B,EAC5B,mBAAmB,EACnB,KAAK,cAAc,GACpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,4BAA4B,EAC5B,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,SAAS,EACd,KAAK,gBAAgB,EACrB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { detectScript, isLatinScript, NON_LATIN_SCRIPT_RE } from './detector.js';
|
|
2
|
-
export { createRomanizer
|
|
1
|
+
export { detectScript, isLatinScript, requiresExternalRomanization, NON_LATIN_SCRIPT_RE, } from './detector.js';
|
|
2
|
+
export { createRomanizer } from './romanizer.js';
|
|
3
3
|
export { UnsupportedRomanizationError, } from './types.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,4BAA4B,EAC5B,mBAAmB,GAEpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EACL,4BAA4B,GAQ7B,MAAM,YAAY,CAAC"}
|
package/dist/romanizer.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type { Romanizer, RomanizerOptions
|
|
2
|
-
|
|
1
|
+
import type { Romanizer, RomanizerOptions } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Ukrainian-specific characters pick the Ukrainian preset; all other Cyrillic
|
|
4
|
+
* romanizes as Russian. Applied per line, so a mixed-language song switches
|
|
5
|
+
* preset line by line.
|
|
6
|
+
*/
|
|
7
|
+
export declare function selectCyrillicPreset(line: string): 'ru' | 'uk';
|
|
3
8
|
export declare function createRomanizer(options?: RomanizerOptions): Romanizer;
|
|
4
9
|
//# sourceMappingURL=romanizer.d.ts.map
|
package/dist/romanizer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"romanizer.d.ts","sourceRoot":"","sources":["../src/romanizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"romanizer.d.ts","sourceRoot":"","sources":["../src/romanizer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAKV,SAAS,EACT,gBAAgB,EAEjB,MAAM,YAAY,CAAC;AA4EpB;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAE9D;AA+ID,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAErE"}
|