# @nlg

`@nlg` gives a definition its wording in natural language.
`l4 render`, `l4 nlg` and the editor read that wording in place of the name.

```l4
GIVEN x IS A NUMBER, y IS A NUMBER
GIVETH A NUMBER
@nlg the greater of %x% and %y%
`the greater of` x y MEANS IF x >= y THEN x ELSE y
```

``#EVAL `the greater of` 3 7`` reads "the greater of 3 and 7".

- **To fix wording in a document:** [Fix wording with @nlg](/l4/tutorials/natural-language-functions/fix-wording-with-nlg.md)
- **To write rules that read well:** [Make rules read like law](/l4/tutorials/natural-language-functions/optimising-natural-language-generation.md)
- **Example:** 

```l4-file
-- An `@nlg` sentence on a mixfix function, and what reads it.
-- See the `@nlg` section of the syntax reference.

GIVEN a IS A NUMBER, b IS A NUMBER
GIVETH A NUMBER
`the lower of` a `and` b @nlg the smaller of %a% and %b%
  MEANS IF a AT MOST b THEN a ELSE b

GIVEN price IS A NUMBER
GIVETH A NUMBER
`the price we charge` price MEANS `the lower of` price `and` 100

#EVAL `the lower of` 840 `and` 160
```



Text in square brackets after a name is a short form: ``DECIDE `the limit` [the statutory limit] IS 5``.

## Slots

`%name%` is filled with the call's argument.

- An input with spaces in its name keeps its backticks: ``%`the amount`%``.
- A slot has no spaces inside. `% amount %` is plain text, and L4 warns.
- An input with no slot is not dropped. It follows the sentence: "the threshold is passed with 5".

To write `%` or `]` as itself, put a backslash before it:

| You write               | You get             |
| ----------------------- | ------------------- |
| `10\%and\%20`           | `10%and%20`         |
| `[rate \] per unit]`    | `rate ] per unit`   |
| `[see note \[3\] here]` | `see note [3] here` |
| `\\`                    | `\`                 |

You need this only where a `%` touches a word: `a 5% levy on %amount%` works as written.
Take care with `%word%`: if `word` names an input, L4 fills it in and nothing warns.

## Where to put it

| Where                                                            | Whose wording it is |
| ---------------------------------------------------------------- | ------------------- |
| On its own line, between the `GIVEN` or `GIVETH` and the rule    | The rule's sentence |
| After the rule's name: ``DECIDE `is large` @nlg …``              | The rule's sentence |
| After an input named in the head: `` `is large` amount @nlg … `` | The rule's sentence |
| On an `AKA` name                                                 | The rule's sentence |
| After an input in the `GIVEN`, or indented under it              | That input's        |
| After a field, or under it                                       | That field's        |
| On its own line above a `GIVEN`                                  | Not the rule's      |

- **Trailing a line, it describes that line. On its own line, it describes what follows.** Fields and inputs are the exception: an annotation under one describes that one.
- **Under the last input, field or `ASSUME`, the column decides.** Indented past the `GIVEN`, `DECLARE` or `ASSUME` keyword, it describes that item. At the keyword's column or left of it, it describes what comes next. One extra space turns a rule's sentence into an input's wording, and nothing warns.
- **After an enum whose last value has no fields,** a line at the margin belongs to that value. Put the next rule's sentence after its name instead.
- **Empty or duplicated:** an empty `@nlg` is ignored with a warning. Two wordings in one language on one thing warn, and neither is used.
- **In the head and above it:** the one above is the rule's sentence, and the one on the input is that input's wording.
- **A head that repeats an input** takes the input from the head, so a wording in the `GIVEN` labels nothing.

## How it reads

| You annotate                                 | It reads                                                                            |
| -------------------------------------------- | ----------------------------------------------------------------------------------- |
| A rule                                       | The sentence heads the rule and the body follows. Every call reads as the sentence. |
| A rule that calls itself, or an imported one | The sentence stands in for the body.                                                |
| An input                                     | Its label in a `WITH` call: `… where the amount is x`.                              |
| A field                                      | After its owner: `@nlg date of birth` reads "the employee's date of birth".         |
| A `BOOLEAN` field                            | On its own, with no owner, so write a whole statement.                              |

- **In a rule's own sentence,** an input of a built-in type reads as a blank, `[x]`. An input of your own type reads as the rule's body calls it, such as "the application kind".
- **A `WITH` call** reads the sentence, then each argument by name: "the smaller of a and b where a is price and b is 100".
- **A call reads the sentence of the definition it resolved to,** not of another definition with the same name.
- **A unit of time after a slot agrees with the number:** "%n% months" reads "1 month" for 1.
- **`l4 nlg` writes literal dates as dates:** `Date 16 7 2025` reads `16 July 2025`. A date that does not exist, such as `Date 31 2 2025`, stays a call.

## Limits

- **An `ASSUME`d function has no named inputs,** so it has no slots, and a call reads as its name and arguments. Use a `BOOLEAN` field or a rule instead.
- **A function passed on, or named without being called,** reads as its name. In `filter even xs`, `even` reads `even`.
- **A sentence is spliced in without brackets,** so nested calls can read alike. Set slots off with words that cannot be part of an argument, and read the output of nested calls. Built-in arithmetic is bracketed: "10 minus (5 minus 2)".
- **A function with no sentence** reads as its pattern: `` `_ LESS _` with 100 and 20 ``.

## Several languages

Tag each wording with its language, and ask for one with `--lang`:

```l4
GIVEN amount IS A NUMBER
GIVETH A BOOLEAN
DECIDE `is large` @nlg:en the amount %amount% is large
                  @nlg:he %amount% עולה על הסף
  IF amount GREATER THAN 100
```

```console
$ l4 nlg --lang he mymodule.l4
$ l4 render --format html --lang he mymodule.l4 -o mymodule.he.html
```

The Render tab in VS Code has a language menu when a file has wordings in more than one language.

- **L4 does not translate.** It picks among the wordings you wrote.
- **Regions match.** `--lang he` reads a `he-IL` wording, and `--lang he-IL` reads a `he` one. An exact match comes first.
- **A missing wording falls back** to the rule's default: the one in the module's language, otherwise the first in the file.
- **The square-bracket form cannot be tagged.**
- **A word glued to the colon is a tag.** `@nlg:the employee pays` has the tag `the`. L4 warns when nothing backs a tag as a language. Leave a space after the colon to keep it as text.

**`@lang he`** on a line of its own means every untagged `@nlg` in the module is Hebrew. It applies to the whole file.

- A module that declares nothing is `en`, so `@lang en` is not needed, and L4 hints that it can go.
- Declare the language of a module that is not English: it sets `<html lang=…>`, right-to-left `dir` and the Akoma Ntoso language.
- If two `@lang` lines disagree, the last one is used, and L4 warns.

**L4's own words,** such as "is equal to", "if" and "with", follow `--lang` where L4 has a table for the language. Hebrew is the only one. It is small and keeps English word order, so have a Hebrew speaker read the output. A word with no entry stays English, and `l4 nlg` names it on stderr.
