summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
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;
+}