howdy/ui/words

Words: everything howdy_ui’s components say, in one language.

let t = i18n.new(locale.to_string(locale.detect(ctx, locales)))
let w = words.translated(t)

pagination.pagination(w, current: 3, total: 12, href: page_href)
toast.region(w, [], toasts)
calendar.new("due", year: 2026, month: 9) |> calendar.locale(w.calendar)
data_table.new(columns, rows) |> data_table.words(w)

Components that are plain functions take the words as their first argument; those built step by step take them with a words step and speak English without one. Calendars, uploaders and attachments keep their own words, which are fields here.

english is what the components have always said. translated gives the words for a translator’s locale from howdy_ui’s catalogues, with numbers, dates and the first day of the week from CLDR; locales without a catalogue fall back to English words with their own number formats. The catalogues were machine translated and are waiting for review by native speakers. Change a few words with a record update: Words(..words.english(), dismiss: "Close").

The catalogues live in ui/locales. After changing them, regenerate howdy/ui/internal/messages from the i18n directory:

gleam run -m howdy/i18n/cli -- gen --locales=../ui/locales --out=../ui/src/howdy/ui/internal/messages.gleam

Types

What a rich text editor says. heading may contain {level}, and too_large {limit}.

pub type RichTextWords {
  RichTextWords(
    toolbar: String,
    bold: String,
    italic: String,
    strike: String,
    code: String,
    link: String,
    heading: String,
    quote: String,
    bullet_list: String,
    numbered_list: String,
    code_block: String,
    divider: String,
    attach: String,
    undo: String,
    redo: String,
    link_address: String,
    link_apply: String,
    link_remove: String,
    bad_link: String,
    no_matches: String,
    remove: String,
    uploading: String,
    too_large: String,
    wrong_type: String,
    failed: String,
    wait: String,
    missing: String,
    unavailable: String,
  )
}

Constructors

  • RichTextWords(
      toolbar: String,
      bold: String,
      italic: String,
      strike: String,
      code: String,
      link: String,
      heading: String,
      quote: String,
      bullet_list: String,
      numbered_list: String,
      code_block: String,
      divider: String,
      attach: String,
      undo: String,
      redo: String,
      link_address: String,
      link_apply: String,
      link_remove: String,
      bad_link: String,
      no_matches: String,
      remove: String,
      uploading: String,
      too_large: String,
      wrong_type: String,
      failed: String,
      wait: String,
      missing: String,
      unavailable: String,
    )
pub type Words {
  Words(
    locale: String,
    number: fn(Int) -> String,
    decimal: fn(Float) -> String,
    percent: fn(Float) -> String,
    position: fn(Int, Int) -> String,
    pagination: String,
    previous_page: String,
    next_page: String,
    breadcrumb: String,
    notifications: String,
    dismiss: String,
    command_menu: String,
    clear: String,
    remove: fn(String) -> String,
    no_results: String,
    select_row: String,
    select_all_rows: String,
    carousel: String,
    slide: String,
    previous_slide: String,
    next_slide: String,
    pause_slides: String,
    play_slides: String,
    resize: String,
    jump_to_newest: String,
    show_data: String,
    total: String,
    out_of: fn(String, String) -> String,
    minimum: String,
    maximum: String,
    question_count: fn(Int, Int) -> String,
    progress: String,
    back: String,
    skip: String,
    next: String,
    finish: String,
    answer_required: String,
    choose_one: String,
    choose_from: String,
    choose_on_scale: String,
    give_one_answer: String,
    loading: String,
    unread: String,
    mark_all_read: String,
    mark_read: String,
    mark_unread: String,
    caught_up: String,
    see_all_notifications: String,
    notifications_failed: String,
    push_on: String,
    push_off: String,
    push_blocked: String,
    calendar: calendar.Locale,
    uploader: uploader.Words,
    attachment: attachment.Words,
    rich_text: RichTextWords,
  )
}

Constructors

  • Words(
      locale: String,
      number: fn(Int) -> String,
      decimal: fn(Float) -> String,
      percent: fn(Float) -> String,
      position: fn(Int, Int) -> String,
      pagination: String,
      previous_page: String,
      next_page: String,
      breadcrumb: String,
      notifications: String,
      dismiss: String,
      command_menu: String,
      clear: String,
      remove: fn(String) -> String,
      no_results: String,
      select_row: String,
      select_all_rows: String,
      carousel: String,
      slide: String,
      previous_slide: String,
      next_slide: String,
      pause_slides: String,
      play_slides: String,
      resize: String,
      jump_to_newest: String,
      show_data: String,
      total: String,
      out_of: fn(String, String) -> String,
      minimum: String,
      maximum: String,
      question_count: fn(Int, Int) -> String,
      progress: String,
      back: String,
      skip: String,
      next: String,
      finish: String,
      answer_required: String,
      choose_one: String,
      choose_from: String,
      choose_on_scale: String,
      give_one_answer: String,
      loading: String,
      unread: String,
      mark_all_read: String,
      mark_read: String,
      mark_unread: String,
      caught_up: String,
      see_all_notifications: String,
      notifications_failed: String,
      push_on: String,
      push_off: String,
      push_blocked: String,
      calendar: calendar.Locale,
      uploader: uploader.Words,
      attachment: attachment.Words,
      rich_text: RichTextWords,
    )

    Arguments

    locale

    The BCP 47 tag of the words’ language, such as de.

    number

    A whole number, such as a page number.

    decimal

    A value in a chart: thousands separators and at most two decimal places.

    percent

    A share of a whole, given as a fraction, such as 0.25 for 25%.

    position

    A position in a sequence, such as “2 of 5”, given the position and the count.

    pagination

    Pagination: the navigation’s name and the links on either side.

    notifications

    Toasts: the region’s name and each toast’s close button.

    command_menu

    Command menus and comboboxes.

    remove

    The remove button on a chosen option’s chip, given its label.

    no_results

    Data tables.

    carousel

    Carousels: what a screen reader calls a carousel and a slide, and the buttons.

    resize

    A drawer’s handle.

    jump_to_newest

    The button that appears in a conversation scrolled back from the newest message.

    show_data

    Charts: the button that shows the table, the label in a donut’s middle, and a value out of a maximum, given both written out.

    minimum

    A range slider’s two thumbs.

    question_count

    Questionnaires: “Question 2 of 5”, given the number and the count, the progress bar, the buttons, and why an answer was not accepted.

    loading

    A label for a spinner.

    unread

    Notification bells: the unread count, which may contain {count}, the buttons, what an empty or failed inbox says, and the browser notification switch. The bell’s name is notifications.

Values

pub fn english() -> Words

The words in English.

pub fn english_decimal(value: Float) -> String

Thousands separators and at most two decimal places: 12,500 or 3.25.

pub fn locales() -> List(String)

The locales howdy_ui has catalogues for. Others still get their own number and date formats from translated, with English words.

pub fn translated(translator t: i18n.Translator) -> Words

The words for a translator’s locale.

✨ Search Document