Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion docs/design/decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -814,12 +814,13 @@ Closes #346, #344 and #343 as one bundle: each CLASS is decided once, and each s

### salutation-titles — salutations, offices and ranks for the languages TITLES had none for (2026-10-04, #606)

Closes #606. No parser code moves: 41 words join TITLES and one, knt (Knight, beside kt), joins SUFFIX_ACRONYMS with a `Knt` case mask. The class is decided once — a word that addresses or ranks a person and is written in FRONT of the name — and each word is then argued on #vocabulary-collisions C-i, the position test, because TITLES has no ambiguous subset and the only two answers available are ship and do not ship. The per-word lists, grouped by language, are the #606 block in nameparser/config/titles.py.
Closes #606 (#662 later added owura and bapak, last bullet). No parser code moves: 41 words join TITLES and one, knt (Knight, beside kt), joins SUFFIX_ACRONYMS with a `Knt` case mask. The class is decided once — a word that addresses or ranks a person and is written in FRONT of the name — and each word is then argued on #vocabulary-collisions C-i, the position test, because TITLES has no ambiguous subset and the only two answers available are ship and do not ship. The per-word lists, grouped by language, are the #606 block in nameparser/config/titles.py.

- **The graf class, decided (Derek, 2026-10-04).** A word borne as a name, but RARELY as the first word of one, ships anyway, on the precedent of graf, which shipped though Steffi Graf exists. This is a judgment on each word's incidence in the leading position — the position C-i asks about — and not a rule, and it is an EXCEPTION to C-i rather than an application of it: C-i is an iff with no threshold, and herra, batoni, hrabia and kreivi were measured as borne in that position, so C-i says do not ship them (TITLES having no ambiguous subset to mark them in). What the exception adds is a weighing C-i does not make, a small measured incidence against the benefit of the title reading, and it is scoped to TITLES and to the words this entry names. It licenses nothing in the particle or suffix sets, and a later TITLES word that wants it is argued on its own counts. The title claim acts only in front, so most bearers are untouched in the forms they write: `Gladys Knight` and `Knight, Gladys` keep family Knight. The cost falls on a name that BEGINS with the word, the cost `Graf Steffi` already paid: `Greve Anna` reads title Greve, family Anna, and a given name is lost the same way, `Herra Wijaya` reading title Herra, family Wijaya. Declaring `FAMILY_FIRST` does not help, since the title claim is read before the order (`Hrabia Anna` reads title Hrabia under it); the family comma does. Two further limits, both pre-existing: a trailing period makes the word the title by rules.md#H5 (`Gladys Knight.` reads title `Knight.`, as `Mary Jane King.` does), and every word this entry adds widens that rule's reach, H5 claiming any listed title behind a period. Accepted rather than prevented, and stated at rules.md#H1's Accepted clause. The issue proposed the class for three words — greve (Scandinavian Count), graaf (Dutch Count), knight. The spot-check the issue asked for (forebears.io, 2026-10-04, worldwide counts rounded) found ten more of its "no known collision" words borne, and Derek extended the decision to all of them rather than excluding them: herra (~3,000 surnames, Costa Rica and the Dominican Republic; ~670 given-name uses, Indonesia and the Philippines), batoni (~1,100, the painter Pompeo Batoni; ~300 given-name uses, Tanzania), ponas (~4,000, Iran), counsel (~730, Australia, the US, England), ponia (~560), the Filipino ginoo, ginang and binibini (~500 each, Philippine lists writing Surname, Given with a comma), and two whose registers often write the surname first, hrabia (~750, Poland) and kreivi (~270, Finland). Those last two, and the given-name uses of herra and batoni, are the leading-position bearers this class accepts, and were decided on with their counts in hand. The line is NOT reproducible from this record, and that is said rather than hidden: the accepted side was counted, while the excluded side — thiru, puan, pan, rodina, ông/bà — was judged from general knowledge of each word, as #606 drafted it, with no count taken (the count source refused further lookups the same day). Each was judged a COMMON leading-position name, against counts in the hundreds on the accepted side; gróf was excluded for want of any evidence at all. Whoever decides κόμης or the next salutation should count the excluded words first, and is free to find the line in a different place. The comment `# borne` in titles.py marks each member, so a sweep meets the decision where it meets the word.
- **Accents are not folded, and two words depend on it.** `_lexicon._normalize` lowercases and composes NFC and does nothing else to letters, so paní and härra cannot match Pani (~76,000 surnames and ~65,000 given names, India and Indonesia) or Harra (~1,100). Accent-folding the lexicon would turn both into collisions; whoever proposes it re-argues this entry. frú depends on nothing: the unaccented fru (Swedish/Danish Mrs) already ships, so the Cameroonian surname Fru (~10,800, where the surname is often written first) already reads as a title in `Fru Anna` and did before this entry; that pre-existing collision is recorded here rather than argued, being no part of #606.
- **gravos was dropped, not excluded.** The issue listed it as the Latin-script Greek for Count; the spot-check could not confirm it is the Greek word at all, which is κόμης (kómis). Nothing was shown, so there is nothing to keep out — it is recorded here so that a later sweep starts from that rather than from the issue's table. κόμης itself is NOT added and NOT excluded: it is a Greek surname (~420 bearers in Greece, official lists writing the surname first), which by its counts sits inside the class above beside hrabia, and it was left out of this change for having no use in current Greek address rather than for its collision. Adding it is a decision still to make.
- **Measurement (2026-10-04).** One corpus name moves, `Greve Anna`, given Greve to title Greve: the rules.md#H1 example this entry added, and the only one of its three examples that moves. Recompute: take the 41 entries of the #606 block in titles.py — the lines that are a quoted string, not the words quoted inside its comments, which name existing entries and excluded ones — parse every distinct name in the tools/differential/corpus*.jsonl glob (1,518 on the day) with the shipped parser and with `Lexicon.default().remove(titles=<those words>, suffix_acronyms={"knt"})`, and diff `as_dict()`. Before the rules.md examples were added, the same diff moved nothing over the 1,809 corpus lines of the tree before #604 merged, gravos still in the word list. The old readings the release-log bullet quotes were checked against the 1.4.0 and 2.3.0 wheels.
- **2026-10-17 #662 — owura and bapak join TITLES; malam and bay are excluded.** Akan and Indonesian Mr., found in the CLDR corpus (`Owura Bertram…`, `Bapak Dwi Putro bin Adinata MP` read the salutation as the given name). Counts from `tools/name_usage.py` on 2026-10-17: owura and bapak each under 100 US Census bearers and none found on Wikidata (a zero proves nothing, per the tool). The two exclusions are in the Excluded (TITLES) block below. Measurement: two corpus names move, both in corpus_cldr.jsonl and both toward CLDR's fields (`Owura Bertram Wilberforce Henry Robert Wooster MP` and `Bapak Dwi Putro bin Adinata MP`, salutation from given to title); recompute with `uv run python tools/differential/snapshot.py --since <the commit before this entry>`. The release-log reading was checked against the 1.4.0, 2.0.0 and 2.4.2 wheels.

