Package: pyclts
pycltsTooling to access and curateCLTS data.This is an attempt to create a system that allows to translate and compare different phonetic transcription systems.Installpycltsprovides a Python API forCLTS data.
Usingpycltsrequires this data to be available locally, either as repository
clone, or as unzipped download of areleased version.To installpycltsrunpip install pycltsThis will install the python API as well as a command line toolclts.
Both, require the location of the data as argument:>>>frompycltsimportCLTS>>>clts=CLTS('PATH/TO/clts')orclts--reposPATH/TO/cltsstatsTo save this effort, the data location can also be looked up in acldfcatalogconfig file, under the keyclts.Such a config file (and the repository clone) can be created automatically,
by installingcldfbenchand runningcldfbench catconfig(please note that command depends on thepyglottologandpyconcepticonlibraries).CompatibilityNote that the CLTS data release and thepycltsversionmust be compatible.pyclts< 3.0 works with CLTS data up to version 1.4.1pyclts>= 3.0 works with CLTS data >= 2.0OverviewUsingpycltsis exemplified in this short code snippet:>>>frompycltsimportCLTS>>>clts=CLTS('clts/')>>>asjp=clts.transcriptionsystem('asjpcode')>>>snd1=clts.bipa['ts']>>>snd2=asjp['c']>>>snd1.name'voiceless alveolar sibilant affricate consonant'>>>snd2.name'voiceless alveolar sibilant affricate consonant'>>>clts.bipa.translate('ts a ŋ ə',asjp)'c E N 3'>>>asjp.translate('C a y',clts.bipa)'tʃ ɐ j'Notes:Since "bipa" is the standard transcriptionsystem in CLTS, it's available - as shortcut -
directly asbipaattribute ofCLTS.We represent the soundstsandc, depending on the alphabet from which they are taken.Soundspycltscan not only deal with sound that are already in our database. Intead, We it tries to create "unknown" sounds automatically and infer its features from the set of diacritics and the base sound:>>>sound=clts.bipa['dʱʷ']>>>sound.name'labialized breathy voiced alveolar stop consonant'>>>sound.generatedTrue>>>sound.aliasTrue>>>print(sound)dʷʱ>>>print(sound.uname)LATINSMALLLETTERD/MODIFIERLETTERSMALLW/MODIFIERLETTERSMALLHWITHHOOK>>>print(sound.codepoints)U+0064U+02b7U+02b1You can see, since we represent breathy-voice phonation differently, we flag this sound as an alias. Also since it is not yet in our database explicitly coded, we flag it as a "generated" sound. In a similar way, you can generate sounds from their names:>>>sound=clts.bipa['pre-aspirated voiced aspirated bilabial stop consonant']>>>print(sound)ʰbʰ>>>sound.generatedTrue>>>sound.name'pre-aspirated aspirated voiced bilabial stop consonant'Note that this sound probably does not exist in any language, but we generate it from the feature components. Note also that thenamethat is automatically given for the sound automatically orders how the features are put together to form the sound identifier. In principle, our features bundles are unordered, but we try to decide for some explicit order of features to enhance comparison.Transcription systems and sound classesYou can also use our transcription data to convert from one transcription system to a given dataset (note that backwards-conversion may not be possible, as transcription data is often limited):>>>sca=clts.soundclass('sca')>>>clts.bipa.translate('f a: t ə r',sca)'B A T E R'The translation can also be done by loading the transcription data directly:>>>sca('v a t ə r')['B','A','T','E','R']Basic Structure of the Packagepycltsprovides access to three basic types of data:transcription systems (pyclts.transcriptionsystems.TranscriptionSystem), a system that cangeneratesoundstranscription data (pyclts.transcriptiondata.TranscriptionData): a dataset with afixed number of soundssound classes (pyclts.soundclasses.SoundClasses): a dataset with a direct mapping from sounds to a concrete character (the sound class)Transcription data is linked to our transcription system by the grapheme for the B(road) IPA transcription system, which serves as our default, and the name, which follows the IPA conventions with some modifications which were needed to make sure that we can represent sounds that we regularly find in cross-linguistic datasets.Parsing Procedurefeaturehandled bynoteexamplenormalizedts._norm(),ts[sound].normalizedthis refers to one-to-one character replacement with obviously wrong unicode lookalikesλ(wrong) vs.ʎ(correct)aliastranscription system data (+indicates alias),ts['sound'].aliasthis refers to "free" IPA variants that are widely used and are therefore officially accepted for "broad ipa" or any other TS, but one variant is usually chosen as the preferred onets(normal) vs.ʦ(alias)sourcets['sound'].sourcethe unnormalized form as it is given to the TSbipa['λ'].source == 'λ'graphemets[lingpy/'sound'].graphemethe normalized form which has not been resolved by an alias```bipa['ʦ'].grapheme == 'ʦ'string/unicodets['sound'].__unicode__()the normalized form in which a potential alias is replaced by its "accepted" counterpartstr(bipa['ʦ']) == 'ts'namebipa['sound'].namethe canonical representation of the feature system that defines a sound, with the sound class (consonant, cluster, vowel, diphthong) in the end, and the feature bundle following the order given in thepyclts.modelsdescription of the corresponding sound class. This representation serves as the basis for translation among different TS.bipa['ts'].name == 'voiceless alveolar sibilant-affricate consonant'generatedts['sound'].generatedIf a sound is not yet know to a given TS, the algorithm tries to generate it by de-composing it into itsbase partand adding features to the left and to the right, based on thediacritics. If a sound has been generated, this is traced with help of the attribute. Normally, generated sounds need to be double-checked by the experts, as their grapheme representation may be erroneous. Thus, while the soundkʷʰcan be regularly defined in a TS (like BIPA), a user might querykʰʷ, in which case the sound would be generated internally, the grapheme would be stored in its normalized form (which is identical with the base), but thestr()-representation would contain the correct order, and the character would be automatically qualified as an alias of an existing one.str(TS['kʰʷ']) == 'kʷʰ' and TS['kʰʷ'].grapheme == 'kʰʷ' and TS[''kʰʷ'].alias and TS['kʰʷ'].generatedbasets['sound'].baseif a sound is being generated, the parsing algorithm first tries to identify the potential "base" of the sound, i.e., a sound that is already known and explicitly defined in a given transcription system. Based on this base sound, the grapheme is then constructed by following the diacritics to the left and to the right. If the so-constructed feature bundle already exists in the transcription system, the constructed sound is treated as an alias, if it does not exist, the sound is only marked as being generated.str(TS['d̤ʷ']) == 'dʷʱ'