{"id":19777483,"url":"https://github.com/ilib-js/ilib-name","last_synced_at":"2025-06-30T10:37:16.711Z","repository":{"id":62186386,"uuid":"521837438","full_name":"iLib-js/ilib-name","owner":"iLib-js","description":"Parse and format names of people","archived":false,"fork":false,"pushed_at":"2022-10-26T16:22:00.000Z","size":1167,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-06-02T18:11:03.457Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","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/iLib-js.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}},"created_at":"2022-08-06T03:36:56.000Z","updated_at":"2024-04-08T01:38:23.000Z","dependencies_parsed_at":"2022-10-28T02:18:44.080Z","dependency_job_id":null,"html_url":"https://github.com/iLib-js/ilib-name","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/iLib-js/ilib-name","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-name","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-name/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-name/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-name/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/iLib-js","download_url":"https://codeload.github.com/iLib-js/ilib-name/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/iLib-js%2Filib-name/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262756894,"owners_count":23359609,"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":"2024-11-12T05:25:16.226Z","updated_at":"2025-06-30T10:37:16.668Z","avatar_url":"https://github.com/iLib-js.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ilib-name\n\nLibrary to parse and format names of people\n\n## Installation\n\n```\nnpm install ilib-name\n\nor\n\nyarn add ilib-name\n```\n\n## API Reference\n\nYou can see the [generated API reference docs](./docs/ilibName.md)\nfor full details.\n\n## Motivation\n\nWhy would you want to parse and format names?\n\nLet's say you have a part of your web site that allows your users to enter some contacts. You may have a name field and an email field. The name field is a single field where they can type the whole name of their contact. Now, you would probably also have a page that lists the contacts in alphabetical order, and the user may be able to click on the last name or first name column to sort by that field.\n\nThe problem is... what is the last name or each contact? What is the first name? In English, you might be tempted to just take the first word in the whole name as the first name, and the last word as the last name. But what if the user has typed in a prefix or suffix like \"Dr. John Smith, PhD.\"? That algorithm won't even work in English, as that contact's name would end up being \"Dr. PhD.\".\n\nNow things get even more complicated when you have to support multiple languages. Some languages typically reverse the order of the names. For this reason, iLib never deals with \"first\" and \"last\" name, as it doesn't even make sense for those languages. Instead, it uses the terms \"given name\" and \"family name\", which are unambiguous and do not depend on order.\n\nThere is even more fun to be had if you try to parse names in other langauges. Here is a table of example names in various languages and how they are parsed.\n\n| Locale                           | Name                          | prefix | given  | middle | family            | suffix |\n|----------------------------------|-------------------------------|--------|--------|--------|-------------------|--------|\n| English for the US (en-US)       | Dr. John James Smith Jr.      | Dr.    | John   | James  | Smith             | Jr.    |\n| German for Germany (de-DE)       | Ludwig von Beethoven          |        | Ludwig |        | von Beethoven     |        |\n| Spanish for Spain (es-ES)        | Jose Manuel Rodriguez Mendoza |        | Jose   | Manuel | Rodriguez Mendoza |        |\n| Korean for South Korea (ko-KR)   | 김인환                        |        | 인환   |        | 김                |        |\n| Indonesian for Indonesia (id-ID) | Sukarno                       |        | Sukamo |        |                   |        |\n\nNote that in English example, we have the prefixes and suffixes to deal with. It turns out that many other languages have prefixes and suffixes too.\n\nIn German, the auxiliary word \"von\" is considered part of the family name. However, when sorting by family name, \"von Beethoven\" would appear under the B's, not the V's, as auxiliaries are ignored. That is, German is sorted by \"head word\" of the family name rather than the first word of the family name.\n\nIn Spain, many people have a given name first, followed by one or more middle names, followed by their father's family name, and followed finally their mother's family name. So in the example above, Jose's family name is \"Rodriguez Mendoza\" where \"Rodriguez\" is Jose's father's family name, and \"Mendoza\" is Jose's mother's family name. If you were to shorten the name, Jose would probably prefer \"Jose Rodriguez\" instead of \"Jose Mendoza\", and Jose's children would get the name \"Rodriguez\" as well.\n\nIn Korean, as in Chinese and Japanese, the family name comes first, followed by the given name with no space in between. In Chinese and Japanese, sometimes only the first character is the family name, and some times up to 3 characters. Either way, the parts of the name have to be teased apart without help from a separating space.\n\nOther languages have reversed order as well. In Hungarian, it is common to have reverse order, as in \"Kovacs Ernie\" instead of \"Ernie Kovacs\" as he is known in the US. In Russian, it is even more complicated, as it is common to write names both in western order and in reverse. Russian speakers can recognize the order easily, as they are very familiar with customs used to create names. Ilyanov is a patronymic name form, and any Russian speaker would recognize it immediately as a family name, no matter where it appeared in the whole name.\n\nIn Indonesia, it is common for people to have only a given name, especially for older folks or people who live outside of large metropolises, or even to have multiple names but no family name. You might be identified more specifically by naming your parents, such as \"Sukarno child of Suparman and Wulandari\". Relatively recently, it has become more common to have a patronymic name appended to your given name, such as \"Sukarno Suparmanputra\". Appending patronymics is also common in Iceland as well.\n\nGiven all the above, the humble Javascript programmer needs a little help to parse and format names so they don't have to be an expert in a large number of languages. Enter ilib-name.\n\n\n## Parsing Names with ilib-name\n\nParsing names is a simple matter of creating an instance of the Name class. Here is an example:\n\n~~~~~~\n{\n    prefix: \"Dr.\",\n    givenName: \"John\",\n    middleName: \"James\",\n    familyName: \"Smith\",\n    suffix: \", Jr.\"\n}\n~~~~~~\n\n\n## Parsing in Other Languages\n\nJust like other iLib classes, you can pass in options to the constructor to control how the parsing proceeds. For example, let's say you want to parse the name in Korean instead:\n\n~~~~~~\nimport { Name } from 'ilib-name';\n\nconst name = new Name(\"김인환\", {locale: \"ko-KR\"});\n~~~~~~\n\nOr if you are using older Javascript:\n\n~~~~~~\nvar NamePkg = require(\"ilib-name\");\nvar Name = NamePkg.Name;\n\nvar name = new Name(\"김인환\", {locale: \"ko-KR\"});\n~~~~~~\n\nNow the properties are:\n\n~~~~~~\n{\n    givenName: \"인환\",\n    familyName: \"김\"\n}\n~~~~~~\n\n\n## Mixed Sets of Names in Asian Languages\n\nIt is typical in a contact list of a person who speaks an Asian language to have a mix of both Asian names and Western names together in varying degrees. The iLib parser can deal with this situation properly when parsing in Asian locales by checking if the name contains any Asian characters in it. If a name contains at least one Asian character, it assumes that the name is an Asian name. If it contains all non-Asian characters, it is assumed to be a Western style name.\n\nThat means the following will still work properly:\n\n~~~~~~\nimport { Name } from 'ilib-name';\n\nconst name = new Name(\"Dr. John James Smith, Jr.\", {locale: \"ko-KR\"});\n~~~~~~\n\nor in older Javascript:\n\n~~~~~~\nvar NamePkg = require(\"ilib-name\");\nvar Name = NamePkg.Name;\n\nvar name = new Name(\"Dr. John James Smith, Jr.\", {locale: \"ko-KR\"});\n~~~~~~\n\nNow, the \"name\" variable should contain the following properties:\n\n~~~~~~\n{\n    prefix: \"Dr.\",\n    givenName: \"John\",\n    middleName: \"James\",\n    familyName: \"Smith\",\n    suffix: \", Jr.\"\n}\n~~~~~~\n\n\n## It Doesn't Work All the Time\n\nThere are many types of names and strings where the parser does not work properly. Don't expect that it should work in 100% of the cases!\n\nFor example, in some Exchange-based contact systems, the administrator may have decided to append the name of an employee's division to each name automatically. Thus, the name \"John Smith (Mortgages and Loans Group)\" will not be parsed corrected. This poor fellow's name is not \"John Group)\"!\n\nIf needed, the parser can be upgraded in the future to support more things and special cases. Please let us know if you have a very common case that is not supported. (email to \"marketing@jedlsoft.com\")\n\n\n## Formatting Names\n\nIn some contacts services, such as Google Contacts, names are given as whole names in a single string, and you need the parser documented in the previous section to decipher the parts of the name.\n\nOther services, such as Outlook/Exchange, give you names that are broken down by field. This is much less ambiguous and makes it easy to sort by a particular name, but it presents a problem if you want to display that name on the screen. What order do you use? What if you don't want to present all the parts of the name and you just want the short version?\n\nThere is where you would use the class NameFmt to reassemble the parts into a single string. Here is an example:\n\n~~~~~~\nimport { Name, NameFmt } from 'ilib-name';\n\n// presumably, these parts came from Outlook or some such service\nconst name = new Name({\n    prefix: \"Dr.\",\n    givenName: \"John\",\n    middleName: \"James\",\n    familyName: \"Smith\",\n    suffix: \", Jr.\"\n});\nconst nf = new NameFmt();\nconst formatted = nf.format(name);\n~~~~~~\n\nor in older Javascript:\n\n~~~~~~\nvar NamePkg = require(\"ilib-name\");\nvar Name = NamePkg.Name;\nvar NameFmt = NamePkg.NameFmt;\n\n// presumably, these parts came from Outlook or some such service\nvar name = new Name({\n    prefix: \"Dr.\",\n    givenName: \"John\",\n    middleName: \"James\",\n    familyName: \"Smith\",\n    suffix: \", Jr.\"\n});\nvar nf = new NameFmt();\nvar formatted = nf.format(name);\n~~~~~~\n\nNow the name in the \"formatted\" variable will appear as the string:\n\n\n\u003e John Smith\n\n\nLet's say you wanted the full name instead where all the parts are assembled in the correct order. In this case, the formatter also takes options to its constructor:\n\n~~~~~~\nimport { Name, NameFmt } from 'ilib-name';\n\n// presumably, these parts came from Outlook or some such service\nconst name = new Name({\n    prefix: \"Dr.\",\n    givenName: \"John\",\n    middleName: \"James\",\n    familyName: \"Smith\",\n    suffix: \", Jr.\"\n});\nconst nf = new NameFmt({style: \"full\"});\nconst formatted = nf.format(name)\n~~~~~~\n\nOr in older Javascript:\n\n~~~~~~\nvar NamePkg = require(\"ilib-name\");\nvar Name = NamePkg.Name;\nvar NameFmt = Name.NameFmt;\n\n// presumably, these parts came from Outlook or some such service\nvar name = new Name({\n    prefix: \"Dr.\",\n    givenName: \"John\",\n    middleName: \"James\",\n    familyName: \"Smith\",\n    suffix: \", Jr.\"\n});\nvar nf = new NameFmt({style: \"full\"});\nvar formatted = nf.format(name)\n~~~~~~\n\nThe entire name will be re-assembled as:\n\n\u003e Dr. John James Smith, Jr.\n\n\n## Collating Family Names\n\nAs mentioned in a previous section, German groups the auxiliary words along with the family name for display, but not for collation sorting. In the case of sorting, you have to get the head word of the name. Dutch also follows these rules, by the way.\n\nThere are two methods of the Name class you can use.\n\nFirst, you can get the head word directly:\n\n~~~~~~\nimport { Name } from \"ilib-name\";\n\nvar name = new Name(\"Ludwig von Beethoven\", {locale: \"de-AT\"});\nvar headname = name.getHeadFamilyName();\n~~~~~~\n\nor in older Javascript:\n\n~~~~~~\nvar NamePkg = require(\"ilib-name\");\nvar Name = NamePkg.Name;\n\nvar name = new Name(\"Ludwig von Beethoven\", {locale: \"de-AT\"});\nvar headname = name.getHeadFamilyName();\n~~~~~~\n\nNow the variable \"headname\" will contain:\n\n\u003e Beethoven\n\nAlternately, you can use the method \"getSortFamilyName\" to get a re-ordered version of the family name that you can use directly for sorting.\n\n~~~~~~\nimport { Name } from \"ilib-name\";\n\nvar name = new Name(\"Pieter van der Veen\", {locale: \"nl-NL\"});\nvar sortname = name.getSortFamilyName();\n~~~~~~\n\nor in older Javascript:\n\n~~~~~~\nvar Name = require(\"ilib/lib/Name.js\");\n\nvar name = new Name(\"Pieter van der Veen\", {locale: \"nl-NL\"});\nvar sortname = name.getSortFamilyName();\n~~~~~~\n\nNow the variable \"sortname\" will contain this string with the head word first, followed by a comma, followed by all the auxiliaries:\n\n\u003e Veen, van der\n\n## Asynchronous Operation\n\nAll the above examples are shown synchronously. Like all other ilib ESM code,\nthis library can be use in asynch mode. Both the Name and the NameFmt class\nhave a static `create()` that is a factory method which creates a new\ninstance asynchronously and returns a Promise. This would be useful in a\nbrowser environment with webpack when the locale data is not yet loaded.\n\nExample of parsing a name asynchronously:\n\n~~~~~~\nimport { Name } from 'ilib-name';\n\n\nName.create(\"Dr. John James Smith, Jr.\", {locale: \"ko-KR\"}).then((name) =\u003e {\n    // do something with the name fields\n});\n~~~~~~\n\n## License\n\nCopyright © 2013-2015, 2018, 2022, JEDLSoft\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\nSee the License for the specific language governing permissions and\nlimitations under the License.\n\n## Release Notes\n\n### v1.0.0\n\n* Copied code from ilib v14.15.0\n    * converted to ES modules\n    * Added Name.create() factory method for asynch operation\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filib-js%2Filib-name","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Filib-js%2Filib-name","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Filib-js%2Filib-name/lists"}