### generational-words — junior and senior in other languages (2026-10-14, #661)

Expand Down Expand Up @@ -965,6 +966,8 @@ Excluded (TITLES):
- cik, paron, tikin, janab (Latin spellings) — unverified, so not shipped. Latin janab follows the sri/shri pattern: Devanagari जनाब ships, and the Latin spelling needs its own check (2026-10-04, #606).
- marshal — a given name (Marshal Yanda). The accepted cost is that `Field Marshal Bernard Montgomery` keeps reading title Field, given Marshal (2026-10-04, #606).
- justice — a given name (Justice Smith). Likewise `Chief Justice John Roberts` keeps title Chief, given Justice (2026-10-04, #606).
- malam (Hausa teacher/Mr.) — a US Census surname (119), 5+ Wikidata family bearers and 1 Wikidata given-name bearer (Nigeria), a lower bound (2026-10-17, #662, `tools/name_usage.py malam`). CLDR's Hausa data files Malam as the title (`grep '"title": "Malam"' tools/differential/cldr_fields.jsonl`), the opposite of the evidence that decided shehu, so this is a decline on the counts, not a shehu-style removal: Derek dropped it for the lower-bound given-name use, and whoever re-argues it should count Hausa given-name use first. The accepted cost is `Malam Shehu Bello` reading given Malam.
- bay (Turkish Mr.) — a US surname with 6,350 bearers and 120 on Wikidata, 11 of them Hungarian; Hungarian writes the surname first, where the title claim acts, so it fails C-i (2026-10-17, #662).
- shehu (Hausa honorific) — a common Hausa given name and an Albanian and Nigerian surname, so the leading title claim took the given name of `Shehu Shagari`, a former president of Nigeria, who read title Shehu, family Shagari in every release from 1.4.0 through 2.4.1. It arrived with an early bulk import (1a51555f) and was never put to C-i; removed 2026-10-13 (#660). Counts from `tools/name_usage.py shehu` on 2026-10-13: 561 US Census surname bearers; on Wikidata 180 family-name bearers (Nigeria 20, Albania 11) and 1 given-name bearer (Nigeria), a lower bound, since Shagari's own entry has no given-name statement. Not weighed under the graf class (#salutation-titles), and the counts above would not settle that weighing: the one leading-position figure, the single Wikidata given-name bearer, is a lower bound and sits below herra's ~670, while the 561 and 180 are family-name bearers, a position C-i does not ask about. The evidence that Shehu leads a name is not a count. It is Shagari himself, and CLDR's Hausa sample data in this tree, whose six renderings carrying the word all file it as the given name (`grep '"given": "Shehu"' tools/differential/cldr_fields.jsonl`). Whoever re-argues the word should count Hausa given-name use first. The accepted cost is the honorific use, `Shehu Abubakar` reading given Shehu as any untitled name does; it belongs in an opt-in pack if anyone asks for it. Moved three CLDR corpus names (`Shehu Muhammed`, `Muhammed, Shehu`, `Modibbo, Shehu Bello`), all three now agreeing with CLDR on every role, so they left `tools/differential/cldr_agreement.json` (moves: `uv run python tools/differential/snapshot.py --since v2.4.1`).
- The trailing-position rule that must NOT be adopted, and 2026-09-08 says what the line is: TITLES holds hundreds of words in no suffix set, at least nineteen of them ordinary English surnames (king, judge, bishop, baron, sheriff, ...), so a blanket "vocabulary outranks position in the trailing slot" reading would turn "Mary Jane King" into title="King" with the family name gone. The leading half of this argument is AGENTS.md's "Dean is deliberately absent" gotcha; this is the trailing half, and it shadows the family name rather than the given (#316). What #316 settled is that the prohibition is on BARE words: "Mary Jane King" still reads family King, while "John Smith Prof." reads title Prof. **The second half of that argument is RETRACTED 2026-09-09**, in review of the docs commit: "a period-marked trailing word being one nobody writes as a surname" claimed the period keeps the collision out of the trailing slot, and it does not. Measured on the branch tree — "Mary Jane King." reads title "King.", given Mary, family Jane, the family name shadowed exactly as the bare reading would have shadowed it, and "John Smith Judge." reads title "Judge." The reach is the vocabulary rather than a handful: of the 746 titles in no suffix set, 627 read as a trailing title once a period is written behind them, and every one of the 119 that do not is kept out by the abbreviation SHAPE — a digit, a hyphen, an apostrophe, or a script whose letters carry combining marks (rules.md#H2 records that half) — no plain ASCII-letter title missing at all. So king, judge, bishop, baron and sheriff ARE reachable in the trailing slot; what the prohibition above buys is the bare spelling and nothing more. The period is a WRITING convention the rule can read, not evidence about the word, and reading it is an ACCEPTED COST under the premise that the input is a name (rules.md H Background): someone who ends a name with a period-marked word has written an abbreviation. rules.md#H5 carries it as an Accepted clause with "Mary Jane King." as the executable example. Recompute the reach with `L = Parser().lexicon; ws = [w for w in L.titles - L.suffix_acronyms - L.suffix_words if " " not in w]; len([w for w in ws if parse("Mary Jane %s." % w).title])` against `len(ws)` — 627 of 746 on 2026-09-09 — the digits move as the vocabulary grows and neither argument does. See #H5.

Expand Down
1 change: 1 addition & 0 deletions docs/release_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Release Log

- **Add junior and senior in other languages as suffixes.** ``Antonio Pavlović mlađi`` gives last ``Pavlović``, suffix ``mlađi``, where 1.4.0 through 2.4.2 gave middle ``Pavlović``, last ``mlađi``. The words come from 45 languages and are read when written as a separate word after the name. :issue:`661`, :issue:`679`
- **Remove mai from the default post-nominal acronyms, so a trailing Mai keeps the name.** ``Tran Thi Mai`` read in Vietnamese order (``FAMILY_FIRST_GIVEN_LAST``) gives given ``Mai``, middle ``Thi``, family ``Tran``, where 2.0.0 through 2.4.2 gave suffix ``Mai`` and no given name; ``Nguyen Mai`` gives family ``Mai``, as 1.4.0 did. The cost is that ``John Smith MAI`` gives last ``MAI`` instead of suffix; ``Smith, John, MAI`` and ``John Smith M.A.I.`` still read as credentials. A caller who needs it back adds it: ``Lexicon.default().add(suffix_acronyms={"mai"})``. See the ``suffix-acronym-collisions`` entry of ``docs/design/decisions.md`` (:issue:`687`)
- **Add the Akan and Indonesian salutations owura and bapak as titles.** ``Bapak Dwi Putro`` gives title ``Bapak``, first ``Dwi``, last ``Putro``, where 1.4.0 through 2.4.2 gave first ``Bapak``, middle ``Dwi``. :issue:`662`

* 2.4.2 - October 13, 2026

Expand Down
6 changes: 6 additions & 0 deletions nameparser/config/titles.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,12 @@
# English Knight, the rank the post-nominal 'knt' names.
'knight', # borne

# #662: Akan and Indonesian Mr.; under 100 census bearers each and
# none found on Wikidata. Hausa malam and Turkish bay are excluded
# (decisions.md, Excluded (TITLES)).
'owura',
'bapak',

# #269: Cyrillic (ru/uk) -- mr/mrs/dr/prof/academician/pan(i)
# honorifics, same title-then-family convention as 'mr'/'dr'/'prof'
# above (not GIVEN_NAME_TITLES: "г-н Петров" families the surname
Expand Down
15 changes: 15 additions & 0 deletions tests/v2/cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1728,6 +1728,21 @@ def _check_cjk_shape_purity(self) -> None:
"Greve, Anna",
{"given": "Anna", "family": "Greve"},
notes="the family comma fixes the surname (#606)"),
Case("salutation_in_indonesian", "Bapak Dwi Putro",
{"title": "Bapak", "given": "Dwi", "family": "Putro"},
classification="fix(#662)",
notes="bapak (Indonesian Mr.) was read as the given name "
"(decisions.md#salutation-titles)"),
Case("salutation_in_akan", "Owura Kwame Mensah",
{"title": "Owura", "given": "Kwame", "family": "Mensah"},
classification="fix(#662)",
notes="owura (Akan Mr.), likewise"),
Case("akan_salutation_trailing_is_a_name_word", "Kwame Mensah Owura",
{"given": "Kwame", "middle": "Mensah", "family": "Owura"},
notes="the title claim acts only in front (#662)"),
Case("akan_salutation_before_a_comma_is_a_name_word", "Owura, Kwame",
{"given": "Kwame", "family": "Owura"},
notes="the family comma fixes the surname (#662)"),
Case("knt_is_a_post_nominal", "Sir John Smith Knt",
{"title": "Sir", "given": "John", "family": "Smith",
"suffix": "Knt"},
Expand Down
19 changes: 2 additions & 17 deletions tools/differential/cldr_agreement.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,6 @@
},
"text": "Sinbad"
},
"ak/nativeFull/givenFirst": {
"given_names": {
"expected": "Bertram Wilberforce Henry Robert",
"got": "Owura Bertram Wilberforce Henry Robert"
},
"text": "Owura Bertram Wilberforce Henry Robert Wooster MP",
"title": {
"expected": "Owura",
"got": ""
}
},
"ak/nativeFull/sorting": {
"given_names": {
"expected": "Bertram Wilberforce Henry Robert",
Expand Down Expand Up @@ -4667,13 +4656,9 @@
},
"given_names": {
"expected": "Dwi Putro bin",
"got": "Bapak Dwi Putro"
"got": "Dwi Putro"
},
"text": "Bapak Dwi Putro bin Adinata MP",
"title": {
"expected": "Bapak",
"got": ""
}
"text": "Bapak Dwi Putro bin Adinata MP"
},
"id/nativeFull/sorting": {
"family": {
Expand Down
4 changes: 2 additions & 2 deletions tools/differential/snapshot.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@
{"name": "Balóch Karima Mehráb", "order": "FAMILY_FIRST", "given": "Karima", "middle": "Mehráb", "family": "Balóch", "initials": "K. M. B."}
{"name": "Balóch Wj. Monir Mómen Monir Mómen", "order": "FAMILY_FIRST", "given": "Wj.", "middle": "Monir Mómen Monir Mómen", "family": "Balóch", "initials": "W. M. M. M. M. B."}
{"name": "Bapak Adinata, Dwi Putro bin MP", "order": "FAMILY_FIRST", "given": "Dwi", "middle": "Putro", "family": "bin Bapak Adinata", "suffix": "MP", "ambiguities": ["PARTICLE_OR_GIVEN"], "initials": "D. P. B. A."}
{"name": "Bapak Dwi Putro bin Adinata MP", "given": "Bapak", "middle": "Dwi Putro", "family": "bin Adinata", "suffix": "MP", "initials": "B. D. P. A."}
{"name": "Bapak Dwi Putro bin Adinata MP", "title": "Bapak", "given": "Dwi", "middle": "Putro", "family": "bin Adinata", "suffix": "MP", "initials": "D. P. A."}
{"name": "Barbara Brukalska", "given": "Barbara", "family": "Brukalska", "initials": "B. B."}
{"name": "Barbara Scharf", "given": "Barbara", "family": "Scharf", "initials": "B. S."}
{"name": "Barbara Scharf, CPPM", "given": "Barbara", "family": "Scharf", "suffix": "CPPM", "initials": "B. S."}
Expand Down Expand Up @@ -2393,7 +2393,7 @@
{"name": "Ospina Pérez, Mariano", "given": "Mariano", "family": "Ospina Pérez", "initials": "M. O. P."}
{"name": "Otto III.", "given": "Otto", "suffix": "III.", "ambiguities": ["GIVEN_OR_FAMILY"], "initials": "O."}
{"name": "Outrein, Johannes d'", "given": "Johannes", "middle": "d'", "family": "Outrein", "initials": "J. d. O."}
{"name": "Owura Bertram Wilberforce Henry Robert Wooster MP", "given": "Owura", "middle": "Bertram Wilberforce Henry Robert", "family": "Wooster", "suffix": "MP", "initials": "O. B. W. H. R. W."}
{"name": "Owura Bertram Wilberforce Henry Robert Wooster MP", "title": "Owura", "given": "Bertram", "middle": "Wilberforce Henry Robert", "family": "Wooster", "suffix": "MP", "initials": "B. W. H. R. W."}
{"name": "Ozaki, Shirō", "given": "Shirō", "family": "Ozaki", "initials": "S. O."}
{"name": "Ozawa, Seiji", "given": "Seiji", "family": "Ozawa", "initials": "S. O."}
{"name": "Ozoliņš Pēteris", "order": "FAMILY_FIRST", "given": "Pēteris", "family": "Ozoliņš", "initials": "P. O."}
Expand Down
Loading