1.80 m
Make forms easier,LLM tools safer.
Use one zero-dependency parser for user-entered quantities, dates, ranges, and model tool arguments. Store typed values, canonical units, spans, and warnings.
pnpm add @pascal-app/lingonpm install @pascal-app/lingoyarn add @pascal-app/lingobun add @pascal-app/lingo5 GB
62.137 mi
< 10 min
Needs review
Try kg
85%
20–28°C
What people type, what you store
These rows are parsed by the real library when this page builds — the same engine that runs in the hero above. Every result carries the original-input span and stable issue codes.
Ranges, conversions, tolerances, fuzzy words, typos, and nine languages of number words — see everything the parser reads in Parse and the full unit catalog.
For the web. For LLMs.
One parser powers both sides: the same schema validates a human form and an LLM tool call.
- One text field replaces a value box plus a unit dropdown — accepts how people actually type, typos included.
- Fields are never yelled at mid-typing:
2 fis incomplete, not invalid. Issues carry stable codes, spans, and did-you-mean suggestions. - Headless everywhere: DOM controller,
<lingo-input>web component, React hook, React Native hook. No styles shipped. - Two-way guarantee:
1.9999 mformats as6′7″, never5′12″— and re-parses to the same value.
- Models are better at emitting
"5'11""than1.8034. Standard Schema fields make the string the reliable path. - Tool-boundary defaults fail loudly on ambiguous numbers, ignored timezones, and clock-drifting relative dates — with candidates a model can self-correct from.
repairToolCallWithfixes malformed payloads client-side, with no extra model round trip.- Deterministic and replayable: an explicit
nowmeans a queued or retried tool call never drifts across midnight.
The tool boundary, before and after
Constrained decoding makes JSON parse. lingo checks whether the values mean what they should — and hands back canonical numbers your database can trust.
// What the model emits (strings, like people write)
{
"weight": "2 lbs",
"height": "5'11\"",
"deliverBy": "next tuesday"
}// After canonicalizeValues(args, spec)
{
"weight": 0.90718474, // kg, exact legal factor
"height": 1.8034, // m
"deliverBy": "2026-07-28T…Z" // ISO, from an explicit now
}import { lingoObject, quantityField, dateField } from '@pascal-app/lingo/ai'
import { tool } from 'ai'
const shipment = lingoObject({
weight: quantityField({ kind: 'mass', unit: 'kg', min: 0 }),
deliverBy: dateField(), // relative dates require an explicit now
})
// AI SDK, OpenAI strict, Anthropic, Gemini, LangChain, MCP — one schema
tool({ inputSchema: shipment, execute: run })// Generative UI: let the model assemble the form,
// let lingo own every quantity/date field it renders.
const field = useLingoInput({ kind: 'mass', unit: 'kg', name: 'weight_kg' })
// agent or human types "2 lbs" -> the form submits weight_kg=0.90718474The same schema drops into the Vercel AI SDK, OpenAI strict tools, Anthropic, Gemini, LangChain, and MCP — see one schema for the form-and-tool pairing.
Frequently asked questions
Short answers, with the docs section to go deeper.
How do I parse "5'11\"" into meters in JavaScript?
parseQuantity("5'11\"", { kind: "length" }).quantity.to("m").value returns 1.8034. lingo reads compounds (5'11", 2 lb 3 oz, 1h30), unicode (½, μm, ′ ″), number words, and typos with did-you-mean — zero dependencies.
Read more →How do I validate LLM tool-call arguments like "2kg" or "next Friday"?
Declare tool inputs with quantityField / dateField from @pascal-app/lingo/ai. Models emit natural-language strings; lingo canonicalizes them at the tool boundary and fails loudly on ambiguity with a machine-actionable candidate instead of a silent guess.
Read more →Can one text input replace a value box plus a unit dropdown?
Yes — that is the core form pattern. A headless DOM controller, <lingo-input> web component, React hook, and React Native hook accept "180cm" or "5ft 11" and submit one hidden canonical value, with spans and stable issue codes for validation UX.
Read more →Does lingo have any runtime dependencies?
Zero. Every entry is tree-shakeable, size budgets are enforced in CI, and Intl (built into every runtime) handles locale-aware number formatting.
Read more →Which languages can lingo parse?
English is built in; opt-in locale packs add Spanish, French, Portuguese, Chinese, Japanese, and en-GB parsing. Packs are data-only subpath imports, so you ship only the languages you load.
Read more →Is parsing deterministic enough for agents and queued jobs?
Yes. Reference time is always an explicit now option (never Date.now() inside parsing), same input plus options gives the same output, and everything format() emits re-parses to the same value.
Read more →