{"id":45976090,"url":"https://github.com/jacksonllee/iso639","last_synced_at":"2026-02-28T16:32:16.000Z","repository":{"id":37533513,"uuid":"218055121","full_name":"jacksonllee/iso639","owner":"jacksonllee","description":"ISO 639 language codes","archived":false,"fork":false,"pushed_at":"2026-01-31T15:07:10.000Z","size":1125,"stargazers_count":52,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-01T02:32:38.234Z","etag":null,"topics":["iso639","iso639-1","iso639-2","iso639-3","language-codes"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jacksonllee.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-10-28T13:38:38.000Z","updated_at":"2026-01-31T17:10:33.000Z","dependencies_parsed_at":"2024-02-08T05:26:04.874Z","dependency_job_id":"26948809-11d9-4f93-b057-e247abd884df","html_url":"https://github.com/jacksonllee/iso639","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/jacksonllee/iso639","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacksonllee%2Fiso639","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacksonllee%2Fiso639/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacksonllee%2Fiso639/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacksonllee%2Fiso639/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jacksonllee","download_url":"https://codeload.github.com/jacksonllee/iso639/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jacksonllee%2Fiso639/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29942842,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-28T13:49:17.081Z","status":"ssl_error","status_checked_at":"2026-02-28T13:48:50.396Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["iso639","iso639-1","iso639-2","iso639-3","language-codes"],"created_at":"2026-02-28T16:32:15.382Z","updated_at":"2026-02-28T16:32:15.984Z","avatar_url":"https://github.com/jacksonllee.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# python-iso639\n\n[![PyPI version](https://badge.fury.io/py/python-iso639.svg)](https://pypi.org/project/python-iso639/)\n[![Supported Python versions](https://img.shields.io/pypi/pyversions/python-iso639.svg)](https://pypi.org/project/python-iso639/)\n[![PyPI downloads last month](https://img.shields.io/pypi/dm/python-iso639)](https://pypi.org/project/python-iso639/)\n[![CircleCI Builds](https://circleci.com/gh/jacksonllee/iso639.svg?style=shield)](https://circleci.com/gh/jacksonllee/iso639)\n\n`python-iso639` is a Python package for ISO 639 language codes, names, and\nother associated information.\n\nCurrent features:\n\n* 🌐 A representation of languages mapped across ISO 639-1, 639-2, and 639-3.\n* 🔎 Functionality to \"guess\" what a language is for a given\n  unknown language code or name.\n* 🚀 Optimized for speed in retrieving language information.\n\n## Installation\n\n```bash\npip install python-iso639\n```\n\n## Usage\n\n`python-iso639` revolves around a `Language` class.\nInstances of `Language` have attributes and methods that you will find useful.\n\nNote that while the package name registered on PyPI is `python-iso639`,\nthe actual import name during runtime is `iso639`\n(which means you should do `import iso639` in your Python code).\n\n### Creating `Language` Instances\n\nCreate a `Language` instance by one of the class methods.\n\n#### `from_part3`, with an ISO 639-3 code\n\n```python\n\u003e\u003e\u003e import iso639\n\u003e\u003e\u003e lang1 = iso639.Language.from_part3('fra')\n\u003e\u003e\u003e type(lang1)\n\u003cclass 'iso639.language.Language'\u003e\n\u003e\u003e\u003e lang1\nLanguage(part3='fra', part2b='fre', part2t='fra', part1='fr', scope='I', type='L', name='French', comment=None, other_names=None, macrolanguage=None, retire_reason=None, retire_change_to=None, retire_remedy=None, retire_date=None)\n```\n\nFast object instantiation for retrieving language information (run on Python 3.13, macOS 15.3.1, Apple M1 Pro)\n\n```python\nIn [1]: import iso639\n\nIn [2]: %timeit iso639.Language.from_part3(\"fra\")\n217 ns ± 0.139 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)\n```\n\n#### From Another ISO 639 Code Set or a Reference Name\n\n```python\n\u003e\u003e\u003e lang2 = iso639.Language.from_part2b('fre')  # ISO 639-2 (bibliographic)\n\u003e\u003e\u003e lang3 = iso639.Language.from_part2t('fra')  # ISO 639-2 (terminological)\n\u003e\u003e\u003e lang4 = iso639.Language.from_part1('fr')  # ISO 639-1\n\u003e\u003e\u003e lang5 = iso639.Language.from_name('French')  # ISO 639-3 reference language name\n```\n\n#### A `LanguageNotFoundError` is Raised for Invalid Inputs\n\n```python\n\u003e\u003e\u003e iso639.Language.from_part3('Fra')  # The user input is case-sensitive!\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\nLanguageNotFoundError: 'Fra' isn't an ISO language code or name\n\u003e\u003e\u003e\n\u003e\u003e\u003e iso639.Language.from_name(\"unknown language\")\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\nLanguageNotFoundError: 'unknown language' isn't an ISO language code or name\n```\n\n### Accessing Attributes\n\n```python\n\u003e\u003e\u003e lang1\nLanguage(part3='fra', part2b='fre', part2t='fra', part1='fr', scope='I', type='L', name='French', comment=None, other_names=None, macrolanguage=None, retire_reason=None, retire_change_to=None, retire_remedy=None, retire_date=None)\n\u003e\u003e\u003e lang1.part3\n'fra'\n\u003e\u003e\u003e lang1.name\n'French'\n```\n\n### Comparison\n\n```python\n\u003e\u003e\u003e lang1 == lang2 == lang3 == lang4 == lang5  # All are French\nTrue\n\u003e\u003e\u003e lang6 = iso639.Language.from_part3('spa')  # Spanish\n\u003e\u003e\u003e lang1 == lang6  # French vs. Spanish\nFalse\n\u003e\u003e\u003e 'French' == lang1.name == lang2.name == lang3.name == lang4.name == lang5.name\nTrue\n\u003e\u003e\u003e lang6.name\n'Spanish'\n```\n\n### Guess a Language: Classmethod `match`\n\nYou don't know which code set or name your input is from?\nUse the `match` classmethod:\n\n```python\n\u003e\u003e\u003e lang1 = iso639.Language.match('fra')\n\u003e\u003e\u003e lang2 = iso639.Language.match('fre')\n\u003e\u003e\u003e lang3 = iso639.Language.match('fr')\n\u003e\u003e\u003e lang4 = iso639.Language.match('French')\n\u003e\u003e\u003e lang1 == lang2 == lang3 == lang4\nTrue\n```\n\nBy default, the classmethod `match` is case-sensitive.\nTo ignore case instead, pass in `strict_case=False`:\n\n```python\n\u003e\u003e\u003e lang5 = iso639.Language.match('FRA', strict_case=False)\n\u003e\u003e\u003e lang6 = iso639.Language.match('french', strict_case=False)\n\u003e\u003e\u003e lang4 == lang5 == lang6\nTrue\n\u003e\u003e\u003e iso639.Language.match(\"french\")\nTraceback (most recent call last):\n  File \"\u003cstdin\u003e\", line 1, in \u003cmodule\u003e\nLanguageNotFoundError: 'french' isn't an ISO language code or name\n```\n\n\u003e [!NOTE]  \n\u003e Depending on your use case, ignoring case could potentially lead to matching issues,\n  where a language code might match an unintended language name (or vice versa),\n  e.g., conflating \"igo\" and \"Igo\", while there exist the ISO 639-3 code `ahl` for Igo and\n  the ISO 639-3 code `igo` for Isebe. \n\nThe classmethod `match` is particularly useful for consistently\naccessing a specific attribute from unknown inputs, e.g., the ISO 639-3 code.\n\n```python\n\u003e\u003e\u003e 'fra' == lang1.part3 == lang2.part3 == lang3.part3 == lang4.part3 == lang5.part3 == lang6.part3 == lang7.part3\nTrue\n```\n\nIf there's no match, a `LanguageNotFoundError` is raised,\nwhich you may want to catch:\n\n```python\n\u003e\u003e\u003e try:\n...     lang = iso639.Language.match('not gonna find a match')\n... except iso639.LanguageNotFoundError:\n...     print(\"no match found!\")\n... \nno match found!\n```\n\n### Macrolanguages and Alternative Names\n\n```python\n\u003e\u003e\u003e language = iso639.Language.match('yue')\n\u003e\u003e\u003e language.name\n'Yue Chinese'  # also commonly known as Cantonese\n\u003e\u003e\u003e language.macrolanguage\n'zho'  # Chinese\n\u003e\u003e\u003e language.other_names\n[Name(print='Yue Chinese', inverted='Chinese, Yue')]\n\u003e\u003e\u003e for name in language.other_names:\n...     print(f'{name.print} | {name.inverted}')\n...\nYue Chinese | Chinese, Yue\n```\n\n### Retired Language Codes:\n\n```python\n\u003e\u003e\u003e language = iso639.Language.match('bvs')\n\u003e\u003e\u003e language.part3\n'bvs'\n\u003e\u003e\u003e language.name\n'Belgian Sign Language'\n\u003e\u003e\u003e language.status\n'R'  # (R)etired\n\u003e\u003e\u003e language.retire_reason\n'S'  # (S)plit\n\u003e\u003e\u003e language.retire_change_to is None\nTrue\n\u003e\u003e\u003e language.retire_remedy\n'Split into Langue des signes de Belgique Francophone [sfb], and Vlaamse Gebarentaal [vgt]'\n\u003e\u003e\u003e language.retire_date\ndatetime.date(2007, 7, 18)\n```\n\n## Into the Weeds\n\n### Attributes of a `Language` Instance\n\nA `Language` instance has the following attributes:\n\n| Attribute          | Data type       | Can it be `None`? | Description                                                                                                           |\n|--------------------|-----------------|-------------------|-----------------------------------------------------------------------------------------------------------------------|\n| `part3`            | `str`           | ✗                 | ISO 639-3 code                                                                                                        |\n| `part2b`           | `str`           | ✓                 | ISO 639-2 code (bibliographic)                                                                                        |\n| `part2t`           | `str`           | ✓                 | ISO 639-2 code (terminological)                                                                                       |\n| `part1`            | `str`           | ✓                 | ISO 639-1 code                                                                                                        |\n| `scope`            | `str`           | ✗                 | One of {(I)ndividual, (M)acrolanguage, (S)pecial}                                                                     |\n| `type`             | `str`           | ✓                 | One of {(A)ncient, (C)onstructed, (E)xtinct, (H)istorical, (L)iving, (S)pecial} [1]                                   |\n| `status`           | `str`           | ✗                 | One of {(A)ctive, (R)etired}, describing the ISO 639-3 code                                                           |\n| `name`             | `str`           | ✗                 | Reference language name in ISO 639-3                                                                                  |\n| `comment`          | `str`           | ✓                 | Comment from ISO 639-3                                                                                                |\n| `other_names`      | `list[Name]`    | ✓                 | Other print and inverted names [2]                                                                                    |\n| `macrolanguage`    | `str`           | ✓                 | Macrolanguage                                                                                                         |\n| `retire_reason`    | `str`           | ✓                 | Retirement reason, one of {(C)hange, (D)uplicate, (N)on-existent, (S)plit, (M)erge}                                   |\n| `retire_change_to` | `str`           | ✓                 | ISO 639-3 code to which this language can be changed, if retirement reason is one of {(C)hange, (D)uplicate, (M)erge} |\n| `retire_remedy`    | `str`           | ✓                 | Instructions for updating this retired language code                                                                  |\n| `retire_date`      | `datetime.date` | ✓                 | The date the retirement became effective                                                                              |\n\n[1] If the ISO 639-3 code is retired, then the `type` attribute is `None`,\n    because its value is not clearly discernible from the SIL data source.\n\n[2] A `Name` instance has the attributes `print` and `inverted`,\n    for the print name and inverted name, respectively.\n    If reference name, print name, and inverted name are all the same, then\n    that particular (print name, inverted name) pair is excluded from\n    the `other_names` attribute.\n    For example, for Spanish (ISO 639-3: spa), one (print name, inverted name)\n    pair is (Spanish, Spanish) from the SIL data source, but this pair is\n    excluded from its list of `other_names`.\n\n### How `Language.match` Matches the Language\n\nAt a high level, `Language.match` assumes the input is more likely to be\na language code rather than a language name.\nBeyond that, the precise order in matching is as follows:\n\n* ISO 639-3 codes (among the active codes)\n* ISO 639-2 (bibliographic) codes\n* ISO 639-2 (terminological) codes\n* ISO 639-1 codes\n* ISO 639-3 codes (among the retired codes)\n* ISO 639-3 reference language names\n* ISO 639-3 alternative language names (the \"print\" ones)\n* ISO 639-3 alternative language names (the \"inverted\" ones)\n\nAs soon as a match is found, `Language.match` returns a `Language` instance.\nIf there isn't a match, a `LanguageNotFoundError` is raised.\n\n### `Language` is a dataclass\n\nThe `Language` class is a dataclass.\nAll functionality of\n[dataclasses](https://docs.python.org/3/library/dataclasses.html)\napplies to `Language` and its instances,\ne.g., [`dataclasses.asdict`](https://docs.python.org/3/library/dataclasses.html#dataclasses.asdict):\n\n```python\n\u003e\u003e\u003e import dataclasses, iso639\n\u003e\u003e\u003e language = iso639.Language.match('fra')\n\u003e\u003e\u003e dataclasses.asdict(language)\n{'part3': 'fra', 'part2b': 'fre', 'part2t': 'fra', 'part1': 'fr', 'scope': 'I', 'type': 'L', 'status': 'A', 'name': 'French', 'comment': None, 'other_names': None, 'macrolanguage': None, 'retire_reason': None, 'retire_change_to': None, 'retire_remedy': None, 'retire_date': None}\n```\n\n### Constants\n\n* `DATA_LAST_UPDATED`: The release date of the included language code data from SIL\n\n    ```python\n    \u003e\u003e\u003e import iso639\n    \u003e\u003e\u003e iso639.DATA_LAST_UPDATED\n    datetime.date(2026, 1, 15)\n    ```\n\n* `ALL_LANGUAGES`: The list of all `Language` objects based on the included language code data\n\n    ```python\n    \u003e\u003e\u003e import iso639\n    \u003e\u003e\u003e type(iso639.ALL_LANGUAGES)\n    \u003cclass 'set'\u003e\n    \u003e\u003e\u003e len(iso639.ALL_LANGUAGES)\n    8313\n    ```\n\n## Links\n\n* Author: [Jackson L. Lee](https://jacksonllee.com)\n* Source code: https://github.com/jacksonllee/iso639\n\n## License and Data Source\n\nThe `python-iso639` code is released under an Apache 2.0 license.\nPlease see [LICENSE.txt](https://github.com/jacksonllee/iso639/blob/main/LICENSE.txt)\nfor details.\n\nThe data source that backs this package is the\n[language code tables published by SIL](https://iso639-3.sil.org/code_tables/download_tables).\nThe tables are included in this package under [`src/iso639/_data/`](src/iso639/_data/).\nThey are the UTF8-encoded `*.tab` tab-separated files bundled as a ZIP archive file,\ntypically found at a URL that looks like\n`https://iso639-3.sil.org/sites/iso639-3/files/downloads/iso-639-3_Code_Tables_YYYYMMDD.zip`\n(replace `YYYYMMDD` with the data release date).\nNote that SIL resources have their [terms of use](https://www.sil.org/terms-use).\n\n## Why Another ISO 639 Package?\n\nBoth packages [iso639](https://pypi.org/project/iso639/)\nand [iso-639](https://pypi.org/project/iso-639/) exist on PyPI.\nHowever, as of this writing (May 2022), they were last updated in 2016 and don't seem to be maintained anymore\nfor updating the language codes.\n[pycountry](https://pypi.org/project/pycountry/) is a great package,\nbut what if you want a more lightweight package with just the language codes only and not the other stuff? :-)\n\nIf you ever notice that the upstream ISO 639-3 tables from SIL have been updated\nand yet this package isn't using the latest data,\nplease ping me by [opening a GitHub issue](https://github.com/jacksonllee/iso639/issues).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjacksonllee%2Fiso639","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjacksonllee%2Fiso639","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjacksonllee%2Fiso639/lists"}