{"id":25279899,"url":"https://github.com/canclid/to-jyutping","last_synced_at":"2025-10-27T16:31:01.990Z","repository":{"id":57377367,"uuid":"457757746","full_name":"CanCLID/to-jyutping","owner":"CanCLID","description":"粵語拼音自動標註工具 Cantonese Pronunciation Automatic Labeling Tool","archived":false,"fork":false,"pushed_at":"2023-05-06T21:29:09.000Z","size":125,"stargazers_count":6,"open_issues_count":3,"forks_count":1,"subscribers_count":8,"default_branch":"main","last_synced_at":"2024-04-25T21:43:43.043Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CanCLID.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-10T11:47:41.000Z","updated_at":"2024-07-15T07:55:28.293Z","dependencies_parsed_at":"2024-07-15T08:16:00.341Z","dependency_job_id":null,"html_url":"https://github.com/CanCLID/to-jyutping","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CanCLID%2Fto-jyutping","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CanCLID%2Fto-jyutping/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CanCLID%2Fto-jyutping/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CanCLID%2Fto-jyutping/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CanCLID","download_url":"https://codeload.github.com/CanCLID/to-jyutping/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238523987,"owners_count":19486601,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-12T18:05:12.903Z","updated_at":"2025-10-27T16:31:01.534Z","avatar_url":"https://github.com/CanCLID.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# to-jyutping\n\n[![npm](https://img.shields.io/npm/v/to-jyutping)](https://www.npmjs.com/package/to-jyutping) [![types](https://img.shields.io/npm/types/to-jyutping)](https://www.npmjs.com/package/to-jyutping) [![license](https://img.shields.io/npm/l/to-jyutping)](https://www.npmjs.com/package/to-jyutping)\n\n### 粵語拼音自動標註工具 Cantonese Pronunciation Automatic Labeling Tool\n\n## Installation\n\n```shell\nnpm install to-jyutping\n```\n\n### Via CDN\n\n```html\n\u003cscript src=\"https://unpkg.com/to-jyutping@3.1.1\" defer\u003e\u003c/script\u003e\n```\n\n### In Other Languages\n\n- [Python (pip) Version](https://pypi.org/project/ToJyutping/) ([Repo](https://github.com/CanCLID/ToJyutping))\n\n## Usage\n\nFor the 8 basic functions, examples are worth a thousand words:\n\n```js\nimport ToJyutping from \"to-jyutping\";\n\n\u003e ToJyutping.getJyutpingList(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n[[\"咁\", \"gam3\"], [\"啱\", \"ngaam1\"], [\"老\", \"lou5\"], [\"世\", \"sai3\"], [\"要\", \"jiu1\"], [\"求\", \"kau4\"], [\"佢\", \"keoi5\"], [\"等\", \"dang2\"], [\"陣\", \"zan6\"], [\"要\", \"jiu3\"], [\"開\", \"hoi1\"], [\"會\", \"wui2\"], [\"，\", null], [\"剩\", \"zing6\"], [\"低\", \"dai1\"], [\"嘅\", \"ge3\"], [\"嘢\", \"je5\"], [\"我\", \"ngo5\"], [\"會\", \"wui5\"], [\"搞\", \"gaau2\"], [\"掂\", \"dim6\"], [\"㗎\", \"gaa3\"], [\"喇\", \"laa3\"], [\"。\", null]]\n\n\u003e ToJyutping.getJyutping(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n\"咁(gam3)啱(ngaam1)老(lou5)世(sai3)要(jiu1)求(kau4)佢(keoi5)等(dang2)陣(zan6)要(jiu3)開(hoi1)會(wui2)，剩(zing6)低(dai1)嘅(ge3)嘢(je5)我(ngo5)會(wui5)搞(gaau2)掂(dim6)㗎(gaa3)喇(laa3)。\"\n\n\u003e ToJyutping.getJyutpingText(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n\"gam3 ngaam1 lou5 sai3 jiu1 kau4 keoi5 dang2 zan6 jiu3 hoi1 wui2 zing6 dai1 ge3 je5 ngo5 wui5 gaau2 dim6 gaa3 laa3\"\n\n\u003e ToJyutping.getJyutpingCandidates(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n[[\"咁\", [\"gam3\", \"gam2\", \"gam1\", \"gam4\"]], [\"啱\", [\"ngaam1\", \"aam1\", \"am1\", \"ngam1\"]], [\"老\", [\"lou5\", \"lou2\"]], [\"世\", [\"sai3\", \"sai2\"]], [\"要\", [\"jiu1\", \"jiu3\", \"jiu2\"]], [\"求\", [\"kau4\"]], [\"佢\", [\"keoi5\", \"heoi5\"]], [\"等\", [\"dang2\"]], [\"陣\", [\"zan6\", \"zan2\"]], [\"要\", [\"jiu3\", \"jiu2\", \"jiu1\"]], [\"開\", [\"hoi1\"]], [\"會\", [\"wui2\", \"wui5\", \"wui6\", \"wui3\", \"kui2\", \"kui3\", \"kwui2\"]], [\"，\", []], [\"剩\", [\"zing6\", \"sing6\"]], [\"低\", [\"dai1\"]], [\"嘅\", [\"ge3\", \"ge2\", \"koi2\", \"koi3\"]], [\"嘢\", [\"je5\", \"e5\"]], [\"我\", [\"ngo5\", \"o5\"]], [\"會\", [\"wui5\", \"wui6\", \"wui2\", \"wui3\", \"kui2\", \"kui3\", \"kwui2\"]], [\"搞\", [\"gaau2\"]], [\"掂\", [\"dim6\", \"dim3\", \"dim1\"]], [\"㗎\", [\"gaa3\", \"ga3\", \"gaa2\", \"gaa1\", \"gaa4\"]], [\"喇\", [\"laa3\", \"laa1\", \"laak3\", \"laa5\", \"laat3\"]], [\"。\", []]]\n\n\u003e ToJyutping.getIPAList(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n[[\"咁\", \"kɐm˧\"], [\"啱\", \"ŋaːm˥\"], [\"老\", \"lou̯˩˧\"], [\"世\", \"sɐi̯˧\"], [\"要\", \"jiːu̯˥\"], [\"求\", \"kʰɐu̯˨˩\"], [\"佢\", \"kʰɵy̑˩˧\"], [\"等\", \"tɐŋ˧˥\"], [\"陣\", \"t͡sɐn˨\"], [\"要\", \"jiːu̯˧\"], [\"開\", \"hɔːi̯˥\"], [\"會\", \"wuːi̯˧˥\"], [\"，\", null], [\"剩\", \"t͡seŋ˨\"], [\"低\", \"tɐi̯˥\"], [\"嘅\", \"kɛː˧\"], [\"嘢\", \"jɛː˩˧\"], [\"我\", \"ŋɔː˩˧\"], [\"會\", \"wuːi̯˩˧\"], [\"搞\", \"kaːu̯˧˥\"], [\"掂\", \"tiːm˨\"], [\"㗎\", \"kaː˧\"], [\"喇\", \"laː˧\"], [\"。\", null]]\n\n\u003e ToJyutping.getIPA(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n\"咁[kɐm˧]啱[ŋaːm˥]老[lou̯˩˧]世[sɐi̯˧]要[jiːu̯˥]求[kʰɐu̯˨˩]佢[kʰɵy̑˩˧]等[tɐŋ˧˥]陣[t͡sɐn˨]要[jiːu̯˧]開[hɔːi̯˥]會[wuːi̯˧˥]，剩[t͡seŋ˨]低[tɐi̯˥]嘅[kɛː˧]嘢[jɛː˩˧]我[ŋɔː˩˧]會[wuːi̯˩˧]搞[kaːu̯˧˥]掂[tiːm˨]㗎[kaː˧]喇[laː˧]。\"\n\n\u003e ToJyutping.getIPAText(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n\"kɐm˧.ŋaːm˥.lou̯˩˧.sɐi̯˧.jiːu̯˥.kʰɐu̯˨˩.kʰɵy̑˩˧.tɐŋ˧˥.t͡sɐn˨.jiːu̯˧.hɔːi̯˥.wuːi̯˧˥.t͡seŋ˨.tɐi̯˥.kɛː˧.jɛː˩˧.ŋɔː˩˧.wuːi̯˩˧.kaːu̯˧˥.tiːm˨.kaː˧.laː˧\"\n\n\u003e ToJyutping.getIPACandidates(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n[[\"咁\", [\"kɐm˧\", \"kɐm˧˥\", \"kɐm˥\", \"kɐm˨˩\"]], [\"啱\", [\"ŋaːm˥\", \"aːm˥\", \"ɐm˥\", \"ŋɐm˥\"]], [\"老\", [\"lou̯˩˧\", \"lou̯˧˥\"]], [\"世\", [\"sɐi̯˧\", \"sɐi̯˧˥\"]], [\"要\", [\"jiːu̯˥\", \"jiːu̯˧\", \"jiːu̯˧˥\"]], [\"求\", [\"kʰɐu̯˨˩\"]], [\"佢\", [\"kʰɵy̑˩˧\", \"hɵy̑˩˧\"]], [\"等\", [\"tɐŋ˧˥\"]], [\"陣\", [\"t͡sɐn˨\", \"t͡sɐn˧˥\"]], [\"要\", [\"jiːu̯˧\", \"jiːu̯˧˥\", \"jiːu̯˥\"]], [\"開\", [\"hɔːi̯˥\"]], [\"會\", [\"wuːi̯˧˥\", \"wuːi̯˩˧\", \"wuːi̯˨\", \"wuːi̯˧\", \"kʰuːi̯˧˥\", \"kʰuːi̯˧\", \"kʷʰuːi̯˧˥\"]], [\"，\", []], [\"剩\", [\"t͡seŋ˨\", \"seŋ˨\"]], [\"低\", [\"tɐi̯˥\"]], [\"嘅\", [\"kɛː˧\", \"kɛː˧˥\", \"kʰɔːi̯˧˥\", \"kʰɔːi̯˧\"]], [\"嘢\", [\"jɛː˩˧\", \"ɛː˩˧\"]], [\"我\", [\"ŋɔː˩˧\", \"ɔː˩˧\"]], [\"會\", [\"wuːi̯˩˧\", \"wuːi̯˨\", \"wuːi̯˧˥\", \"wuːi̯˧\", \"kʰuːi̯˧˥\", \"kʰuːi̯˧\", \"kʷʰuːi̯˧˥\"]], [\"搞\", [\"kaːu̯˧˥\"]], [\"掂\", [\"tiːm˨\", \"tiːm˧\", \"tiːm˥\"]], [\"㗎\", [\"kaː˧\", \"kɐ˧\", \"kaː˧˥\", \"kaː˥\", \"kaː˨˩\"]], [\"喇\", [\"laː˧\", \"laː˥\", \"laːk̚˧\", \"laː˩˧\", \"laːt̚˧\"]], [\"。\", []]]\n```\n\nFor `getJyutpingCandidates` and `getIPACandidates`, pronunciations are sorted according to how likely they are to be correct in a sentence, with the first being the most likely.\n\nMethods may also be imported individually:\n\n```js\n\u003e import { getJyutpingList } from \"to-jyutping\";\n\u003e getJyutpingList(\"咁啱老世要求佢等陣要開會，剩低嘅嘢我會搞掂㗎喇。\");\n\"gam3 ngaam1 lou5 sai3 jiu1 kau4 keoi5 dang2 zan6 jiu3 hoi1 wui2, zing6 dai1 ge3 je5 ngo5 wui5 gaau2 dim6 gaa3 laa3.\"\n```\n\nIn rare cases, the pronunciation of a single character can contain more than one syllable:\n\n```js\n\u003e ToJyutping.getJyutpingList(\"一瓩\");\n[[\"一\", \"jat1\"], [\"瓩\", \"cin1 ngaa5\"]]\n\u003e ToJyutping.getIPAList(\"一瓩\");\n[[\"一\", \"jɐt̚˥\"], [\"瓩\", \"t͡sʰiːn˥.ŋaː˩˧\"]]\n```\n\nThey are mostly dated ligature characters (合字) coined to represent units with SI prefixes.\n\n## Custom Entries \u0026 Existing Entries Overriding or Exclusion\n\nWith an accuracy rate of 99%, the possibility of needing an adjustment is rare. However, Cantonese, like other varieties of Chinese, is mostly written in logographs, which means that homographs (同形詞) that are indistinguishable out of context can occur. Consider the following sentence:\n\n\u003e 上堂終於講到分數\n\nIn the above sentence, there are multiple possible pronunciations of 上, 到 and 分, and their meanings are different depending on how they are actually pronounced:\n\n| Pronunciation | Meaning |\n| --- | --- |\n| soeng**5** tong4 zung1 jyu1 gong2 dou**3** fan**1** sou3 | Attending the lesson, it finally came to talk about scores.\u003cbr\u003e_(Perhaps the scores weren’t available until today.)_ |\n| soeng**5** tong4 zung1 jyu1 gong2 dou**3** fan**6** sou3 | Attending the lesson, it finally came to talk about fractions.\u003cbr\u003e_(Perhaps the progress of the math class was slow.)_ |\n| soeng**5** tong4 zung1 jyu1 gong2 dou**2** fan**1** sou3 | Attending the lesson, eventually it was able to talk about scores.\u003cbr\u003e_(Perhaps the teacher wasn’t allowed to reveal the scores until today.)_ |\n| soeng**5** tong4 zung1 jyu1 gong2 dou**2** fan**6** sou3 | Attending the lesson, eventually it was able to talk about fractions.\u003cbr\u003e_(Perhaps the introduction to fractions requires some other concepts to be taught.)_ |\n| soeng**6** tong4 zung1 jyu1 gong2 dou**3** fan**1** sou3 | The previous lesson finally came to talk about scores.\u003cbr\u003e_(Perhaps the teacher just made the scores available right before the previous lesson.)_ |\n| soeng**6** tong4 zung1 jyu1 gong2 dou**3** fan**6** sou3 | The previous lesson finally came to talk about fractions.\u003cbr\u003e_(Perhaps the students just managed to catch up the progress in the math class.)_ |\n| soeng**6** tong4 zung1 jyu1 gong2 dou**2** fan**1** sou3 | Eventually, it was able to talk about scores in the previous lesson.\u003cbr\u003e_(Perhaps the teacher was finally allowed to reveal the scores in the previous lesson.)_ |\n| soeng**6** tong4 zung1 jyu1 gong2 dou**2** fan**6** sou3 | Eventually, it was able to talk about fractions in the previous lesson.\u003cbr\u003e_(Perhaps the teacher just finished teaching the other concepts required for learning fractions.)_ |\n\nThus, the library offers the ability to include custom entries and override or exclude built-in entries:\n\n```js\n\u003e ToJyutping.getJyutpingText(\"上堂終於講到分數\");\n\"soeng5 tong4 zung1 jyu1 gong2 dou3 fan1 sou3\"\n\n\u003e const converterLesson = ToJyutping.customize({ 上堂: null, 分數: \"fan6 sou3\" });\n\u003e converterLesson.getJyutpingText(\"上堂終於講到分數\");\n\"soeng6 tong4 zung1 jyu1 gong2 dou3 fan6 sou3\"\n```\n\nIn the above example:\n\n- By default, the library special-cases the pronunciation of 上堂 to “soeng5 tong4”. Setting `上堂` to `null` removes the special case and both 上 and 堂 now fallback to the their default pronunciations, which are “soeng6” and “tong4” respectively.\n- By default, the library does not special-case 分數. Thus, the pronunciations of each individual characters, which in this case are “fan1” and “sou3”, are used. By including the entry `分數` and setting it to `fan6 sou3`, the converter outputs `fan6 sou3` when `分數` is encountered.\n\nIn general, setting any built-in entry to `null` or `undefined` fallbacks it to shorter matches and ultimately individual character pronunciations if there isn’t a match:\n\n```js\n\u003e ToJyutping.getJyutpingText(\"好學生\");\n\"hou2 hok6 saang1\"\n\n\u003e const converterStudious = ToJyutping.customize({ 好學生: null });\n\u003e converterStudious.getJyutpingText(\"好學生\");\n\"hou3 hok6 saang1\" // Using shorter matches 好學 and 生\n\n\u003e const converterGoodStudent = converterStudious.customize({ 好學: null });\n\u003e converterGoodStudent.getJyutpingText(\"好學生\");\n\"hou2 hok6 saang1\" // Using individual character pronunciations as it can’t be decomposed further\n```\n\nConverters can be chained without affecting each other:\n\n```js\n\u003e const converterDou2 = converterLesson.customize({ 到: \"dou2\" });\n\u003e const converterNull = converterLesson.customize({ 到: null });\n\n\u003e converterDou2.getJyutpingText(\"上堂終於講到分數\");\n\"soeng6 tong4 zung1 jyu1 gong2 dou2 fan6 sou3\"\n\n\u003e converterNull.getJyutpingText(\"上堂終於講到分數\");\n\"soeng6 tong4 zung1 jyu1 gong2 […] fan6 sou3\"\n\n\u003e ToJyutping.getJyutpingText(\"上堂終於講到分數\");\n\"soeng5 tong4 zung1 jyu1 gong2 dou3 fan1 sou3\" // Also not affected\n```\n\n\u003e [!WARNING]\n\u003e\n\u003e - This library only offers basic customization functionality. If there are longer built-in word entries, they aren’t overridden:\n\u003e\n\u003e   ```js\n\u003e   \u003e converterDou2.getJyutpingText(\"笑到轆地\");\n\u003e   \"siu3 dou3 luk1 dei2\"\n\u003e\n\u003e   \u003e converterNull.getJyutpingText(\"笑到轆地\");\n\u003e   \"siu3 dou3 luk1 dei2\"\n\u003e\n\u003e   \u003e const converterAnotherLesson = ToJyutping.customize({ 上: null, 分: \"fan6\" });\n\u003e   \u003e converterAnotherLesson.getJyutpingText(\"上堂終於講到分數\");\n\u003e   \"soeng5 tong4 zung1 jyu1 gong2 dou3 fan6 sou3\"\n\u003e   ```\n\u003e\n\u003e   In the second example, their isn’t an entry for 分數, so 分 is patched successfully. However, this is not the case for 上 since the longer built-in entry 上堂 is prioritized.\n\u003e\n\u003e - The original pronunciations will be lost. If you are using `getJyutpingCandidates` or `getIPACandidates`, you will need to include the pronunciations manually:\n\u003e   ```js\n\u003e   \u003e const 到OriginalPronunciations = ToJyutping.getJyutpingCandidates(\"到\");\n\u003e   \u003e 到OriginalPronunciations\n\u003e   [[\"到\", [\"dou3\", \"dou2\"]]]\n\u003e   \u003e const converterDou2Dou3 = converterLesson.customize({ 到: [\"dou2\", ...到OriginalPronunciations[0][1]] });\n\u003e   \u003e converterDou2Dou3.getJyutpingCandidates(\"到\");\n\u003e   [[\"到\", [\"dou2\", \"dou3\"]]]\n\u003e   ```\n\u003e   Notice how the library automatically deduplicates the values for you.\n\n### Helper\n\n```js\n\u003e ToJyutping.jyutpingToIPA(\"jat1\");\n\"jɐt̚˥\"\n\u003e ToJyutping.jyutpingToIPA(\"cin1 ngaa5\");\n\"t͡sʰiːn˥.ŋaː˩˧\"\n```\n\nNote that autocorrection is intentionally not included in this helper, and an error is thrown if strings like `jyt6` are passed into the function.\nPunctuation is ignored in the helper.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcanclid%2Fto-jyutping","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcanclid%2Fto-jyutping","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcanclid%2Fto-jyutping/lists"}