@kensio/pinyinjs 0.1.0-beta.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +87 -0
- package/NOTICE +7 -0
- package/README.md +144 -19
- package/data/full.entries +13400 -13400
- package/data/manifest.json +4 -4
- package/data/standard.entries +2492 -2492
- package/dist/cli/arguments.d.ts +67 -0
- package/dist/cli/arguments.d.ts.map +1 -1
- package/dist/cli/arguments.js +79 -0
- package/dist/cli/arguments.js.map +1 -1
- package/dist/cli/colour.d.ts +77 -0
- package/dist/cli/colour.d.ts.map +1 -0
- package/dist/cli/colour.js +117 -0
- package/dist/cli/colour.js.map +1 -0
- package/dist/cli/commands.d.ts +49 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +404 -42
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/environment.d.ts.map +1 -1
- package/dist/cli/environment.js +20 -0
- package/dist/cli/environment.js.map +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +43 -16
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/run.d.ts +11 -0
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +4 -2
- package/dist/cli/run.js.map +1 -1
- package/dist/decode/convert.d.ts +20 -0
- package/dist/decode/convert.d.ts.map +1 -1
- package/dist/decode/convert.js +170 -12
- package/dist/decode/convert.js.map +1 -1
- package/dist/decode/decode.d.ts +3 -2
- package/dist/decode/decode.d.ts.map +1 -1
- package/dist/decode/decode.js +17 -4
- package/dist/decode/decode.js.map +1 -1
- package/dist/decode/reading-rules.d.ts +56 -0
- package/dist/decode/reading-rules.d.ts.map +1 -0
- package/dist/decode/reading-rules.js +107 -0
- package/dist/decode/reading-rules.js.map +1 -0
- package/dist/decode/rules.d.ts +66 -0
- package/dist/decode/rules.d.ts.map +1 -0
- package/dist/decode/rules.js +138 -0
- package/dist/decode/rules.js.map +1 -0
- package/dist/decode/sandhi.d.ts +1 -1
- package/dist/decode/sandhi.d.ts.map +1 -1
- package/dist/decode/sandhi.js +60 -1
- package/dist/decode/sandhi.js.map +1 -1
- package/dist/decode/word.d.ts +18 -0
- package/dist/decode/word.d.ts.map +1 -1
- package/dist/dictionary/artifact.d.ts.map +1 -1
- package/dist/dictionary/artifact.js +28 -1
- package/dist/dictionary/artifact.js.map +1 -1
- package/dist/dictionary/dictionary.d.ts +9 -0
- package/dist/dictionary/dictionary.d.ts.map +1 -1
- package/dist/dictionary/dictionary.js +7 -0
- package/dist/dictionary/dictionary.js.map +1 -1
- package/dist/dictionary/entry.d.ts +12 -0
- package/dist/dictionary/entry.d.ts.map +1 -1
- package/dist/dictionary/entry.js.map +1 -1
- package/dist/dictionary/merge.d.ts +3 -1
- package/dist/dictionary/merge.d.ts.map +1 -1
- package/dist/dictionary/merge.js +19 -1
- package/dist/dictionary/merge.js.map +1 -1
- package/dist/format/transcription.d.ts +52 -0
- package/dist/format/transcription.d.ts.map +1 -0
- package/dist/format/transcription.js +88 -0
- package/dist/format/transcription.js.map +1 -0
- package/dist/index.d.ts +24 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/numerals/cardinal.d.ts +39 -0
- package/dist/numerals/cardinal.d.ts.map +1 -0
- package/dist/numerals/cardinal.js +111 -0
- package/dist/numerals/cardinal.js.map +1 -0
- package/dist/numerals/characters.d.ts +31 -0
- package/dist/numerals/characters.d.ts.map +1 -0
- package/dist/numerals/characters.js +80 -0
- package/dist/numerals/characters.js.map +1 -0
- package/dist/numerals/numerals.d.ts +76 -0
- package/dist/numerals/numerals.d.ts.map +1 -0
- package/dist/numerals/numerals.js +119 -0
- package/dist/numerals/numerals.js.map +1 -0
- package/dist/numerals/text.d.ts +52 -0
- package/dist/numerals/text.d.ts.map +1 -0
- package/dist/numerals/text.js +248 -0
- package/dist/numerals/text.js.map +1 -0
- package/dist/orthography/grouping.d.ts +56 -11
- package/dist/orthography/grouping.d.ts.map +1 -1
- package/dist/orthography/grouping.js +109 -35
- package/dist/orthography/grouping.js.map +1 -1
- package/dist/orthography/idiom-list.d.ts +56 -0
- package/dist/orthography/idiom-list.d.ts.map +1 -0
- package/dist/orthography/idiom-list.js +296 -0
- package/dist/orthography/idiom-list.js.map +1 -0
- package/dist/orthography/idioms.d.ts +18 -0
- package/dist/orthography/idioms.d.ts.map +1 -0
- package/dist/orthography/idioms.js +22 -0
- package/dist/orthography/idioms.js.map +1 -0
- package/dist/orthography/reduplication.d.ts +52 -0
- package/dist/orthography/reduplication.d.ts.map +1 -0
- package/dist/orthography/reduplication.js +99 -0
- package/dist/orthography/reduplication.js.map +1 -0
- package/dist/orthography/rule.d.ts +50 -0
- package/dist/orthography/rule.d.ts.map +1 -0
- package/dist/orthography/rule.js +101 -0
- package/dist/orthography/rule.js.map +1 -0
- package/dist/sources/cedict.d.ts +23 -0
- package/dist/sources/cedict.d.ts.map +1 -1
- package/dist/sources/cedict.js +28 -0
- package/dist/sources/cedict.js.map +1 -1
- package/dist/syllable/syllable.d.ts +1 -1
- package/dist/syllable/syllable.d.ts.map +1 -1
- package/dist/syllable/syllable.js +2 -37
- package/dist/syllable/syllable.js.map +1 -1
- package/dist/tone/tone-mark.d.ts +23 -0
- package/dist/tone/tone-mark.d.ts.map +1 -1
- package/dist/tone/tone-mark.js +49 -0
- package/dist/tone/tone-mark.js.map +1 -1
- package/dist/transcription/bopomofo.d.ts +46 -0
- package/dist/transcription/bopomofo.d.ts.map +1 -0
- package/dist/transcription/bopomofo.js +371 -0
- package/dist/transcription/bopomofo.js.map +1 -0
- package/dist/transcription/gwoyeu.d.ts +32 -0
- package/dist/transcription/gwoyeu.d.ts.map +1 -0
- package/dist/transcription/gwoyeu.js +491 -0
- package/dist/transcription/gwoyeu.js.map +1 -0
- package/dist/transcription/ipa.d.ts +40 -0
- package/dist/transcription/ipa.d.ts.map +1 -0
- package/dist/transcription/ipa.js +221 -0
- package/dist/transcription/ipa.js.map +1 -0
- package/dist/transcription/spelling-index.d.ts +23 -0
- package/dist/transcription/spelling-index.d.ts.map +1 -0
- package/dist/transcription/spelling-index.js +61 -0
- package/dist/transcription/spelling-index.js.map +1 -0
- package/dist/transcription/wade-giles.d.ts +108 -0
- package/dist/transcription/wade-giles.d.ts.map +1 -0
- package/dist/transcription/wade-giles.js +656 -0
- package/dist/transcription/wade-giles.js.map +1 -0
- package/dist/transcription/yale.d.ts +43 -0
- package/dist/transcription/yale.d.ts.map +1 -0
- package/dist/transcription/yale.js +242 -0
- package/dist/transcription/yale.js.map +1 -0
- package/package.json +9 -5
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gwoyeu Romatzyh (國語羅馬字), in both directions.
|
|
3
|
+
*
|
|
4
|
+
* GR is the odd one of the five. Every other system here writes a syllable and
|
|
5
|
+
* then marks its tone — a diacritic, a raised digit, a tone letter — so the
|
|
6
|
+
* spelling is one mapping over the inventory and the tone rides on top of it.
|
|
7
|
+
* GR spells the tone *into* the syllable: 山 shān is `shan`, 陝 shǎn is `shaan`,
|
|
8
|
+
* 善 shàn is `shann`. So it is four mappings rather than one, related by the
|
|
9
|
+
* tonal rules below, and reading it back is an index keyed per tone.
|
|
10
|
+
*
|
|
11
|
+
* The rules come from Wikipedia's *Spelling in Gwoyeu Romatzyh*, which states
|
|
12
|
+
* them as a rule of thumb per tone plus a handful of clauses. They are
|
|
13
|
+
* implemented here as stated, with one amendment recorded in
|
|
14
|
+
* {@link zeroInitial}, and the whole of it is scored against a different page's
|
|
15
|
+
* four GR columns in [syllabary.test.ts](syllabary.test.ts).
|
|
16
|
+
*
|
|
17
|
+
* Three things follow from the tone being in the spelling:
|
|
18
|
+
*
|
|
19
|
+
* - **There is no toneless form.** The basic form *is* the first tone, so a
|
|
20
|
+
* syllable whose tone was never written cannot be told from one written in
|
|
21
|
+
* the first tone. That is bopomofo's shortfall exactly, arrived at from the
|
|
22
|
+
* other direction — see `docs/romanization/`.
|
|
23
|
+
* - **The neutral tone is a dot in front**, and GR keeps the etymological tone
|
|
24
|
+
* spelling of the syllable behind it (`perng.yeou` for 朋友). A neutral
|
|
25
|
+
* pinyin syllable does not record what that tone was, so this module writes
|
|
26
|
+
* the basic form: `.iou` where a GR writer has `.yeou`. Reading is not so
|
|
27
|
+
* limited — a dot in front of any tonal spelling reads as the neutral tone.
|
|
28
|
+
* - **儿化 is the `-l` suffix**, and it is written here as a plain suffix
|
|
29
|
+
* rather than as the fusion GR actually performs. See {@link ERHUA_SUFFIX}.
|
|
30
|
+
*/
|
|
31
|
+
import { DICTIONARY_SYLLABLES } from "../syllable/inventory.js";
|
|
32
|
+
import { readSyllable } from "../syllable/syllable.js";
|
|
33
|
+
import { NEUTRAL_TONE } from "../tone/tone.js";
|
|
34
|
+
/**
|
|
35
|
+
* The four tones, for building the index.
|
|
36
|
+
*/
|
|
37
|
+
const CONTOUR_TONES = [1, 2, 3, 4];
|
|
38
|
+
/**
|
|
39
|
+
* How each initial is spelled.
|
|
40
|
+
*
|
|
41
|
+
* GR uses the voiced letters for the unaspirated series, as pinyin does, so
|
|
42
|
+
* this half of the table is nearly pinyin's own. The three that differ are the
|
|
43
|
+
* alveolar affricates — `tz` and `ts` for pinyin z and c — and the palatals,
|
|
44
|
+
* which GR does not distinguish from the retroflexes at all: `j`, `ch` and `sh`
|
|
45
|
+
* stand for both series, and it is the following `i` that says which. That is
|
|
46
|
+
* why pinyin zhu, ju and jiu come out as `ju`, `jiu` and `jiou`.
|
|
47
|
+
*/
|
|
48
|
+
const INITIAL_SPELLINGS = new Map([
|
|
49
|
+
["b", "b"],
|
|
50
|
+
["p", "p"],
|
|
51
|
+
["m", "m"],
|
|
52
|
+
["f", "f"],
|
|
53
|
+
["d", "d"],
|
|
54
|
+
["t", "t"],
|
|
55
|
+
["n", "n"],
|
|
56
|
+
["l", "l"],
|
|
57
|
+
["g", "g"],
|
|
58
|
+
["k", "k"],
|
|
59
|
+
["h", "h"],
|
|
60
|
+
["j", "j"],
|
|
61
|
+
["q", "ch"],
|
|
62
|
+
["x", "sh"],
|
|
63
|
+
["zh", "j"],
|
|
64
|
+
["ch", "ch"],
|
|
65
|
+
["sh", "sh"],
|
|
66
|
+
["r", "r"],
|
|
67
|
+
["z", "tz"],
|
|
68
|
+
["c", "ts"],
|
|
69
|
+
["s", "s"],
|
|
70
|
+
]);
|
|
71
|
+
/**
|
|
72
|
+
* How each final is spelled in the basic form.
|
|
73
|
+
*
|
|
74
|
+
* Written out in full, as the finals table of *Spelling in Gwoyeu Romatzyh*
|
|
75
|
+
* has them: `iou` and `uei` rather than pinyin's contracted iu and ui, `iu` for
|
|
76
|
+
* ü, `au` for ao, and `el` for er — the `-r` being spoken for by the second
|
|
77
|
+
* tone.
|
|
78
|
+
*/
|
|
79
|
+
const FINAL_SPELLINGS = {
|
|
80
|
+
a: "a",
|
|
81
|
+
o: "o",
|
|
82
|
+
e: "e",
|
|
83
|
+
ê: "è",
|
|
84
|
+
er: "el",
|
|
85
|
+
ai: "ai",
|
|
86
|
+
ei: "ei",
|
|
87
|
+
ao: "au",
|
|
88
|
+
ou: "ou",
|
|
89
|
+
an: "an",
|
|
90
|
+
en: "en",
|
|
91
|
+
ang: "ang",
|
|
92
|
+
eng: "eng",
|
|
93
|
+
ong: "ong",
|
|
94
|
+
i: "i",
|
|
95
|
+
ia: "ia",
|
|
96
|
+
io: "io",
|
|
97
|
+
ie: "ie",
|
|
98
|
+
iao: "iau",
|
|
99
|
+
iou: "iou",
|
|
100
|
+
ian: "ian",
|
|
101
|
+
in: "in",
|
|
102
|
+
iang: "iang",
|
|
103
|
+
ing: "ing",
|
|
104
|
+
iong: "iong",
|
|
105
|
+
u: "u",
|
|
106
|
+
ua: "ua",
|
|
107
|
+
uo: "uo",
|
|
108
|
+
uai: "uai",
|
|
109
|
+
uei: "uei",
|
|
110
|
+
uan: "uan",
|
|
111
|
+
uen: "uen",
|
|
112
|
+
uang: "uang",
|
|
113
|
+
ueng: "ueng",
|
|
114
|
+
ü: "iu",
|
|
115
|
+
üe: "iue",
|
|
116
|
+
üan: "iuan",
|
|
117
|
+
ün: "iun",
|
|
118
|
+
m: "m",
|
|
119
|
+
n: "n",
|
|
120
|
+
ng: "ng",
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* The initials after which the empty rhyme is written `-y`.
|
|
124
|
+
*
|
|
125
|
+
* 詩 shī is `shy` and 斯 sī is `sy`, which is the same observation Yale makes
|
|
126
|
+
* with its `r` and `z`: the i of shi is a continuation of the initial rather
|
|
127
|
+
* than a vowel. GR spends a letter of its own on it, and that letter behaves
|
|
128
|
+
* as a vowel for every tonal rule below — `shy`, `shyr`, `shyy`, `shyh`.
|
|
129
|
+
*/
|
|
130
|
+
const EMPTY_RHYME_INITIALS = new Set([
|
|
131
|
+
"zh",
|
|
132
|
+
"ch",
|
|
133
|
+
"sh",
|
|
134
|
+
"r",
|
|
135
|
+
"z",
|
|
136
|
+
"c",
|
|
137
|
+
"s",
|
|
138
|
+
]);
|
|
139
|
+
/**
|
|
140
|
+
* The sonorant initials, which swap what the first two tones do.
|
|
141
|
+
*
|
|
142
|
+
* A syllable beginning l-, m-, n- or r- takes an `-h-` as its second letter in
|
|
143
|
+
* the first tone and is left alone in the second: 媽 mā is `mha` and 麻 má is
|
|
144
|
+
* `ma`. The reason is frequency rather than phonology — these initials carry
|
|
145
|
+
* far more second tones than first ones — and it is the one place where the
|
|
146
|
+
* basic form is not the first tone.
|
|
147
|
+
*/
|
|
148
|
+
const SONORANT_INITIALS = new Set(["l", "m", "n", "r"]);
|
|
149
|
+
/**
|
|
150
|
+
* The letters that count as a vowel for the tonal rules.
|
|
151
|
+
*
|
|
152
|
+
* `y` is the empty rhyme and `è` is pinyin's ê; both are the whole of the rime
|
|
153
|
+
* they appear in, so both take the doubling and the `-r` exactly as a vowel
|
|
154
|
+
* does.
|
|
155
|
+
*/
|
|
156
|
+
const VOWELS = "aeiouyè";
|
|
157
|
+
/**
|
|
158
|
+
* The vowels a tone mark can sit on in pinyin, in the order the rule tries
|
|
159
|
+
* them, which is what "the main vowel" means for the third tone's doubling.
|
|
160
|
+
*/
|
|
161
|
+
const MAIN_VOWELS = ["a", "o", "e"];
|
|
162
|
+
/**
|
|
163
|
+
* The 儿化 suffix.
|
|
164
|
+
*
|
|
165
|
+
* GR marks rhotacisation with `-l`, and this module writes it as a plain
|
|
166
|
+
* suffix: 花儿 huār is `hual`. **What GR itself does is a fusion rather than a
|
|
167
|
+
* suffix** — 一點兒 yìdiǎnr is `ideal`, where `dean` has lost its `-n` — and
|
|
168
|
+
* the fusion collapses syllables that were distinct, which is why *Spelling in
|
|
169
|
+
* Gwoyeu Romatzyh* notes that `jiel` is either 今兒 or 雞兒. Modelling it needs
|
|
170
|
+
* a rime-by-rime table of rhotacised forms, which is a phonological claim
|
|
171
|
+
* rather than a spelling convention, and is not made here — the same line
|
|
172
|
+
* [ipa.ts](ipa.ts) draws around its suffixed [ɚ].
|
|
173
|
+
*
|
|
174
|
+
* The visible consequence is that this module's 儿化 always reads back and
|
|
175
|
+
* GR's own does not.
|
|
176
|
+
*/
|
|
177
|
+
const ERHUA_SUFFIX = "l";
|
|
178
|
+
/**
|
|
179
|
+
* The dot written in front of a neutral-tone syllable.
|
|
180
|
+
*
|
|
181
|
+
* A full stop, which is how GR writes it in print. Chao's own practice is to
|
|
182
|
+
* use it on a word's first appearance rather than throughout; this module
|
|
183
|
+
* always writes it, because it is the only thing in GR that can say "neutral"
|
|
184
|
+
* rather than leaving it to be inferred.
|
|
185
|
+
*/
|
|
186
|
+
const NEUTRAL_MARK = ".";
|
|
187
|
+
/**
|
|
188
|
+
* Whether a letter is one the tonal rules treat as a vowel.
|
|
189
|
+
*
|
|
190
|
+
* Spelled out rather than written `VOWELS.includes(letter)` because
|
|
191
|
+
* `"aeiouyè".includes("")` is true, and the letter before the first one of a
|
|
192
|
+
* spelling is exactly that: the empty string. A rule asking "is the letter
|
|
193
|
+
* before this one a vowel" would silently say yes at the start of every
|
|
194
|
+
* syllable.
|
|
195
|
+
*/
|
|
196
|
+
function isVowel(letter) {
|
|
197
|
+
return letter !== undefined && letter !== "" && VOWELS.includes(letter);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* How a final is spelled after a given initial.
|
|
201
|
+
*/
|
|
202
|
+
function rimeSpelling(initial, final) {
|
|
203
|
+
return final === "i" && EMPTY_RHYME_INITIALS.has(initial)
|
|
204
|
+
? "y"
|
|
205
|
+
: FINAL_SPELLINGS[final];
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* The basic form of a syllable: the spelling every tonal rule starts from.
|
|
209
|
+
*/
|
|
210
|
+
function basicForm(syllable) {
|
|
211
|
+
const { initial, final } = syllable;
|
|
212
|
+
const spelt = INITIAL_SPELLINGS.get(initial) ?? "";
|
|
213
|
+
return `${spelt}${rimeSpelling(initial, final)}`;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Where the rime's vowels start and end.
|
|
217
|
+
*
|
|
218
|
+
* The five syllables with no vowel letter at all — the syllabic nasals 呣, 唔,
|
|
219
|
+
* 嗯 and their aspirated pair — fall back to the last letter, so that the rules
|
|
220
|
+
* asking for "the vowel" have something to work on. GR has no attested
|
|
221
|
+
* spelling for any of them; see `docs/romanization/`.
|
|
222
|
+
*/
|
|
223
|
+
function vowelSpan(form) {
|
|
224
|
+
let start = 0;
|
|
225
|
+
while (start < form.length && !isVowel(form[start])) {
|
|
226
|
+
start += 1;
|
|
227
|
+
}
|
|
228
|
+
if (start === form.length) {
|
|
229
|
+
return [form.length - 1, form.length - 1];
|
|
230
|
+
}
|
|
231
|
+
let end = start;
|
|
232
|
+
while (isVowel(form[end + 1])) {
|
|
233
|
+
end += 1;
|
|
234
|
+
}
|
|
235
|
+
return [start, end];
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Tone 1: the basic form, with `-h-` inserted after a sonorant initial.
|
|
239
|
+
*/
|
|
240
|
+
function firstTone(form, initial) {
|
|
241
|
+
return SONORANT_INITIALS.has(initial)
|
|
242
|
+
? `${form.slice(0, 1)}h${form.slice(1)}`
|
|
243
|
+
: form;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* The i or u a glide can be written on, turned into y or w.
|
|
247
|
+
*
|
|
248
|
+
* The rule is `NiV → NyV` and `NuV → NwV`, where N is a non-vowel or nothing at
|
|
249
|
+
* all: the i or u has to be the medial rather than part of a diphthong, which
|
|
250
|
+
* is what the "not preceded by a vowel" test says. The `+ -i if final` clause
|
|
251
|
+
* covers the rimes that are nothing but the medial — `i` becomes `yi` and not
|
|
252
|
+
* a bare `y`.
|
|
253
|
+
*/
|
|
254
|
+
function glided(form) {
|
|
255
|
+
for (const [letter, glide] of [
|
|
256
|
+
["i", "y"],
|
|
257
|
+
["u", "w"],
|
|
258
|
+
]) {
|
|
259
|
+
const at = form.indexOf(letter);
|
|
260
|
+
if (at !== -1 && !isVowel(form[at - 1])) {
|
|
261
|
+
const rest = form.slice(at + 1);
|
|
262
|
+
return `${form.slice(0, at)}${glide}${rest === "" ? letter : rest}`;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return undefined;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Tone 2: i/u to y/w, or an `-r` after the vowels.
|
|
269
|
+
*/
|
|
270
|
+
function secondTone(form, initial) {
|
|
271
|
+
if (SONORANT_INITIALS.has(initial)) {
|
|
272
|
+
return form;
|
|
273
|
+
}
|
|
274
|
+
const glide = glided(form);
|
|
275
|
+
if (glide !== undefined) {
|
|
276
|
+
return glide;
|
|
277
|
+
}
|
|
278
|
+
const [, end] = vowelSpan(form);
|
|
279
|
+
return `${form.slice(0, end + 1)}r${form.slice(end + 1)}`;
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* The i or u a third tone can be swapped for e or o.
|
|
283
|
+
*
|
|
284
|
+
* `Vi`/`iV` becomes `Ve`/`eV` and `Vu`/`uV` becomes `Vo`/`oV`, so the letter
|
|
285
|
+
* has to sit beside a vowel; where both an i and a u are available it is
|
|
286
|
+
* whichever comes *first* that changes, which is why 交 jiǎo is `jeau` and not
|
|
287
|
+
* `jiao`. The swap is abandoned where it would produce `ee` or `oo`, both of
|
|
288
|
+
* which are the doubling below and would collide with it.
|
|
289
|
+
*/
|
|
290
|
+
function swapped(form) {
|
|
291
|
+
const found = [
|
|
292
|
+
["i", "e"],
|
|
293
|
+
["u", "o"],
|
|
294
|
+
]
|
|
295
|
+
.map(([letter, swap]) => [form.indexOf(letter), swap])
|
|
296
|
+
.filter(([at]) => at !== -1)
|
|
297
|
+
.toSorted((one, other) => one[0] - other[0])[0];
|
|
298
|
+
if (found === undefined) {
|
|
299
|
+
return undefined;
|
|
300
|
+
}
|
|
301
|
+
const [at, swap] = found;
|
|
302
|
+
const before = form[at - 1];
|
|
303
|
+
const after = form[at + 1];
|
|
304
|
+
const isBeside = isVowel(before) || isVowel(after);
|
|
305
|
+
const isDoubles = before === swap || after === swap;
|
|
306
|
+
return isBeside && !isDoubles
|
|
307
|
+
? `${form.slice(0, at)}${swap}${form.slice(at + 1)}`
|
|
308
|
+
: undefined;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Tone 3, where the swap does not apply: double the main vowel.
|
|
312
|
+
*
|
|
313
|
+
* The main vowel is the one a pinyin tone mark would sit on — a, then o or e,
|
|
314
|
+
* then the last vowel there is — so 請 qǐng is `chiing` and 給 gěi is `geei`.
|
|
315
|
+
*/
|
|
316
|
+
function doubled(form) {
|
|
317
|
+
const [start, end] = vowelSpan(form);
|
|
318
|
+
const rime = form.slice(start, end + 1);
|
|
319
|
+
const main = MAIN_VOWELS.map((vowel) => rime.indexOf(vowel)).find((at) => at !== -1);
|
|
320
|
+
const at = start + (main ?? rime.length - 1);
|
|
321
|
+
return `${form.slice(0, at + 1)}${form.slice(at, at + 1)}${form.slice(at + 1)}`;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Tone 3: i/u to e/o beside a vowel, or the main vowel doubled.
|
|
325
|
+
*/
|
|
326
|
+
function thirdTone(form) {
|
|
327
|
+
return swapped(form) ?? doubled(form);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Tone 4: change or double the last letter, or add `-h`.
|
|
331
|
+
*
|
|
332
|
+
* The `⇏iw` clause is why 去 qù is `chiuh` and not `chiw`: the u of `iu` is the
|
|
333
|
+
* ü rather than the second half of a diphthong, and turning it into a w would
|
|
334
|
+
* say the wrong thing about the vowel.
|
|
335
|
+
*/
|
|
336
|
+
function fourthTone(form) {
|
|
337
|
+
const last = form.slice(-1);
|
|
338
|
+
const before = form.slice(-2, -1);
|
|
339
|
+
if (last === "i" && isVowel(before)) {
|
|
340
|
+
return `${form.slice(0, -1)}y`;
|
|
341
|
+
}
|
|
342
|
+
if (last === "u" && isVowel(before) && before !== "i") {
|
|
343
|
+
return `${form.slice(0, -1)}w`;
|
|
344
|
+
}
|
|
345
|
+
if (form.endsWith("ng")) {
|
|
346
|
+
return `${form.slice(0, -2)}nq`;
|
|
347
|
+
}
|
|
348
|
+
if (last === "n" || last === "l") {
|
|
349
|
+
return `${form}${last}`;
|
|
350
|
+
}
|
|
351
|
+
return `${form}h`;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Put the y- or w- on a syllable that has no initial, in tones 3 and 4.
|
|
355
|
+
*
|
|
356
|
+
* **This is the one place where the published rules needed amending, and the
|
|
357
|
+
* amendment is a correction of one word.** They say that a basic form starting
|
|
358
|
+
* i- or u- has that letter *replaced* by y- or w- (tone 4), or changed to e- or
|
|
359
|
+
* o- with a y- or w- added (tone 3). Applied literally that deletes a vowel the
|
|
360
|
+
* attested spellings keep: 一 yī's basic form is `i`, and tone 4 comes out `yh`
|
|
361
|
+
* where the source has `yih`. Nine cells of the syllabary fail that way, all of
|
|
362
|
+
* them a rime that is bare or closed by a consonant — `yii`, `yih`, `wuu`,
|
|
363
|
+
* `wuh`, `yiin`, `yinn`, `yiing`, `yinq`, `yuh`.
|
|
364
|
+
*
|
|
365
|
+
* The rime table of *Spelling in Gwoyeu Romatzyh* says what actually happens,
|
|
366
|
+
* and it is one rule rather than two: **the letter replaced is a medial**, so
|
|
367
|
+
* it goes only when a different vowel follows it. `iuh` has a u after the i and
|
|
368
|
+
* becomes `yuh`; `ih` has an h and becomes `yih`; `ii` has the same vowel
|
|
369
|
+
* doubled, which is not a following vowel at all, and becomes `yii`. Tone 3
|
|
370
|
+
* needs no separate clause once that is said, because its own swap has already
|
|
371
|
+
* eaten the medial wherever there was one.
|
|
372
|
+
*/
|
|
373
|
+
function zeroInitial(form, basic) {
|
|
374
|
+
const onset = basic.slice(0, 1);
|
|
375
|
+
if (onset !== "i" && onset !== "u") {
|
|
376
|
+
return form;
|
|
377
|
+
}
|
|
378
|
+
const glide = onset === "i" ? "y" : "w";
|
|
379
|
+
const next = form[1];
|
|
380
|
+
const isMedial = form.slice(0, 1) === onset && isVowel(next) && next !== onset;
|
|
381
|
+
return `${glide}${isMedial ? form.slice(1) : form}`;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Spell a syllable in a given tone, which is the whole of GR's tonal rules.
|
|
385
|
+
*/
|
|
386
|
+
function toneForm(syllable, tone) {
|
|
387
|
+
const { initial } = syllable;
|
|
388
|
+
const basic = basicForm(syllable);
|
|
389
|
+
if (tone === 1) {
|
|
390
|
+
return firstTone(basic, initial);
|
|
391
|
+
}
|
|
392
|
+
if (tone === 2) {
|
|
393
|
+
return secondTone(basic, initial);
|
|
394
|
+
}
|
|
395
|
+
const changed = tone === 3 ? thirdTone(basic) : fourthTone(basic);
|
|
396
|
+
return initial === "" ? zeroInitial(changed, basic) : changed;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Write a syllable in Gwoyeu Romatzyh: 就 jiù becomes `jiow`.
|
|
400
|
+
*
|
|
401
|
+
* An unwritten tone is written as the basic form, because GR has no other
|
|
402
|
+
* form to write — which means it reads back as a first tone, exactly as
|
|
403
|
+
* bopomofo's unmarked syllable does. The neutral tone takes the dot in front,
|
|
404
|
+
* and the syllable behind it is the basic form rather than the etymological
|
|
405
|
+
* spelling GR would use, for the reason the module comment gives.
|
|
406
|
+
*/
|
|
407
|
+
export function writeGwoyeu(syllable) {
|
|
408
|
+
const { tone } = syllable;
|
|
409
|
+
const spelt = toneForm(syllable, tone === undefined || tone === NEUTRAL_TONE ? 1 : tone);
|
|
410
|
+
const suffix = syllable.erhua === true ? ERHUA_SUFFIX : "";
|
|
411
|
+
const dot = tone === NEUTRAL_TONE ? NEUTRAL_MARK : "";
|
|
412
|
+
return `${dot}${spelt}${suffix}`;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* Write a word in Gwoyeu Romatzyh, one syllable after another.
|
|
416
|
+
*
|
|
417
|
+
* Solid, as GR writes a word: 北京 is `Beeijing`, which is the convention
|
|
418
|
+
* pinyin inherited. GR uses an apostrophe where the join is ambiguous — its own
|
|
419
|
+
* name for pinyin, `Pin'in`, is the standard example — and that is not written
|
|
420
|
+
* here, for the same reason `readGwoyeu` takes one syllable at a time: knowing
|
|
421
|
+
* where the boundary is ambiguous means being able to split the word, and
|
|
422
|
+
* nothing here splits a GR word.
|
|
423
|
+
*/
|
|
424
|
+
export function writeGwoyeuWord(syllables) {
|
|
425
|
+
return syllables.map((syllable) => writeGwoyeu(syllable)).join("");
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Every syllable each spelling stands for, keyed per tone.
|
|
429
|
+
*
|
|
430
|
+
* The other readers here index the inventory once and read the tone off the
|
|
431
|
+
* marks; GR has no marks, so the index is built four times over and each entry
|
|
432
|
+
* carries the tone its spelling means. That is the whole practical difference
|
|
433
|
+
* between reading GR and reading the rest.
|
|
434
|
+
*/
|
|
435
|
+
function indexTonalForms() {
|
|
436
|
+
const index = new Map();
|
|
437
|
+
for (const pinyin of DICTIONARY_SYLLABLES) {
|
|
438
|
+
const syllable = readSyllable(pinyin);
|
|
439
|
+
/* c8 ignore next 3 -- inventory.test.ts holds the parser to the inventory */
|
|
440
|
+
if (syllable === undefined) {
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
for (const tone of CONTOUR_TONES) {
|
|
444
|
+
const toned = { ...syllable, tone };
|
|
445
|
+
const key = toneForm(syllable, tone);
|
|
446
|
+
const found = index.get(key);
|
|
447
|
+
if (found === undefined) {
|
|
448
|
+
index.set(key, [toned]);
|
|
449
|
+
}
|
|
450
|
+
else {
|
|
451
|
+
found.push(toned);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return index;
|
|
456
|
+
}
|
|
457
|
+
const INDEX = indexTonalForms();
|
|
458
|
+
/**
|
|
459
|
+
* Look a spelling up, allowing for the 儿化 suffix on the end of it.
|
|
460
|
+
*
|
|
461
|
+
* Tried second and separately, as it is for Yale: `ell` is 二 èr, and it is also
|
|
462
|
+
* the same rime in the first tone with the suffix on the end. Both readings are
|
|
463
|
+
* real, and it is the caller's to narrow.
|
|
464
|
+
*/
|
|
465
|
+
function lookUp(spelling) {
|
|
466
|
+
const base = spelling.endsWith(ERHUA_SUFFIX) ? spelling.slice(0, -1) : "";
|
|
467
|
+
const suffixed = base === ""
|
|
468
|
+
? []
|
|
469
|
+
: (INDEX.get(base) ?? []).map((syllable) => ({
|
|
470
|
+
...syllable,
|
|
471
|
+
erhua: true,
|
|
472
|
+
}));
|
|
473
|
+
return [...(INDEX.get(spelling) ?? []), ...suffixed];
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* Read a Gwoyeu Romatzyh syllable: `jiow` becomes 就 jiù.
|
|
477
|
+
*
|
|
478
|
+
* A leading dot is the neutral tone, and it wins over whatever tone the
|
|
479
|
+
* spelling behind it carries — `.yeou` is a neutral 友, which is what GR means
|
|
480
|
+
* by it. Returns every syllable the spelling stands for, and nothing at all for
|
|
481
|
+
* a spelling no syllable of the inventory writes.
|
|
482
|
+
*/
|
|
483
|
+
export function readGwoyeu(text) {
|
|
484
|
+
const written = text.trim().normalize("NFC").toLowerCase();
|
|
485
|
+
const isNeutral = written.startsWith(NEUTRAL_MARK);
|
|
486
|
+
const found = lookUp(isNeutral ? written.slice(NEUTRAL_MARK.length) : written);
|
|
487
|
+
return isNeutral
|
|
488
|
+
? found.map((syllable) => ({ ...syllable, tone: NEUTRAL_TONE }))
|
|
489
|
+
: found;
|
|
490
|
+
}
|
|
491
|
+
//# sourceMappingURL=gwoyeu.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gwoyeu.js","sourceRoot":"","sources":["../../src/transcription/gwoyeu.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Syllable } from "../syllable/syllable.js";
|
|
2
|
+
/**
|
|
3
|
+
* How an IPA syllable writes its tone.
|
|
4
|
+
*
|
|
5
|
+
* Chao's tone letters are the standard notation and the default; `numbers`
|
|
6
|
+
* writes his pitch numerals instead (55, 35, 214, 51), which is what a plain
|
|
7
|
+
* ASCII field wants.
|
|
8
|
+
*/
|
|
9
|
+
export interface IpaOptions {
|
|
10
|
+
readonly tones?: "letters" | "numbers" | "none";
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Transcribe a syllable without its tone: 就 jiù becomes `tɕiou`.
|
|
14
|
+
*/
|
|
15
|
+
export declare function writeIpaSymbols(syllable: Syllable): string;
|
|
16
|
+
/**
|
|
17
|
+
* Transcribe a syllable in IPA: 就 jiù becomes `tɕiou˥˩`.
|
|
18
|
+
*
|
|
19
|
+
* Without brackets, since whether it is phonemic or phonetic is the caller's
|
|
20
|
+
* claim to make and not this table's.
|
|
21
|
+
*/
|
|
22
|
+
export declare function writeIpa(syllable: Syllable, options?: IpaOptions): string;
|
|
23
|
+
/**
|
|
24
|
+
* Transcribe a word, one syllable after another.
|
|
25
|
+
*
|
|
26
|
+
* Run together, as a transcription of connected speech is written. The tone
|
|
27
|
+
* letters mark where each syllable ends, so nothing is lost by it — except for
|
|
28
|
+
* the neutral tone, which writes nothing and so leaves a boundary unmarked.
|
|
29
|
+
*/
|
|
30
|
+
export declare function writeIpaWord(syllables: readonly Syllable[], options?: IpaOptions): string;
|
|
31
|
+
/**
|
|
32
|
+
* Read an IPA transcription back: `tɕiou˥˩` becomes 就 jiù.
|
|
33
|
+
*
|
|
34
|
+
* An index over the inventory, as everything here is, so a transcription of
|
|
35
|
+
* something Mandarin does not have reads as nothing rather than as a syllable
|
|
36
|
+
* nobody says. Returns an array for the same reason the other readers do,
|
|
37
|
+
* though IPA has less to be ambiguous about than any of them.
|
|
38
|
+
*/
|
|
39
|
+
export declare function readIpa(text: string): readonly Syllable[];
|
|
40
|
+
//# sourceMappingURL=ipa.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipa.d.ts","sourceRoot":"","sources":["../../src/transcription/ipa.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAqIxD;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;CACjD;AA0BD;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,CAI1D;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,GAAE,UAAe,GAAG,MAAM,CAW7E;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,SAAS,QAAQ,EAAE,EAC9B,OAAO,GAAE,UAAe,GACvB,MAAM,CAER;AAkCD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,CAGzD"}
|