diff options
| author | sanine <sanine.not@pm.me> | 2024-05-06 18:03:34 -0500 | 
|---|---|---|
| committer | sanine <sanine.not@pm.me> | 2024-05-06 18:03:34 -0500 | 
| commit | 83606cd57dbfdad8a1fa0eaef2ee127f7fc2ba2c (patch) | |
| tree | ede1cc779e0c0faab0511ab802dd1b14afff4114 /src | |
| parent | 345b7daf4509ac89f70790c71cb2cba9b7a4f300 (diff) | |
add basic consonant features
Diffstat (limited to 'src')
| -rw-r--r-- | src/language.test.ts | 38 | ||||
| -rw-r--r-- | src/language.ts | 379 | 
2 files changed, 417 insertions, 0 deletions
| diff --git a/src/language.test.ts b/src/language.test.ts index e9845a1..d3c6f23 100644 --- a/src/language.test.ts +++ b/src/language.test.ts @@ -31,3 +31,41 @@ test('correctly output basic vowels', () => {  	})).toBe('eː');  }); + + +test('correctly output basic consonants', () => { +	expect(lang.consonantFeaturesToIpa({ +		place: lang.ConsonantPlace.Bilabial, +		manner: lang.ConsonantManner.Nasal, +		voice: true, +	})).toBe('m'); +	expect(lang.consonantFeaturesToIpa({ +		place: lang.ConsonantPlace.Uvular, +		manner: lang.ConsonantManner.NonSibilantFricative, +		voice: true, +	})).toBe('ʁ'); +	expect(lang.consonantFeaturesToIpa({ +		place: lang.ConsonantPlace.Velar, +		manner: lang.ConsonantManner.Plosive, +		voice: false, +	})).toBe('k'); +}); + + +test('fail to output impossible consonants', () => { +	expect(lang.consonantFeaturesToIpa({ +		place: lang.ConsonantPlace.Retroflex, +		manner: lang.ConsonantManner.NonSibilantAffricate, +		voice: false, +	})).toBe(''); +	expect(lang.consonantFeaturesToIpa({ +		place: lang.ConsonantPlace.Labiodental, +		manner: lang.ConsonantManner.Trill, +		voice: true, +	})).toBe(''); +	expect(lang.consonantFeaturesToIpa({ +		place: lang.ConsonantPlace.Palatal, +		manner: lang.ConsonantManner.Approximant, +		voice: false, +	})).toBe(''); +}); diff --git a/src/language.ts b/src/language.ts index 2d0f547..0721e09 100644 --- a/src/language.ts +++ b/src/language.ts @@ -19,6 +19,8 @@ export interface VowelFeatures {  	long: boolean;  	nasal: boolean;  } + +// convert a set of vowel features to an IPA representation  export function vowelFeaturesToIpa(features: VowelFeatures): string {  	const ipa = () => {  		switch (features.height) { @@ -101,3 +103,380 @@ export function vowelFeaturesToIpa(features: VowelFeatures): string {  	const vlong = features.long ? 'ː' : '';  	return ipa() + nasal + vlong;  } + + +export enum ConsonantPlace { +	Bilabial, +	Labiodental, +	Linguolabial, +	Dental, +	Alveolar, +	Postalveolar, +	Retroflex, +	Palatal, +	Velar, +	Uvular, +	Pharyngeal, +	Glottal, +} +export enum ConsonantManner { +	Nasal, +	Plosive, +	SibilantAffricate, +	NonSibilantAffricate, +	SibilantFricative, +	NonSibilantFricative, +	Approximant, +	Tap, +	Trill, +	LateralAffricate, +	LateralFricative, +	LateralApproximant, +	LateralTap, +} +export interface ConsonantFeatures { +	place: ConsonantPlace; +	manner: ConsonantManner; +	voice: boolean; +} + + +export function consonantFeaturesToIpa(features: ConsonantFeatures): string { +	switch (features.place) { +		case ConsonantPlace.Bilabial: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'm' : 'm̥'; +			case ConsonantManner.Plosive: +			return features.voice ? 'b' : 'p'; +			case ConsonantManner.SibilantAffricate: +			return ''; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'bβ' : 'pɸ'; +			case ConsonantManner.SibilantFricative: +			return ''; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'β' : 'ɸ'; +			case ConsonantManner.Approximant: +			return features.voice ? 'β̞' : ''; +			case ConsonantManner.Tap: +			return features.voice ? 'ⱱ̟' : ''; +			case ConsonantManner.Trill: +			return features.voice ? 'ʙ' : 'ʙ̥'; +			case ConsonantManner.LateralAffricate: +			case ConsonantManner.LateralFricative: +			case ConsonantManner.LateralApproximant: +			case ConsonantManner.LateralTap: +			return ''; +		} + +		case ConsonantPlace.Labiodental: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'ɱ' : 'ɱ̊'; +			case ConsonantManner.Plosive: +			return features.voice ? 'b̪' : 'p̪'; +			case ConsonantManner.SibilantAffricate: +			return ''; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'b̪v' : 'p̪f'; +			case ConsonantManner.SibilantFricative: +			return ''; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'v' : 'f'; +			case ConsonantManner.Approximant: +			return features.voice ? 'ʋ' : ''; +			case ConsonantManner.Tap: +			return features.voice ? 'ⱱ' : ''; +			case ConsonantManner.Trill: +			case ConsonantManner.LateralAffricate: +			case ConsonantManner.LateralFricative: +			case ConsonantManner.LateralApproximant: +			case ConsonantManner.LateralTap: +			return ''; +		} + +		case ConsonantPlace.Linguolabial: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'n̼' : ''; +			case ConsonantManner.Plosive: +			return features.voice ? 'd̼' : 't̼'; +			case ConsonantManner.SibilantAffricate: +			case ConsonantManner.NonSibilantAffricate: +			case ConsonantManner.SibilantFricative: +			return ''; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ð̼' : 'θ̼'; +			case ConsonantManner.Approximant: +			return ''; +			case ConsonantManner.Tap: +			return features.voice ? 'ɾ̼' : ''; +			case ConsonantManner.Trill: +			case ConsonantManner.LateralAffricate: +			case ConsonantManner.LateralFricative: +			case ConsonantManner.LateralApproximant: +			case ConsonantManner.LateralTap: +			return ''; +		} + +		case ConsonantPlace.Dental: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'n' : 'n̥'; +			case ConsonantManner.Plosive: +			return features.voice ? 'd̪' : 't̪'; +			case ConsonantManner.SibilantAffricate: +			return features.voice ? 'd̪z̪' : 't̪s̪'; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'd̪ð' : 't̪θ'; +			case ConsonantManner.SibilantFricative: +			return features.voice ? 'z' : 's'; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ð' : 'θ'; +			case ConsonantManner.Approximant: +			return features.voice ? 'ð̞' : ''; +			case ConsonantManner.Tap: +			return features.voice ? 'ɾ' : 'ɾ̥'; +			case ConsonantManner.Trill: +			return features.voice ? 'r' : 'r̥'; +			case ConsonantManner.LateralAffricate: +			return features.voice ? 'dɮ' : 'tɬ'; +			case ConsonantManner.LateralFricative: +			return features.voice ? 'ɮ' : 'ɬ'; +			case ConsonantManner.LateralApproximant: +			return features.voice ? 'l̪' : ''; +			case ConsonantManner.LateralTap: +			return features.voice ? 'ɺ' : 'ɺ̥'; +		} + +		case ConsonantPlace.Alveolar: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'n' : 'n̥'; +			case ConsonantManner.Plosive: +			return features.voice ? 'd' : 't'; +			case ConsonantManner.SibilantAffricate: +			return features.voice ? 'dz' : 'ts'; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'dɹ̝' : 'tɹ̝̊'; +			case ConsonantManner.SibilantFricative: +			return features.voice ? 'z' : 's'; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ð̠' : 'θ̠'; +			case ConsonantManner.Approximant: +			return features.voice ? 'ɹ' : ''; +			case ConsonantManner.Tap: +			return features.voice ? 'ɾ' : 'ɾ̥'; +			case ConsonantManner.Trill: +			return features.voice ? 'r' : 'r̥'; +			case ConsonantManner.LateralAffricate: +			return features.voice ? 'dɮ' : 'tɬ'; +			case ConsonantManner.LateralFricative: +			return features.voice ? 'ɮ' : 'ɬ'; +			case ConsonantManner.LateralApproximant: +			return features.voice ? 'l' : ''; +			case ConsonantManner.LateralTap: +			return features.voice ? 'ɺ' : 'ɺ̥'; +		} + +		case ConsonantPlace.Postalveolar: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'n' : 'n̥'; +			case ConsonantManner.Plosive: +			return features.voice ? 'd' : 't'; +			case ConsonantManner.SibilantAffricate: +			return features.voice ? 'd̠ʒ' : 't̠ʃ'; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'd̠ɹ̠˔' : 't̠ɹ̠̊˔'; +			case ConsonantManner.SibilantFricative: +			return features.voice ? 'ʒ' : 'ʃ'; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ɹ̠˔' : 'ɹ̠̊˔'; +			case ConsonantManner.Approximant: +			return features.voice ? 'ɹ̠' : ''; +			case ConsonantManner.Tap: +			return features.voice ? 'r̠' : 'ɾ̥'; +			case ConsonantManner.Trill: +			return features.voice ? 'r' : 'r̥'; +			case ConsonantManner.LateralAffricate: +			return features.voice ? 'dɮ' : 'tɬ'; +			case ConsonantManner.LateralFricative: +			return features.voice ? 'ɮ' : 'ɬ'; +			case ConsonantManner.LateralApproximant: +			return features.voice ? 'l̠' : ''; +			case ConsonantManner.LateralTap: +			return features.voice ? 'ɺ' : 'ɺ̥'; +		} + +		case ConsonantPlace.Retroflex: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'ɳ' : 'ɳ̊'; +			case ConsonantManner.Plosive: +			return features.voice ? 'ɖ' : 'ʈ'; +			case ConsonantManner.SibilantAffricate: +			return features.voice ? 'dʐ' : 'tʂ'; +			case ConsonantManner.NonSibilantAffricate: +			return ''; +			case ConsonantManner.SibilantFricative: +			return features.voice ? 'ʐ' : 'ʂ'; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ɻ˔' : 'ɻ̊˔'; +			case ConsonantManner.Approximant: +			return features.voice ? 'ɻ' : ''; +			case ConsonantManner.Tap: +			return features.voice ? 'ɽ' : 'ɽ̊'; +			case ConsonantManner.Trill: +			return features.voice ? 'ɽr' : 'ɽ̊r̥'; +			case ConsonantManner.LateralAffricate: +			return features.voice ? 'd𝼅' : 'tꞎ'; +			case ConsonantManner.LateralFricative: +			return features.voice ? '𝼅' : 'ꞎ'; +			case ConsonantManner.LateralApproximant: +			return features.voice ? 'ɭ' : ''; +			case ConsonantManner.LateralTap: +			return features.voice ? '𝼈' : '𝼈̥'; +		} + +		case ConsonantPlace.Palatal: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'ɲ' : 'ɲ̊'; +			case ConsonantManner.Plosive: +			return features.voice ? 'ɟ' : 'c'; +			case ConsonantManner.SibilantAffricate: +			return features.voice ? 'dʑ' : 'tɕ'; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'ɟʝ' : 'cç'; +			case ConsonantManner.SibilantFricative: +			return features.voice ? 'ʑ' : 'ɕ'; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ʝ' : 'ç'; +			case ConsonantManner.Approximant: +			return features.voice ? 'j' : ''; +			case ConsonantManner.Tap: +			case ConsonantManner.Trill: +			return ''; +			case ConsonantManner.LateralAffricate: +			return features.voice ? 'ɟʎ̝' : 'c𝼆'; +			case ConsonantManner.LateralFricative: +			return features.voice ? 'ʎ̝' : '𝼆'; +			case ConsonantManner.LateralApproximant: +			return features.voice ? 'ʎ' : ''; +			case ConsonantManner.LateralTap: +			return features.voice ? 'ʎ̆' : ''; +		} + +		case ConsonantPlace.Velar: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'ŋ' : 'ŋ̊'; +			case ConsonantManner.Plosive: +			return features.voice ? 'g' : 'k'; +			case ConsonantManner.SibilantAffricate: +			return ''; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'ɡɣ' : 'kx'; +			case ConsonantManner.SibilantFricative: +			return ''; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ɣ' : 'x'; +			case ConsonantManner.Approximant: +			return features.voice ? 'ɰ' : ''; +			case ConsonantManner.Tap: +			case ConsonantManner.Trill: +			return ''; +			case ConsonantManner.LateralAffricate: +			return features.voice ? 'ɡʟ̝' : 'k𝼄'; +			case ConsonantManner.LateralFricative: +			return features.voice ? 'ʟ̝' : '𝼄'; +			case ConsonantManner.LateralApproximant: +			return features.voice ? 'ʟ' : ''; +			case ConsonantManner.LateralTap: +			return features.voice ? 'ʟ̆' : ''; +		} + +		case ConsonantPlace.Uvular: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return features.voice ? 'ɴ' : 'ɴ̥'; +			case ConsonantManner.Plosive: +			return features.voice ? 'ɢ' : 'q'; +			case ConsonantManner.SibilantAffricate: +			return ''; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'ɢʁ' : 'qχ'; +			case ConsonantManner.SibilantFricative: +			return ''; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ʁ' : 'χ'; +			case ConsonantManner.Approximant: +			return features.voice ? 'ʁ̞' : ''; +			case ConsonantManner.Tap: +			return features.voice ? 'ɢ̆' : ''; +			case ConsonantManner.Trill: +			return features.voice ? 'ʀ' : 'ʀ̥'; +			case ConsonantManner.LateralAffricate: +			case ConsonantManner.LateralFricative: +			return ''; +			case ConsonantManner.LateralApproximant: +			return features.voice ? 'ʟ̠' : ''; +			case ConsonantManner.LateralTap: +			return ''; +		} + +		case ConsonantPlace.Pharyngeal: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return ''; +			case ConsonantManner.Plosive: +			return features.voice ? '' : 'ʡ'; +			case ConsonantManner.SibilantAffricate: +			return ''; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? 'ʡʢ' : 'ʡʜ'; +			case ConsonantManner.SibilantFricative: +			return ''; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ʕ' : 'ħ'; +			case ConsonantManner.Approximant: +			return ''; +			case ConsonantManner.Tap: +			return features.voice ? 'ʡ̆' : ''; +			case ConsonantManner.Trill: +			return features.voice ? 'ʢ' : 'ʜ'; +			case ConsonantManner.LateralAffricate: +			case ConsonantManner.LateralFricative: +			case ConsonantManner.LateralApproximant: +			case ConsonantManner.LateralTap: +			return ''; +		} + +		case ConsonantPlace.Glottal: +		switch (features.manner) { +			case ConsonantManner.Nasal: +			return ''; +			case ConsonantManner.Plosive: +			return features.voice ? '' : 'ʔ'; +			case ConsonantManner.SibilantAffricate: +			return ''; +			case ConsonantManner.NonSibilantAffricate: +			return features.voice ? '' : 'ʔh'; +			case ConsonantManner.SibilantFricative: +			return ''; +			case ConsonantManner.NonSibilantFricative: +			return features.voice ? 'ɦ' : 'h'; +			case ConsonantManner.Approximant: +			return features.voice ? 'ʔ̞' : ''; +			case ConsonantManner.Tap: +			case ConsonantManner.Trill: +			case ConsonantManner.LateralAffricate: +			case ConsonantManner.LateralFricative: +			case ConsonantManner.LateralApproximant: +			case ConsonantManner.LateralTap: +			return ''; +		} +	} +} | 
