summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2024-05-06 13:55:32 -0500
committersanine <sanine.not@pm.me>2024-05-06 13:55:32 -0500
commit345b7daf4509ac89f70790c71cb2cba9b7a4f300 (patch)
treec3a26c74a0ecfe826f965cad7bdbfe62b65d2c80 /src
parentdc78c78d1aec79e532badeedd782186c4742e3a3 (diff)
add basic vowel features
Diffstat (limited to 'src')
-rw-r--r--src/language.test.ts33
-rw-r--r--src/language.ts103
2 files changed, 136 insertions, 0 deletions
diff --git a/src/language.test.ts b/src/language.test.ts
new file mode 100644
index 0000000..e9845a1
--- /dev/null
+++ b/src/language.test.ts
@@ -0,0 +1,33 @@
+import * as lang from './language';
+
+test('correctly output basic vowels', () => {
+ expect(lang.vowelFeaturesToIpa({
+ height: lang.VowelHeight.Close,
+ depth: lang.VowelDepth.Front,
+ round: false,
+ long: false,
+ nasal: false,
+ })).toBe('i');
+ expect(lang.vowelFeaturesToIpa({
+ height: lang.VowelHeight.Mid,
+ depth: lang.VowelDepth.Central,
+ round: false,
+ long: false,
+ nasal: false,
+ })).toBe('ə');
+ expect(lang.vowelFeaturesToIpa({
+ height: lang.VowelHeight.Open,
+ depth: lang.VowelDepth.Back,
+ round: true,
+ long: false,
+ nasal: true,
+ })).toBe('ɒ̃');
+ expect(lang.vowelFeaturesToIpa({
+ height: lang.VowelHeight.CloseMid,
+ depth: lang.VowelDepth.Front,
+ round: false,
+ long: true,
+ nasal: false,
+ })).toBe('eː');
+
+});
diff --git a/src/language.ts b/src/language.ts
new file mode 100644
index 0000000..2d0f547
--- /dev/null
+++ b/src/language.ts
@@ -0,0 +1,103 @@
+export enum VowelHeight {
+ Open,
+ NearOpen,
+ OpenMid,
+ Mid,
+ CloseMid,
+ NearClose,
+ Close,
+}
+export enum VowelDepth {
+ Front,
+ Central,
+ Back,
+}
+export interface VowelFeatures {
+ height: VowelHeight;
+ depth: VowelDepth;
+ round: boolean;
+ long: boolean;
+ nasal: boolean;
+}
+export function vowelFeaturesToIpa(features: VowelFeatures): string {
+ const ipa = () => {
+ switch (features.height) {
+ case VowelHeight.Open:
+ switch (features.depth) {
+ case VowelDepth.Front:
+ return features.round ? 'ɶ' : 'a';
+ case VowelDepth.Central:
+ return features.round ? 'ɞ' : 'ä';
+ case VowelDepth.Back:
+ return features.round ? 'ɒ' : 'ɑ';
+ }
+
+ case VowelHeight.NearOpen:
+ switch (features.depth) {
+ case VowelDepth.Front:
+ return features.round ? 'ɶ' : 'æ';
+ case VowelDepth.Central:
+ return features.round ? 'ɞ' : 'ɐ';
+ case VowelDepth.Back:
+ return features.round ? 'ɒ' : 'ɑ';
+ }
+
+ case VowelHeight.OpenMid:
+ switch (features.depth) {
+ case VowelDepth.Front:
+ return features.round ? 'œ' : 'ɛ';
+ case VowelDepth.Central:
+ return features.round ? 'ɞ' : 'ɜ';
+ case VowelDepth.Back:
+ return features.round ? 'ɒ' : 'ɑ';
+ }
+
+ case VowelHeight.Mid:
+ switch (features.depth) {
+ case VowelDepth.Front:
+ return features.round ? 'ø̞' : 'e̞';
+ case VowelDepth.Central:
+ return features.round ? 'ɵ' : 'ə';
+ case VowelDepth.Back:
+ return features.round ? 'o̞' : 'ɤ̞';
+ }
+
+ case VowelHeight.CloseMid:
+ switch (features.depth) {
+ case VowelDepth.Front:
+ return features.round ? 'ø' : 'e';
+ case VowelDepth.Central:
+ return features.round ? 'ɵ' : 'ɘ';
+ case VowelDepth.Back:
+ return features.round ? 'o' : 'ɤ';
+ }
+
+ case VowelHeight.NearClose:
+ switch (features.depth) {
+ case VowelDepth.Front:
+ return features.round ? 'ʏ' : 'ɪ';
+ case VowelDepth.Central:
+ return features.round ? 'ʉ' : 'ɨ';
+ case VowelDepth.Back:
+ return features.round ? 'u' : 'ʊ';
+ }
+
+ case VowelHeight.Close:
+ switch (features.depth) {
+ case VowelDepth.Front:
+ return features.round ? 'y' : 'i';
+ case VowelDepth.Central:
+ return features.round ? 'ʉ' : 'ɨ';
+ case VowelDepth.Back:
+ return features.round ? 'u' : 'ɯ';
+ }
+
+ default:
+ throw new Error(`bad vowel height: ${features.height}`);
+ }
+ };
+
+ const nasal = features.nasal ? '̃' : '';
+ const vlong = features.long ? 'ː' : '';
+ return ipa() + nasal + vlong;
+}