# `Localize.PersonName`
[🔗](https://github.com/elixir-localize/localize_person_names/blob/v0.1.0/lib/localize/person_name.ex#L1)

Locale-aware person name formatting built on the Unicode CLDR
person names specification.

A person name is represented as a `t:Localize.PersonName.t/0`
struct containing name parts (title, given name, surname, etc.)
plus optional locale and ordering preferences.

Formatting is driven by the locale's CLDR person name patterns,
which vary by length (`:short`, `:medium`, `:long`), usage
(`:addressing`, `:referring`, `:monogram`), formality (`:formal`,
`:informal`), and name order (`:given_first`, `:surname_first`,
`:sorting`).

## Primary API

* `new/1` — creates a validated `Localize.PersonName` struct.

* `to_string/2` — formats a person name as a string.

* `to_string!/2` — formats a person name, raising on error.

* `to_iodata/2` — formats a person name as iodata.

* `to_iodata!/2` — formats a person name as iodata, raising on error.

## Integrating existing structs

Any struct can participate in person name formatting in two ways:

* Implement the `Localize.PersonName.Convertible` protocol —
  a single function that returns a `Localize.PersonName` struct.
  Recommended for most cases, including third-party structs.

* Implement the `Localize.PersonName` behaviour — eleven
  callbacks on the struct's module, each returning one name
  field. Use this when the struct's module is under your control
  and you want individual name fields exposed as module functions.

When the formatter receives a struct, it first looks for a
`Convertible` protocol implementation; if none is found, it falls
back to the behaviour callbacks via `cast_to_person_name/1`.

# `error_message`

```elixir
@type error_message() :: String.t() | {module(), String.t()}
```

Standard error response.

# `formality`

```elixir
@type formality() :: :formal | :informal
```

Valid `:formality` option.

# `format`

```elixir
@type format() :: :short | :medium | :long
```

Valid `:format` option.

# `format_option`

```elixir
@type format_option() ::
  {:format, format()}
  | {:order, name_order()}
  | {:usage, usage()}
  | {:formality, formality()}
  | {:locale, Localize.LanguageTag.t() | atom() | String.t()}
  | {:locale_switching, boolean()}
```

An option to `to_string/2` and `to_iodata/2`.

# `format_options`

```elixir
@type format_options() :: [format_option()]
```

A keyword list of options for `to_string/2` and `to_iodata/2`.

# `name_order`

```elixir
@type name_order() :: :given_first | :surname_first | :sorting
```

Valid `:order` option.

# `t`

```elixir
@type t() :: %Localize.PersonName{
  credentials: String.t() | nil,
  generation: String.t() | nil,
  given_name: String.t() | nil,
  informal_given_name: String.t() | nil,
  locale: Localize.LanguageTag.t() | nil,
  other_given_names: String.t() | nil,
  other_surnames: String.t() | nil,
  preferred_order: name_order() | nil,
  surname: String.t() | nil,
  surname_prefix: String.t() | nil,
  title: String.t() | nil
}
```

A PersonName struct containing the fields supported
for person name formatting.

# `usage`

```elixir
@type usage() :: :addressing | :referring | :monogram
```

Valid `:usage` option.

# `credentials`

```elixir
@callback credentials(name :: struct()) :: String.t() | nil
```

Return the credentials as a `t:String.t/0` or `nil` for the given struct.

# `generation`

```elixir
@callback generation(name :: struct()) :: String.t() | nil
```

Return the generation as a `t:String.t/0` or `nil` for the given struct.

# `given_name`

```elixir
@callback given_name(name :: struct()) :: String.t() | nil
```

Return the given name as a `t:String.t/0` or `nil` for the given struct.

# `informal_given_name`

```elixir
@callback informal_given_name(name :: struct()) :: String.t() | nil
```

Return the informal given name as a `t:String.t/0` or `nil` for the given struct.

# `locale`

```elixir
@callback locale(name :: struct()) :: Localize.LanguageTag.t() | nil
```

Return the locale or nil for the given struct.

# `other_given_names`

```elixir
@callback other_given_names(name :: struct()) :: String.t() | nil
```

Return the other given names as a `t:String.t/0` or `nil` for the given struct.

# `other_surnames`

```elixir
@callback other_surnames(name :: struct()) :: String.t() | nil
```

Return the other surnames as a `t:String.t/0` or `nil` for the given struct.

# `preferred_order`

```elixir
@callback preferred_order(name :: struct()) :: name_order()
```

Return the preferred name order for the given struct.

# `surname`

```elixir
@callback surname(name :: struct()) :: String.t() | nil
```

Return the surname as a `t:String.t/0` or `nil` for the given struct.

# `surname_prefix`

```elixir
@callback surname_prefix(name :: struct()) :: String.t() | nil
```

Return the surname prefix as a `t:String.t/0` or `nil` for the given struct.

# `title`

```elixir
@callback title(name :: struct()) :: String.t() | nil
```

Return the title as a `t:String.t/0` or `nil` for the given struct.

# `cast_to_person_name`

```elixir
@spec cast_to_person_name(struct()) :: t()
```

Casts any struct that implements the `Localize.PersonName`
behaviour into a `t:Localize.PersonName.t/0` struct.

### Arguments

* `struct` is any struct that implements the
  `Localize.PersonName` behaviour.

### Returns

* A `t:Localize.PersonName.t/0` struct.

# `new`

```elixir
@spec new(attributes :: Keyword.t()) :: {:ok, t()} | {:error, error_message()}
```

Returns a `t:Localize.PersonName.t/0` struct crafted
from a keyword list of attributes.

### Arguments

* `attributes` is a keyword list of person name
  attributes that is used to construct a `t:Localize.PersonName.t/0`.

### Options

* `:given_name` is a person's given name. This is a required
  attribute. The value is any `t:String.t/0`.

* `:title` is a person's title such as "Mr." or "Dr.".

* `:other_given_names` is any `t:String.t/0` or `nil`. The
  default is `nil`.

* `:informal_given_name` is any `t:String.t/0` or `nil`. The
  default is `nil`.

* `:surname_prefix` is any `t:String.t/0` or `nil`. The
  default is `nil`.

* `:surname` is any `t:String.t/0` or `nil`. The
  default is `nil`.

* `:other_surnames` is any `t:String.t/0` or `nil`. The
  default is `nil`.

* `:generation` is any `t:String.t/0` or `nil`. The
  default is `nil`.

* `:credentials` is any `t:String.t/0` or `nil`. The
  default is `nil`.

* `:locale` is a locale identifier or `t:Localize.LanguageTag.t/0`
  or `nil`. The default is `nil`.

* `:preferred_order` is one of `:given_first`, `:surname_first`
  or `:sorting`. The default is `nil`, meaning that the name order
  is derived from the name's locale and the formatting locale.

### Returns

* `{:ok, person_name_struct}` or

* `{:error, reason}`.

### Examples

    iex> Localize.PersonName.new(title: "Mr.", given_name: "José", surname: "Valim", credentials: "Ph.D.", locale: "pt")
    {:ok,
     %Localize.PersonName{
       title: "Mr.",
       given_name: "José",
       other_given_names: nil,
       informal_given_name: nil,
       surname_prefix: nil,
       surname: "Valim",
       other_surnames: nil,
       generation: nil,
       credentials: "Ph.D.",
       preferred_order: nil,
       locale: %Localize.LanguageTag{
         language: :pt,
         language_subtags: [],
         script: :Latn,
         territory: :BR,
         language_variants: [],
         locale: %{},
         transform: %{},
         extensions: %{},
         private_use: [],
         requested_locale_id: "pt",
         canonical_locale_id: "pt",
         cldr_locale_id: :pt
       }
     }}

    iex> Localize.PersonName.new(surname: "Valim")
    {:error, "Person Name requires at least a :given_name"}

# `to_iodata`

```elixir
@spec to_iodata(person_name :: struct(), options :: format_options()) ::
  {:ok, :erlang.iodata()} | {:error, error_message()}
```

Returns a formatted person name as iodata.

Accepts the same arguments and options as `to_string/2`.

### Returns

* `{:ok, iodata}` or

* `{:error, reason}`.

### Examples

    iex> {:ok, jose} = Localize.PersonName.new(title: "Mr.", given_name: "José", surname: "Valim", credentials: "Ph.D.", locale: "pt")
    iex> Localize.PersonName.to_iodata(jose)
    {:ok, ["José"]}

    iex> {:ok, jose} = Localize.PersonName.new(title: "Mr.", given_name: "José", surname: "Valim", credentials: "Ph.D.", locale: "pt")
    iex> Localize.PersonName.to_iodata(jose, format: :long, formality: :formal)
    {:ok, ["Mr.", " ", "Valim"]}

# `to_iodata!`

```elixir
@spec to_iodata!(person_name :: struct(), options :: format_options()) ::
  :erlang.iodata() | no_return()
```

Same as `to_iodata/2` but raises on error.

# `to_string`

```elixir
@spec to_string(name :: struct(), options :: format_options()) ::
  {:ok, String.t()} | {:error, error_message()}
```

Returns a formatted person name as a string.

### Arguments

* `person_name` is any struct that implements the
  `Localize.PersonName` behaviour, including the native
  `t:Localize.PersonName.t/0` struct.

* `options` is a keyword list of options.

### Options

* `:format` is the relative length of a formatted name.
  The valid values are `:short`, `:medium` and `:long`.
  The default is derived from the formatting locale's
  preferences.

* `:usage` indicates how the formatted name is used.
  The valid values are `:addressing`, `:referring` or
  `:monogram`. The default is `:addressing`.

* `:formality` indicates the formality of usage.
  The valid values are `:formal` and `:informal`.
  The default is derived from the formatting locale's
  preferences.

* `:order` expresses preference for name part order.
  The valid values are `:given_first`, `:surname_first`
  and `:sorting`. The default is based on the person
  name struct and the formatting locale.

* `:locale` is a locale identifier or
  `t:Localize.LanguageTag.t/0`. The default is
  `Localize.get_locale()`.

* `:locale_switching` when `true`, switches the formatting
  locale to match the name's script when they differ. For
  example, a Latin-script name formatted in a Japanese locale
  will use Latin-based formatting patterns. The default is
  `false` for compatibility with the CLDR test data. See
  `TODO.md` for details.

### Returns

* `{:ok, formatted_name}` or

* `{:error, reason}`.

### Examples

    iex> {:ok, jose} = Localize.PersonName.new(title: "Mr.", given_name: "José", surname: "Valim", credentials: "Ph.D.", locale: "pt")
    iex> Localize.PersonName.to_string(jose)
    {:ok, "José"}

    iex> {:ok, jose} = Localize.PersonName.new(title: "Mr.", given_name: "José", surname: "Valim", credentials: "Ph.D.", locale: "pt")
    iex> Localize.PersonName.to_string(jose, format: :long, formality: :formal, usage: :referring)
    {:ok, "Mr. José Valim Ph.D."}

# `to_string!`

```elixir
@spec to_string!(name :: struct(), options :: format_options()) ::
  String.t() | no_return()
```

Same as `to_string/2` but raises on error.

### Examples

    iex> {:ok, jose} = Localize.PersonName.new(title: "Mr.", given_name: "José", surname: "Valim", credentials: "Ph.D.", locale: "pt")
    iex> Localize.PersonName.to_string!(jose)
    "José"

    iex> {:ok, jose} = Localize.PersonName.new(title: "Mr.", given_name: "José", surname: "Valim", credentials: "Ph.D.", locale: "pt")
    iex> Localize.PersonName.to_string!(jose, format: :long, formality: :formal, usage: :referring)
    "Mr. José Valim Ph.D."

---

*Consult [api-reference.md](api-reference.md) for complete listing*
