OCaml Cmdliner localization means building understandable multilingual command-line help and manpages while preserving the options, positional arguments, subcommands and exit behavior a real OCaml program accepts. If you are searching for translated Cmdliner Arg.info documentation, localized Cmd.info and Manpage sections, OCaml CLI error messages, accessible Unicode help or reliable release tests, begin with the distinction between a typed term and the prose describing that term.
Cmdliner defines a command-line interface declaratively through Arg, Term, Cmd and Manpage. It can generate help, syntax-error output and manual pages from those definitions, so the same source often appears in terminal help and longer documentation. The descriptions supplied by the application are not the same thing as accepted tokens or built-in English text; translating one without checking the others can mislead a user even when every sentence sounds natural.
This world-facing guide follows a fictional inspection program that never changes its input. It covers Cmdliner-style composition, command groups, aliases, document variables, regional text, shell syntax, environment variables, error reporting and testing on installed artifacts. The aim is clear educational nonfiction for developers, translators and documentation teams, not a promise that switching an OCaml locale automatically localizes every sentence inside a library.
Quick answer: build localized documentation around stable Cmdliner terms
Write the command grammar once, provide reviewed language-specific descriptions when constructing Arg.info and Cmd.info, and keep the actual --input flag or child command name stable unless compatibility is deliberately managed. Test the generated manpage as well as terminal help, because section headings, markup and document substitutions may render differently from the concise command synopsis. Inventory generated parser errors separately from developer-controlled prose.
- Use
Arg.infofor option-specific human documentation; an option’s actual name belongs to its parser definition. - Use
Cmd.infoandManpagestructures to provide purposeful command-level documentation. - Keep values, accepted aliases, environment variable behavior and output data stable across presentation languages.
- Test
--help,--version, bad arguments, absent arguments, nested commands and each manual format you ship. - Distinguish a generated failure message from a localized application error with its own severity and recovery instruction.
- Include resource files and documentation in packaged builds, not only the development checkout.
Reading route
The first example shows how typed arguments and human help fit together. The design guide then covers common Cmdliner decisions in depth, including user-facing failure studies. A four-week plan and FAQs make the information usable by a small team, while source links provide precise API details for readers working with a particular Cmdliner version.
A minimal Cmdliner example: one interface, multiple explanations
Imagine an OCaml tool called atlas-check that reports which data file a person intends to inspect. It requires --input and accepts --verbose. The example below shows one English set of descriptions; a localized build would supply different doc values through a message resource table without silently renaming either flag. Its only displayed result is a path label; the example intentionally performs no real file operation.
open Cmdliner
let input =
let doc = "Path of the file to inspect" in
Arg.(required & opt (some string) None
& info ["input"] ~docv:"FILE" ~doc)
let verbose =
let doc = "Show additional information" in
Arg.(value & flag & info ["verbose"] ~doc)
let inspect input verbose =
Printf.printf "Selected input: %s\n" input;
if verbose then print_endline "Verbose mode requested"
let term = Term.(const inspect $ input $ verbose)
let command =
Cmd.v (Cmd.info "atlas-check"
~doc:"Inspect a file without changing it") term
let () = exit (Cmd.eval command)
The command receives a parsed file path and a Boolean, not translated sentences. In this example, replacing the English doc and the command-level description is a presentation change; replacing info ["input"] with a translated option string is a syntax change. Any production implementation should check the documented Cmdliner API against its pinned package version and adapt the simplified example to the program’s real security and file-access rules.
A multi-language program may choose its messages before building command. That design forces an important question: how does a user choose a language before a parser that prints language-specific help is constructed? There is no universal answer. A documented environment/configuration preference or a carefully defined bootstrap parser is preferable to secretly searching raw arguments for language-looking substrings.
What makes Cmdliner distinct
Cmdliner’s building blocks are terms. They can represent parsed arguments, values and computations, and they are combined to form a command. Cmd.info stores the command’s name and documentation; Cmd.group organizes child commands; Manpage supports documentation beyond a small one-line option description. The library also controls some error text and formatting, which should be checked independently from the application’s resource catalog.
The official command-line interface manual documents rules that translators can easily miss: options, positional arguments and environment defaults have parsing semantics; reserved names such as --help are not ordinary user-defined options; and child commands may be matched with unambiguous prefixes. A translated manpage must not accidentally teach a different grammar. Good writing begins by reading the behavior instead of inferring behavior from an English sentence.
Thirty concrete Cmdliner design decisions
1. Document language versus parser language
A writer assumes the locale chosen for documentation also changes accepted argv keywords, although the parser still recognizes the names declared in Arg.info. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Treat user language as a presentation choice. Provide translated context around canonical tokens, and keep parsing decisions independent unless a versioned, documented alias policy is introduced. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Compare successful parses under two locales and require identical argument values. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
2. The Arg.info names list
The declaration info ["input"] supplies a public flag name, not a placeholder for a translated label. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Keep this list stable; translate the doc that explains it. If introducing a second name, check whether the alias collides with another option or with conventions in the command tree. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Run –input with actual values and verify any new alias while replaying old shell scripts. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
3. Short forms and conventions
A document adds -e in an example because it fits the target language, but the program has no such short option. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Only list aliases explicitly declared in Cmdliner. Do not invent local initials. Short options have particular syntax and may be bundled in a user’s shell invocation. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Capture both help and invocation results for every published short and long name. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
4. Required values
A translation says ‘You can select a file’ when the term actually requires a file path. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Reflect the required term’s behavior accurately. Explain what the user must provide and show a minimal valid command, rather than using vague marketing language. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Run a no-argument invocation and one with –input; compare the observed requirement with the promise. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
5. The docv placeholder
The writer replaces FILE with an entire translated sentence, producing a hard-to-read synopsis. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Use the ~docv display placeholder to indicate a type of value, not the exact input token or a multi-step instruction. Put fuller explanation in ~doc. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Copy an example and verify shell quoting, especially for paths containing spaces. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
6. Argument converters
A decimal, date or path converter accepts a particular input grammar independent of the language of its documentation. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Explain the exact expected format and conversion failures. Translating an example’s decimal separator is unsafe if the converter does not accept it. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Test valid, invalid and regionally formatted values against the actual converter. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
7. Option defaults
A help sentence claims a default input file that no longer matches the Arg term definition. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Keep defaults synchronized with the executable configuration. A translator should receive the current value and whether the default comes from command options or the environment. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Compare omitted-flag behavior with explicit values, and check the translated default statement. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
8. Boolean flags
A local-language explanation says to supply true or false after a flag that actually takes no value. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Describe flag presence instead of inventing an argument. If a switch uses a converter or value, say exactly how it differs from a no-value Boolean flag. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Test –verbose, –verbose=true and the absent flag; document only supported forms. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
9. Repeated options
Help implies that multiple occurrences accumulate, whereas the selected term may use a different occurrence policy. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Describe repetition only after reading the specific Arg combinator and installed version. Clarify whether the last value wins, a list is accumulated or repeated use is invalid. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Run duplicate options with different values and inspect the resulting parsed term. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
10. Positional arguments
A translator turns a positional value into an apparent option by adding leading hyphens in an example. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Explain its position and quoting, using terminal-ready examples. Teach -- to disambiguate values that look like options when relevant. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Run a path starting with a hyphen before and after the delimiter. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
11. Environment-backed defaults
An environment variable supplies a value when an option is absent, but the documentation presents it as a second always-required step. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Distinguish explicit arguments, optional environment fallback and what happens when neither is supplied. Keep environment variable identifiers stable unless a compatibility plan exists. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Test unset, valid, invalid and conflicting environment values; record which source wins. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
12. Cmd.info descriptions
The root description is grammatically fluent but gives an incorrect account of what the command actually changes. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Use Cmd.info for a precise verb and scope: inspect, validate, report, export or modify. The translated claim must match the side effects of the evaluated term. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Observe a safe test run and check that the description is not stronger than the behavior. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
13. Cmd.group child commands
The parent help describes a translated child name that cannot be invoked by that name. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Separate Cmd.group syntax from prose. Keep child command identifiers canonical and document aliases only when the program accepts them. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Run parent help, each child help and every copied example. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
14. Unambiguous prefixes
Cmdliner may accept shortened long names and child command prefixes, making accidental lookalikes a subtle issue. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Do not promise prefixes as stable aliases without testing the exact command tree. Adding a new sibling can make a formerly unique prefix ambiguous. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Test a shortened child name before and after adding a hypothetical sibling in a fixture. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
15. Reserved names
The application adds a translated alternative to –help and unexpectedly conflicts with Cmdliner’s built-in help handling. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Treat --help, and --version when configured, as special reserved behaviors rather than ordinary translations. Check library rules before introducing convenience aliases. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Test these switches under every locale and ensure they do not trigger a real business action. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
16. Version output
A translated page says –version describes language pack version, but it actually reports the executable’s version. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Separate program version, language-catalog revision and documentation version in your writing. Avoid changing the meaning of a reserved version path. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Compare version output and executable metadata across locale choices. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
17. Manpage blocks
A translator flattens a structured manual into one enormous paragraph and loses headings that helped users navigate. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Build each Manpage block with a clear purpose and review its rendered order. Preserve semantic sections, code fragments, lists and short examples when translating prose. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Render the manpage in all supported formats and confirm the main task can be found quickly. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
18. Manpage conventions
An author treats NAME, SYNOPSIS and OPTIONS as arbitrary prose and duplicates or contradicts content generated by Cmdliner. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Understand which parts are generated and which are application-owned. Write supplementary descriptions instead of restating the parser grammar inconsistently. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Compare the generated synopsis and manual examples line by line. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
19. Markup and substitutions
Documentation variables or formatting escapes are translated as ordinary words, and the renderer produces broken text. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Keep formatting notation and variable names intact unless the documentation explicitly defines them as localizable. Provide translators with rendered examples and plain-language context. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Check rendered output, not only catalog source, for missing substitutions and literal markup artifacts. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
20. Terminal versus manpage rendering
A paragraph works in a rich manpage but produces an unreadable wall of text in terminal help. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Use concise option descriptions and move longer context into appropriate documentation sections. Keep examples short and reliable in both presentations. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Capture narrow and wide terminal help plus rendered manpage and compare the information hierarchy. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
21. Generated parse failures
An invalid option error remains English even after every doc string is translated. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Inventory Cmdliner-generated diagnostics separately. Check supported APIs and the release version before attempting wrappers; avoid claiming total framework localization without proof. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Test absent values, unknown options and wrong child commands under two locales. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
22. Application errors
A domain validation failure is translated with a different severity from the underlying parse failure. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Keep domain-level failures in application-owned resources with explicit outcome and safe recovery guidance. Do not reinterpret failure as success because the destination language prefers gentler phrasing. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Record stdout, stderr and exit code for each failing example. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
23. Exit codes
An error template says ‘completed with warnings’ when the process exits unsuccessfully. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Preserve the meaning of standard error conditions and Cmdliner exit outcomes. A human-friendly message can be polite without misrepresenting the result. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Compare actual exit codes under the same invalid argv in every supported language. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
24. Help format selection
The manual advertises a particular help format that the installed Cmdliner version does not actually provide or generate as expected. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Consult current documentation for supported help formats and make claims only about the tested build. Do not generalize from a different major version. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Request each supported help form and check that it displays the intended sections. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
25. Locale selection
A program needs the desired language before it constructs the Cmdliner documentation values, yet normal parsing happens later. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Choose a predictable initial locale source or controlled preliminary parsing step. Document precedence when a language option, environment value and config file disagree. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Test conflicts, duplicates, unsupported locales and a help request together. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
26. Fallback and missing resources
A missing translation key renders as an empty option description and gives no clue what value to supply. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Require essential fields and use a reviewed fallback catalog. Distinguish intentional empty sections from absent resources and report packaging errors safely. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Remove a resource key in a test build and verify a readable fallback and a detectable quality failure. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
27. Plural-sensitive status messages
A summary says one records or embeds an English plural suffix into a sentence that cannot be reordered naturally. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Store complete semantic messages with plural categories instead of concatenating English fragments. Maintain numeric meaning independent of target grammar. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Test 0, 1, 2 and larger counts in the languages you officially support. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
28. Unicode file paths
A translated example changes the Unicode normalization of a filename, which no longer matches an actual file on disk. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Keep path values as data. A translated explanation may describe the path, but the program must not silently normalize or transliterate it without a documented policy. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Use composed and decomposed accented path fixtures on supported platforms. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
29. Right-to-left documentation
An Arabic line includes an ASCII flag and a path; visual reordering makes the copied command ambiguous. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Separate executable examples from surrounding RTL prose, test bidi rendering and avoid embedding critical syntax inside dense paragraphs. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Copy examples on real terminals and verify received argv is unchanged. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
30. Machine-readable output
A localized command prints a banner before JSON, breaking pipelines that previously parsed stdout as a single document. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Make human presentation optional or direct it to an appropriate channel. Preserve field names, types, delimiter rules and ordering promises of the machine output format. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Parse JSON or CSV under every locale and compare the structural contract. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
31. Packaging and reproducibility
The manpage is correct in a checkout but the release archive contains only English documentation resources. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Build and inspect clean packages, include language catalogs deliberately, and check how paths differ across operating systems. Do not rely on developer workspace resources. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Install from a published artifact and render help and manuals after removing checkout paths. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
32. Documentation continuity
An older tutorial shows an option no longer accepted, while new translated help has been corrected. The cost is rarely limited to awkward wording: the person reading the manual may form the wrong mental model of what arguments are accepted or what effects will follow.
Maintain a versioned command reference and execute all example commands as regression tests. Protect old scripts with intentional migration instructions rather than surprise renames. In Cmdliner, confirm whether the information belongs to a command term, an argument info record, the manpage specification or application output. That ownership determines whether a text edit is enough.
Re-run historical supported argv fixtures and the translated quick-start on every release. Keep an explicit fixture with the exact input, selected language, expected observable behavior and actual terminal output. A reviewer should be able to reproduce the distinction without guessing which source file owns it.
Worked failure investigations with recovery steps
Investigation 1: The translated synopsis contains an extra argument
A translated ~docv appears to describe two separate values. Shorten the placeholder and move explanatory grammar into ~doc. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Compare help, then run a one-value and a two-value invocation to document the actual arity. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 2: A missing –input error contradicts the guide
The guide calls an input optional even though the term is built with required. Repair the explanation rather than weakening validation by accident. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Run the command without input and verify the correction matches its error path. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 3: A German manpage shows literal markup
A formatting substitution was edited as normal German prose. Restore the exact syntax and translate only surrounding content with a rendered preview. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Generate the finished manual and inspect the target heading and example visually and as text. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 4: The French help works only on a developer laptop
The release archive omitted its language resources. Audit packaging inputs instead of assuming that a source-tree test proves delivery. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Unpack the actual artifact into a clean directory and run –help after clearing development paths. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 5: An environment default overrides an explicit flag
The program’s precedence differs from the translated explanation. Test the binding rule and rewrite the explanation to match verified Cmdliner behavior. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Use one conflicting CLI value and environment value and check the parsed result. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 6: A short child-command prefix becomes ambiguous
An additional child command shares its initial letters with an old command. Stop advertising the prefix as though it were a permanent alias. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Test both full names and abbreviations; update examples to canonical names. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 7: An unknown option error is still English
Descriptions are localized, but the wording is library-generated. Inventory that output and determine what the pinned Cmdliner version supports before claiming complete localization. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Use an unknown flag to inspect every visible line, including any suggestion and usage. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 8: –help is mistakenly treated as a business switch
A new localized alias collides with Cmdliner’s reserved option handling. Remove the collision and leave standard discovery usable. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Run root help and child help, verifying no file or external action occurs. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 9: A machine-readable status gains translated headers
A manual-friendly print statement executes before the JSON payload. Keep machine data pure and move optional explanation elsewhere. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Pipe output to a strict JSON parser under two languages and compare decoded structure. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 10: An error translation leaks the original file path
A formatter interpolates an unredacted sensitive input into a friendly message. Use a safe error schema and scrutinize debug traces. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Feed a synthetic secret in a failing argument and scan terminal capture for the exact token. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 11: Arabic command tokens display in the wrong apparent order
Mixed-direction prose joins the shell invocation into a sentence. Separate the command visually and ask a language reviewer to copy it. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Inspect both rendered documentation and the actual token array received by the executable. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 12: A comma-formatted number fails validation
The manpage example was localized as a number, but the converter still expects an invariant input syntax. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Check the converter and either document that syntax or implement tested locale-aware parsing as a separate feature. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 13: A warning translates as an approval
The translated text removes uncertainty and says the inspection is complete despite a nonzero exit. Preserve the underlying state and degree of certainty. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Compare translations against the recorded result and exit status, not just vocabulary. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 14: A terminal capture loses accents
An incompatible output encoding or font is selected in the deployment image. Verify the target environment and communicate limitations explicitly. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Compare raw output bytes and real terminal display across supported environments. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 15: An old example invokes a renamed child
A documentation-only translation changed the token in the shell sample. Restore the canonical child spelling or add an explicitly tested alias. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Execute the published example in CI for every package you release. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
Investigation 16: A reader cannot find the recovery instruction
The option description lists parameters but gives no next step for invalid input. Add concise application-owned guidance in the appropriate error or manual section. This is a concrete semantic mismatch, not merely an aesthetic preference: accuracy depends on the relationship between the command grammar and what a reader is told.
Have a tester recover from a deliberately incorrect invocation using only the translated output. Save a small transcript with the language choice, program version, invocation and status; use it as a reusable regression test.
An implementation plan that fits four weeks
Week 1 — understand and freeze the command grammar
List all defined Arg.info names and docv placeholders, all root and grouped commands, environment defaults, version behavior, output formats and exit states. Capture current help and manual pages. Mark each sentence as application-owned, Cmdliner-generated or external documentation. Gather representative successful and unsuccessful commands from real user workflows. The output is a baseline that makes later text changes auditable and prevents an apparent translation improvement from becoming an unnoticed breaking change.
Before moving forward, have a maintainer and a language reviewer compare the same example: one checks what Cmdliner accepts, and the other checks whether the resulting instruction is intelligible. Their combined evidence matters more than either review in isolation.
Week 2 — author language resources and review documentation
Move program descriptions, option docs, examples, manpage sections and application error explanations into a controlled resource table. Give translators context about actual defaults, accepted values, side effects, input types and failure severity. Select one locale before building the relevant Cmdliner information. Review reserved tokens and documentation formatting, and make sure no rendering escape is translated as text. A native-language reader should complete a task rather than merely attest that sentences sound grammatical.
Before moving forward, have a maintainer and a language reviewer compare the same example: one checks what Cmdliner accepts, and the other checks whether the resulting instruction is intelligible. Their combined evidence matters more than either review in isolation.
Week 3 — exercise the installed parser and output
Test root and grouped command help, manual formats, unambiguous abbreviations, shell quoting, environment fallbacks, bad arguments and unknown switches. Run narrow terminals and Unicode paths. Record stderr and stdout separately, and compare exit codes and structured data across languages. Introduce a missing message and an unavailable regional locale to test fallback. Check that the package resolves its message resources on Windows, Linux or macOS where supported.
Before moving forward, have a maintainer and a language reviewer compare the same example: one checks what Cmdliner accepts, and the other checks whether the resulting instruction is intelligible. Their combined evidence matters more than either review in isolation.
Week 4 — package, publish and maintain
Rebuild from a clean checkout or release environment, inspect artifacts and test all published command examples. Document the supported language set, locale precedence, canonical syntax and known rendering limitations. Keep Cmdliner version-specific behavior in the release notes rather than presenting it as universal. Preserve one source of truth for option names and evaluate translation changes alongside parser changes. Archive concise test evidence so future maintainers can understand what ‘localized’ was proven to mean.
Before moving forward, have a maintainer and a language reviewer compare the same example: one checks what Cmdliner accepts, and the other checks whether the resulting instruction is intelligible. Their combined evidence matters more than either review in isolation.
Frequently asked questions
What does Cmdliner Arg.info do?
It declares information about a command-line argument, including names and human documentation. The name list and the doc string are not interchangeable, so translating the latter should not silently change the former. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
Can Cmdliner generate manpages?
Yes. The library supports structured command documentation and generated manuals. Review the appropriate Manpage API and the rendered output of your installed version before assuming every formatting detail is customizable. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
Should I translate the command name?
Not merely by changing a guide. Command names are accepted syntax and may appear in scripts. If a new alias is deliberately added, test compatibility and show the canonical spelling in examples. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
Does changing ~doc localize every error?
No such complete coverage should be assumed. Library-owned parser diagnostics and application-owned domain errors follow different pathways and require separate tests. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
Why is a docv placeholder important?
It tells the reader what kind of value an option expects. It does not itself define the parser grammar. Keep it concise and pair it with a realistic, correctly quoted example. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
What about –help and –version?
Treat reserved help and version handling as program-interface features. Do not reassign them casually, and check both root and child command behavior. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
Can I localize environment variable names?
Environment identifiers are part of the configuration interface. Describe them in the target language, but avoid changing their spelling without an explicit migration contract. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
Should JSON output be translated?
Keep machine-readable key names, types and status meanings stable by default. A separate human report can use localized prose and number formatting when it is clearly distinct from machine output. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
How do I test a right-to-left manual?
Render the actual help and manual in supported environments, isolate code tokens, copy and execute example commands, and involve a reviewer who reads the language naturally. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
How do I handle a missing locale?
Choose a reviewed fallback and make availability truthful. A regional variant must not be claimed merely because the program falls back to a different language. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
What changes when upgrading Cmdliner?
Available APIs and rendered help details can evolve. Pin and document the release, review the migration documentation and rerun tests rather than relying on a screenshot from an old major version. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
What is the minimum trustworthy release evidence?
A clean install should show understandable help, working examples, consistent error semantics, proper resource inclusion, reliable Unicode rendering and unchanged parser behavior for supported argv. Test with a reproducible command and keep the result alongside the reviewed documentation; the executable is the final authority for accepted input.
Official sources and API references
The OCaml Cmdliner documentation explains terms, commands, automatically generated help and manuals. The Cmd module reference covers command information and groups; the Cmdliner command-line manual describes token parsing, prefixes, options, environment variables and reserved names. Consult the documentation version that corresponds to your dependency rather than mixing incompatible examples.
Related eduKateSG reading
Use the Translate Like a Pro series index and the Master Art of Translation complete system to explore adjacent skills. For another typed functional-language parser, read Haskell optparse-applicative localization. The present guide is focused on OCaml Cmdliner’s term-based interface, generated documentation and operational QA.
Release acceptance: a reader should be able to act correctly
A good Cmdliner translation explains what a command will do, what it will not do, which exact tokens it accepts and what to try when something fails. The term graph must behave as before. The manual should agree with real help, and both should use a reviewed fallback if a resource is missing. Each language should support a successful example, a meaningful failure and a clear exit status. That is the standard to use when deciding whether a multilingual OCaml CLI is ready for other people’s work.