VIEW THIS AS

Auto mode follows the Route Engine until you choose a viewpoint.

YOU ARE HERE

ROUTE CHECK

CONNECTED TO

WHAT NEXT

Use the canonical route for this room, or HELP if you are unsure.

Translate Like a Pro | 8660 — Haskell optparse-generic Localization, Generic Records, Helpful Types, Defaults and CLI QA

Haskell optparse-generic localization means translating the help and instructions generated from Generic records while keeping the actual command-line flags, typed values and defaults reliable. This guide covers Options.Generic, ParseRecord, getRecord, Helpful annotations, the <?> help operator, <!> defaults, Wrapped and Unwrapped records, Unicode arguments and release testing. It is for Haskell developers who want a multilingual CLI without confusing source-code type labels with the interface that users execute.

Imagine AtlasCatalog, a local utility that reads a geographic-place CSV and reports coverage. A researcher in Japan follows atlascatalog –source atlas.csv –limit 25, while a colleague in Brazil wants a clear explanation of limit and a German colleague receives a parse error. The flags are often generated from record field names; translating the words in help does not automatically change those derived flags, and doing so casually would change what scripts and users can type.

The essential rule is to preserve record-field-derived command identity, value types and parser results; translate descriptive text and worked explanations where a controlled application layer permits; then compare behavior with the same input fixtures across locales. optparse-generic 1.5.3 documents a parser derived from Generic records, field help annotations using <?>, defaults using <!> and an unwrapRecord pattern. Those are documented mechanisms, not a promise of built-in locale catalogs, so this guide distinguishes verified behavior from localization architecture you supply.

Quick answer — how to localize Haskell optparse-generic safely

  • Keep Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults exact in runnable examples and program behavior.
  • Translate getRecord descriptions, Helpful <?> annotations, human-facing command explanations, error guidance and sample-task instructions in a controlled language layer.
  • Distinguish library-generated text from messages owned by the application.
  • Pin and inspect the installed Haskell dependencies before relying on a public example.
  • Test valid commands, missing values, invalid options and unsafe side-effect claims.
  • Capture real stdout, stderr and exit status; compare typed outputs instead of translated strings.
  • Test Unicode filenames, narrow terminals, right-to-left explanations and copied commands.
  • Record a supported-language fallback and ask native speakers to complete a real task.

Chapter 1 — What the command-line interface actually does

A command-line interface is a compact language. It combines a program name, selected action, options and data supplied by the reader. In Haskell optparse-generic, Options.Generic derives parsers from Generic data types; ParseRecord connects records to CLI parsing; getRecord creates help; <?> documents fields through Helpful; <!> supplies defaults; unwrapRecord and Wrapped/Unwrapped can separate annotated and consumer-facing structures. This arrangement is valuable because the program can recognize the intended operation without interpreting an entire natural-language sentence. It is also why careless translation is risky: replacing a recognized command with a fluent but unimplemented synonym is equivalent to changing the program, not improving its documentation.

Begin with a task the reader already understands: AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report. The example task is atlascatalog –source atlas.csv –limit 25. Before translating anything, identify the input file, the executable tokens, the expected result and possible side effects. A professional guide is useful when it answers what will change, what will not change, how to confirm success, and what happens if a step fails. Those four questions are more important than showing every optional switch on the first screen.

Chapter 2 — Separate executable identity from language

The simplest reliable distinction is between a machine token and a human description. Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults belong to the interface contract. getRecord descriptions, Helpful <?> annotations, human-facing command explanations, error guidance and sample-task instructions are candidates for localization, provided the chosen software architecture can display the translated text. A filename or number is usually data, which needs its own validation and formatting policy. The fact that all three may appear in one help line does not make them interchangeable.

Create a small inventory with columns for the visible string, where it originates, who owns it, whether users must type it and what tests protect it. For example, a translated phrase can sit beside –help, while –help itself remains literal. Reconfirm where the string is actually rendered: command help, validation error, progress output, a manual page, a generated completion script or a copied example. A change to a help paragraph should not need to rewire parsing.

Chapter 3 — A small version-aware technical example

The following Haskell excerpt is a compact illustration of the code boundary. It is not an invitation to run unreviewed operations against real records. Put equivalent code in a disposable project, pin the library version and test with sample inputs. If your installed package differs from the cited documentation, inspect its public API first. Some applications wrap libraries with their own helper layers, so a team’s production command may accept different options from this educational example.

Read the example in two directions. First, follow the value typed by a user through the parser and into the program’s action. Second, find which strings describe that process to the reader. Translation belongs primarily in the second path, while validation and successful execution belong in the first. If the input path or option set changes when only the description language changes, that is evidence of a behavioral regression.

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
import Options.Generic

data Query = Query
  { source :: FilePath <?> "Path to a local catalog"
  , limit  :: Int      <!> "25"
  } deriving (Generic, Show)
instance ParseRecord Query

main :: IO ()
main = do
  q <- getRecord "Inspect a local place catalog"
  print (q :: Query)

Chapter 4 — Help must form a useful path, not a dictionary

A good help page begins with purpose, then a minimum safe invocation, then common arguments, then the next action after success or failure. It should not force a novice to decode a complete reference table before trying a single harmless example. Show a real path format, state whether it refers to a file or folder, identify default behavior, and explain what the command will write. Use short option descriptions for scanning, followed by detailed discussion for ambiguous or risky actions.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, start with a local fixture and a clear observation such as a row count, a checked schema, or a summarized warning. Present a command in code formatting and keep its spelling stable. The surrounding explanation can adapt to local grammar, but the command cannot change unless the program really supports another syntax. Think of translated help as a trustworthy user journey rather than a list of words that happen to be equivalent.

Chapter 5 — Choose a locale without changing the task

A multilingual application needs to determine the language before it constructs human-facing output. Depending on the application’s design, a documented flag, environment variable or configuration setting may be appropriate. Use predictable fallbacks and support an explicit list of locale tags. A user who requests Japanese help should not accidentally run a different operation, write to a different directory or grant broader permissions. Locale selection is a presentation decision until the application explicitly documents a different contract.

Avoid assuming that a low-level parser library supplies a ready-made translation catalog. The technical reference may document description strings without providing message extraction, fallback or plural handling. A practical architecture keeps a catalog keyed by stable identifiers and lets application code choose complete sentences. The key is never itself a command flag. Record which messages still come from Haskell optparse-generic so readers and maintainers do not confuse a partial translation with total support.

Chapter 6 — Make errors actionable, accurate and safe

An error message should answer what failed, where the user can look and which next action is safe. Missing arguments, unknown switches, unsupported values, unreadable files and malformed contents are different failures. Some are rejected by the parser before the application starts; others occur later. Translating them into one generic ‘operation failed’ sentence removes critical information. Where messages are controlled by a dependency and lack a documented translation hook, a localized application explanation can be safer than brittle rewriting of raw dependency output.

Never print a successful-completion message after a command that failed. Compare exit status and side effects as well as displayed wording. When errors mention sensitive paths, identifiers or internal details, avoid exposing secrets in the guise of helpful localization. Show enough context for recovery without turning a CLI diagnostic into a data leak. The correct reader-facing wording often includes a valid minimal invocation and a pointer to a local log reference.

Chapter 7 — Treat Unicode and typography as engineering issues

Translation changes the shape of text. French descriptions may be longer, Japanese glyphs may occupy multiple terminal display columns, Arabic paragraphs may mix right-to-left text with left-to-right options, and filenames can contain combining marks or spaces. A string that looks fine in a browser may be unreadable or uncopyable in a shell. The program’s data representation, stdout encoding, terminal font and renderer are separate boundaries worth checking.

Keep executable tokens in code formatting, preserve ASCII punctuation where it has syntax meaning, and test copied commands as bytes. Check a narrow terminal and a normal terminal, stdout piped into a file and errors written to stderr. A correct translation should help a reader act, not merely look attractive in the translator’s editor. Confirm the supported environments rather than claiming universal Unicode behavior from the language runtime alone.

Chapter 8 — Check real outcomes, not just translated snapshots

A screenshot proves that text appeared. It does not prove that an operator selected the correct input, that the parser produced the intended value or that a command avoided an unpromised write. Build fixtures for a valid invocation, missing required input, malformed value, unknown option, Unicode path and a permissions failure. Compare parsed outputs, exit code and file effects across languages. The content of the sentence may change, but the operational result should stay consistent.

Native-language testing adds a different kind of evidence. Ask a reader to explain what the command will do before executing it, which part of the example is a placeholder, and what the next step is after a failure. A reviewer who can translate every word but selects the wrong operation has found a usability defect. Use that observation to fix help ordering, not just vocabulary.

Chapter 9 — Haskell optparse-generic design decisions that change translation quality

1. Generic fields become public interface

A record such as Query { source :: FilePath, limit :: Int } is Haskell data, yet optparse-generic uses its shape to derive command-line syntax. The field label source can become the long flag –source. Treat renaming a record field as an interface migration, not a harmless translation edit. If help needs a different natural-language phrase, provide an explanation without silently changing the flag name.

To make this decision useful for a real reader, first identify which part of atlascatalog –source atlas.csv –limit 25 is a typed token, which part is an input value, and which part is merely explanatory. Record the behavior before revising the wording. When a localized page makes a promise, turn that promise into a fixture: invoke a valid sample command, inspect the structured result and check that side effects match the guide.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

2. getRecord creates useful first-run help

getRecord accepts a program description and reads CLI arguments into a typed record. A localized explanation should make the program’s task clear before listing switches, but the type inference and field parser remain unaffected by prose alone. When a language requires a longer description, inspect how help wraps instead of stripping away important scope or side-effect words.

This issue usually appears when source code, an English help screen and a translator’s draft are reviewed separately. Put them side by side. Ask the maintainer to show what Haskell optparse-generic actually accepts, ask the language reviewer to describe the intended operation without consulting English, and let the test suite arbitrate differences. A good edit survives both kinds of review.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

3. Helpful is a real type-level wrapper

The <?> annotation associates help text with a field, using Helpful and type-level symbols. The documentation shows that printed results may contain a Helpful wrapper unless a different record design is used. Explain that this is a type-and-derivation concern, not a translation problem. Never advise translators to delete type annotations merely to make runtime output look cleaner.

A small example is better than a sweeping claim. Build a disposable input, run it once successfully and then change only the display language. If the parsed values or selected files differ, the localization boundary has moved too far. If behavior matches but the reader cannot explain what happened, the prose is still not adequate. Both outcomes deserve independent fixes.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

4. Wrapped and Unwrapped separate concerns

The documented unwrapRecord pattern allows a record parametrized with a wrapper to carry help metadata in its parsing type and ordinary values in its consumer type. This is a helpful boundary: help can be explicit without spreading documentation wrappers through business logic. Translation must preserve the parsed semantics after unwrapping; the output should have the same source path and limit across languages.

Keep a note of ownership and version. If the wording comes from library help generation, check the installed public API. If the wording comes from the application, change it with a catalog key and a semantic test. Never translate an internal identifier simply because it looks English, and never leave a user without an explanation because a technical token must remain stable.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

5. Defaults are parser behavior

The <!> operator supplies a default for a readable field. A translated help description may say that a limit defaults to 25, but that statement must match the actual value declared in the data type and read by the parser. Never translate a numeric default into a different value for rhetorical convenience. Test an omitted flag and an explicit –limit 25 invocation.

To make this decision useful for a real reader, first identify which part of atlascatalog –source atlas.csv –limit 25 is a typed token, which part is an input value, and which part is merely explanatory. Record the behavior before revising the wording. When a localized page makes a promise, turn that promise into a fixture: invoke a valid sample command, inspect the structured result and check that side effects match the guide.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

6. Positionals derive from record structure

A constructor without field labels may be interpreted as positional command-line arguments. That is a major distinction from labelled record fields. Explain in examples whether a user types –source atlas.csv or atlas.csv alone. Translating the placeholder label must never reorder positionals or make a required value seem optional.

This issue usually appears when source code, an English help screen and a translator’s draft are reviewed separately. Put them side by side. Ask the maintainer to show what Haskell optparse-generic actually accepts, ask the language reviewer to describe the intended operation without consulting English, and let the test suite arbitrate differences. A good edit survives both kinds of review.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

7. Special field types affect multiplicity

The documentation illustrates Bool, Maybe, list and monoidal wrappers such as First, Last, Sum and Product. Each changes how flags or repeated arguments are interpreted. A translated explanation should say whether a switch may repeat and what the result means; do not invent semantics by assuming that all repeated options override the prior value.

A small example is better than a sweeping claim. Build a disposable input, run it once successfully and then change only the display language. If the parsed values or selected files differ, the localization boundary has moved too far. If behavior matches but the reader cannot explain what happened, the prose is still not adequate. Both outcomes deserve independent fixes.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

8. Parsing errors are not grammar lessons

An invalid –limit bananas value is a type error, not a misunderstanding of English words. Show an exact valid command and a human explanation that an integer is required. If a library-owned error remains in a base language, provide optional application-owned recovery guidance without brittle substitution inside the upstream diagnostic.

Keep a note of ownership and version. If the wording comes from library help generation, check the installed public API. If the wording comes from the application, change it with a catalog key and a semantic test. Never translate an internal identifier simply because it looks English, and never leave a user without an explanation because a technical token must remain stable.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

9. Localization may require application architecture

The documentation establishes help annotations and parser derivation, not a multilingual catalog loader. A team can choose a safe app-controlled locale selection strategy and, where necessary, construct locale-specific parser/help data without changing the public fields. Verify the actual API types before choosing a pattern, especially where type-level strings are compiled into declarations.

To make this decision useful for a real reader, first identify which part of atlascatalog –source atlas.csv –limit 25 is a typed token, which part is an input value, and which part is merely explanatory. Record the behavior before revising the wording. When a localized page makes a promise, turn that promise into a fixture: invoke a valid sample command, inspect the structured result and check that side effects match the guide.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

10. Type-level help text cannot always be runtime-swapped

The <?> operator uses a type-level Symbol in documented examples. A runtime locale setting cannot necessarily replace that static annotation on demand. This limit shapes a realistic plan: use distinct builds, generated declarations, or an application-owned help renderer where feasible. Never promise live dynamic substitution in compiled type-level annotations without a tested implementation.

This issue usually appears when source code, an English help screen and a translator’s draft are reviewed separately. Put them side by side. Ask the maintainer to show what Haskell optparse-generic actually accepts, ask the language reviewer to describe the intended operation without consulting English, and let the test suite arbitrate differences. A good edit survives both kinds of review.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

11. Unicode is accepted at more than one boundary

A Haskell String can represent non-Latin text, but shell argument encoding, terminal output, filesystem paths and installed locale settings still need practical testing. A path such as 地図 一覧.csv can be passed with quoting, but a terminal displaying broken characters may prevent users from diagnosing errors. Compare exact underlying path values as well as visible output.

A small example is better than a sweeping claim. Build a disposable input, run it once successfully and then change only the display language. If the parsed values or selected files differ, the localization boundary has moved too far. If behavior matches but the reader cannot explain what happened, the prose is still not adequate. Both outcomes deserve independent fixes.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

12. Numbers and locale display must not change types

A person may expect decimal commas or localized digit grouping, while a CLI flag is parsed as Int or Double according to its parser. Translate the explanation and format reports appropriately, but keep accepted argument syntax explicit. An example should not silently change 2.5 to 2,5 unless the actual parser accepts it and tests prove so.

Keep a note of ownership and version. If the wording comes from library help generation, check the installed public API. If the wording comes from the application, change it with a catalog key and a semantic test. Never translate an internal identifier simply because it looks English, and never leave a user without an explanation because a technical token must remain stable.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

13. Versioned examples matter for Haskell

Hackage lists optparse-generic 1.5.3, but a project may use an earlier release or a particular optparse-applicative dependency. Pin package versions in a build plan, compile examples with the actual toolchain and record relevant extensions. Type errors discovered by readers are not translation defects, yet they undermine trust in a multilingual guide.

To make this decision useful for a real reader, first identify which part of atlascatalog –source atlas.csv –limit 25 is a typed token, which part is an input value, and which part is merely explanatory. Record the behavior before revising the wording. When a localized page makes a promise, turn that promise into a fixture: invoke a valid sample command, inspect the structured result and check that side effects match the guide.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

14. Make parsing and field validation distinct

A record parser can accept a string path even if that file does not exist. The application must validate that the file is readable and has the required columns. A translated ‘invalid –source’ message should not conflate a syntax problem, missing file and malformed content. Separate these stages in both documentation and tests.

This issue usually appears when source code, an English help screen and a translator’s draft are reviewed separately. Put them side by side. Ask the maintainer to show what Haskell optparse-generic actually accepts, ask the language reviewer to describe the intended operation without consulting English, and let the test suite arbitrate differences. A good edit survives both kinds of review.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the acceptance test is concrete: the operator must be able to follow atlascatalog –source atlas.csv –limit 25, tell which output is a preview or final result, and recover from an invalid invocation. The reviewer should record the exact Haskell runtime and dependency versions used. This turns the topic from an abstract translation preference into a verifiable instruction that can be maintained through future releases.

Chapter 10 — Eighteen realistic troubleshooting investigations

The cases below describe different ways a Haskell optparse-generic translation can be polished but wrong. Each has a symptom, a repair and a verification step. They are examples for training and testing, not claims about defects in the library itself. Use fictitious data, preserve any real system’s access controls and rerun relevant checks when the underlying package is upgraded.

Investigation 1: Field name translated

What the operator encounters: An editor renames source to quelle in the Haskell record and changes the generated flag unintentionally. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Preserve the public record/flag identity or introduce a deliberate compatibility migration instead of editorial renaming. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Compile and compare generated help before and after the change. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 2: Helpful wrapper surprise

What the operator encounters: A developer translates help with <?> and then complains that printed records show Helpful constructors. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Explain the documented wrapper semantics and use unwrapRecord if the application needs plain consumer records. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Test the types and printed values of the parsed record. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 3: Default documented incorrectly

What the operator encounters: A translated manual says –limit defaults to 50 while the <!> annotation declares 25. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Review the compiled default rather than editing help in isolation. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Invoke the program without –limit and inspect the parsed value. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 4: Positional treated as flag

What the operator encounters: A constructor with anonymous fields is documented as requiring –source even though the parser accepts a positional. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Document the actual generated usage and avoid rewriting the data type for translation alone. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Capture help and parse a valid positional invocation. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 5: Integer localized as prose

What the operator encounters: A translator replaces –limit 25 with –limit twenty-five in an example. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Leave the accepted machine integer in the command and explain it nearby in natural language. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Run accepted and invalid limit fixtures. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 6: Repeated arguments misunderstood

What the operator encounters: A list field allows multiple values, but the translation says only the final value is kept. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Describe the value aggregation documented by the chosen field type and test its parsed structure. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Use two repeated inputs and inspect the resulting list. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 7: Bool switch confused

What the operator encounters: A Bool-derived switch is described as requiring a ‘true’ string following it. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Check the generated help, then distinguish presence of a flag from supplying a separate value. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Try the bare flag and a flagged value as separate tests. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 8: Path with spaces

What the operator encounters: A Japanese source filename contains a space and the example omits shell quoting. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Use correct shell quoting while preserving the Unicode filename as data. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Run a disposable fixture named 地図 一覧.csv. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 9: Static help translated at runtime

What the operator encounters: A team assumes a type-level <?> Symbol changes when LANG changes and ships identical help in all locales. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: State the compiled nature of that annotation and implement a verified application-level alternative if dynamic help is required. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Compare two locales in the final binary, not in source text alone. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 10: Placeholder changed to a token

What the operator encounters: An editor changes the displayed FILE placeholder into a word that looks like an actual command-line flag. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Differentiate placeholders from literal option spellings with formatting and one runnable example. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Ask a native-language tester to identify exactly what must be typed. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 11: File not found conflated with parse

What the operator encounters: The –source argument parses successfully, but the application cannot open the file and says ‘unknown option’. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Separate type/argument parsing from file-system validation and translate the correct recovery step. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Test missing path and unknown flag as distinct failures. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 12: Arabic code direction

What the operator encounters: Mixed RTL prose and LTR flags change the visual order of –source and a Windows drive path. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Keep command snippets directionally stable and copyable while allowing surrounding prose to flow naturally. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Copy examples from rendered pages and compare exact characters. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 13: CJK help alignment

What the operator encounters: East Asian wide characters produce visually misaligned help columns under narrow terminal widths. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Check actual display columns rather than assuming one code point equals one cell. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Capture 40-column and 80-column terminal help with CJK text. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 14: Obsolete language extensions

What the operator encounters: The tutorial omits the TypeOperators extension needed for an annotated field type. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: State the relevant GHC extensions in the code example and compile with pinned versions. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Run the included sample in a clean project. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 15: Unsupported runtime aliases

What the operator encounters: A manual invents a translated command alias without defining a corresponding parser. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Keep the actual generated flag spelling and translate the explanation, not the grammar. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Test the alias against the release artifact and remove it if unsupported. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 16: Separator misused

What the operator encounters: An example suggests — is ordinary punctuation instead of a shell/option parsing boundary. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Show the exact literal separator only where the installed parser supports that invocation. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Test leading-hyphen filenames under the actual parser. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 17: Error success mismatch

What the operator encounters: A wrapper formats a parse error as a friendly translated notice but exits with zero status. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Preserve failure exit codes and add clear recovery, without claiming the command completed. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Run an invalid option through a shell and capture status and files. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Investigation 18: Ambiguous Double format

What the operator encounters: A translated example changes a Double value from 2.5 to 2,5 without verifying accepted syntax. This matters because help text and a working parser can disagree even when each looks coherent in isolation. A human may follow instructions correctly and still make the wrong call, which is a documentation defect as much as an implementation problem.

A safe correction is specific: Separate localized display of quantities from the parser’s required input grammar. Keep the change limited to the right layer. Do not alter Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults in response to a purely linguistic problem, and do not hide actual application defects beneath nicer wording.

Proof before release: Test both spellings against the pinned library and toolchain. Then repeat the attempt under the default language and at least one translated locale. Compare the result class, stderr and exit status, and inspect whether any output file, report or cache was changed. Mark a test as passing only when the technical result and the reader’s understanding agree.

Chapter 11 — A multilingual acceptance matrix

  • English baseline: Use it to establish actual flags, commands, defaults, success behavior, and known error variants. Record this as a reference trace, not as the one correct grammatical form for every locale.
  • French: Look for long descriptions, distinction between a command and a suggestion, correct treatment of filenames and quantities, and errors that say whether a file is absent or invalid.
  • German: Check compound nouns, table widths, longer help lines and precise distinction between validation and execution. Confirm that examples still contain exact option names.
  • Japanese: Check CJK terminal cell widths, natural task explanations, non-Latin filenames, copied quotes and an unambiguous explanation of values versus placeholders.
  • Arabic: Check right-to-left prose beside left-to-right program tokens, numerals and paths. Verify that copied commands preserve byte order and the underlying command has not been visually rearranged.
  • Hindi and Tamil: Test complex-script rendering, longer instructional sentences, font availability and clear presentation of syntax fragments. Do not use romanization as a substitute for genuine localized guidance without product justification.
  • Spanish and Portuguese: Check regional variations, units, number formatting and whether translated verbs imply a read-only check or a write. Numeric argument syntax must remain what the program actually parses.

The matrix is a set of test questions, not evidence that these locales already ship with Haskell optparse-generic. The application owner must say which languages are supported, how they are selected, who reviews them and which environments are in scope. It is better to support a few languages accurately than to advertise many through untranslated dependency errors and untested scripts.

Chapter 12 — Twelve reader-focused practical exercises

Exercise 1: Generic fields become public interface

The purpose of this exercise is to make generic fields become public interface understandable to someone who has not studied the library source. First, have a learner predict the effect of a safe invocation before executing it; write down the predicted input, output and any possible side effects. Then change the display language, not the command, and have a second learner repeat the prediction without reading the first answer. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: A record such as Query { source :: FilePath, limit :: Int } is Haskell data, yet optparse-generic uses its shape to derive command-line syntax. The field label source can become the long flag –source. Treat renaming a record field as an interface migration, not a harmless translation edit. If help needs a different natural-language phrase, provide an explanation without silently changing the flag name. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 2: getRecord creates useful first-run help

The purpose of this exercise is to make getrecord creates useful first-run help understandable to someone who has not studied the library source. Use an intentionally invalid command to examine recovery guidance. Preserve the typed tokens in the report, identify the exact rejection stage, and ask the learner to choose the next permitted action rather than merely translate the displayed error. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: getRecord accepts a program description and reads CLI arguments into a typed record. A localized explanation should make the program’s task clear before listing switches, but the type inference and field parser remain unaffected by prose alone. When a language requires a longer description, inspect how help wraps instead of stripping away important scope or side-effect words. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 3: Helpful is a real type-level wrapper

The purpose of this exercise is to make helpful is a real type-level wrapper understandable to someone who has not studied the library source. Create two local fixtures: one valid and one that violates the condition under discussion. Test each in the base language and a translated language, comparing the parser result and real files, not just the text on screen. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: The <?> annotation associates help text with a field, using Helpful and type-level symbols. The documentation shows that printed results may contain a Helpful wrapper unless a different record design is used. Explain that this is a type-and-derivation concern, not a translation problem. Never advise translators to delete type annotations merely to make runtime output look cleaner. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 4: Wrapped and Unwrapped separate concerns

The purpose of this exercise is to make wrapped and unwrapped separate concerns understandable to someone who has not studied the library source. Review a narrow-terminal rendering and a copied command. Ask the learner to identify which components are executable grammar, which are placeholders and which describe behavior. Then paste the command into a disposable environment and verify the claim. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: The documented unwrapRecord pattern allows a record parametrized with a wrapper to carry help metadata in its parsing type and ordinary values in its consumer type. This is a helpful boundary: help can be explicit without spreading documentation wrappers through business logic. Translation must preserve the parsed semantics after unwrapping; the output should have the same source path and limit across languages. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 5: Defaults are parser behavior

The purpose of this exercise is to make defaults are parser behavior understandable to someone who has not studied the library source. First, have a learner predict the effect of a safe invocation before executing it; write down the predicted input, output and any possible side effects. Then change the display language, not the command, and have a second learner repeat the prediction without reading the first answer. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: The <!> operator supplies a default for a readable field. A translated help description may say that a limit defaults to 25, but that statement must match the actual value declared in the data type and read by the parser. Never translate a numeric default into a different value for rhetorical convenience. Test an omitted flag and an explicit –limit 25 invocation. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 6: Positionals derive from record structure

The purpose of this exercise is to make positionals derive from record structure understandable to someone who has not studied the library source. Use an intentionally invalid command to examine recovery guidance. Preserve the typed tokens in the report, identify the exact rejection stage, and ask the learner to choose the next permitted action rather than merely translate the displayed error. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: A constructor without field labels may be interpreted as positional command-line arguments. That is a major distinction from labelled record fields. Explain in examples whether a user types –source atlas.csv or atlas.csv alone. Translating the placeholder label must never reorder positionals or make a required value seem optional. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 7: Special field types affect multiplicity

The purpose of this exercise is to make special field types affect multiplicity understandable to someone who has not studied the library source. Create two local fixtures: one valid and one that violates the condition under discussion. Test each in the base language and a translated language, comparing the parser result and real files, not just the text on screen. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: The documentation illustrates Bool, Maybe, list and monoidal wrappers such as First, Last, Sum and Product. Each changes how flags or repeated arguments are interpreted. A translated explanation should say whether a switch may repeat and what the result means; do not invent semantics by assuming that all repeated options override the prior value. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 8: Parsing errors are not grammar lessons

The purpose of this exercise is to make parsing errors are not grammar lessons understandable to someone who has not studied the library source. Review a narrow-terminal rendering and a copied command. Ask the learner to identify which components are executable grammar, which are placeholders and which describe behavior. Then paste the command into a disposable environment and verify the claim. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: An invalid –limit bananas value is a type error, not a misunderstanding of English words. Show an exact valid command and a human explanation that an integer is required. If a library-owned error remains in a base language, provide optional application-owned recovery guidance without brittle substitution inside the upstream diagnostic. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 9: Localization may require application architecture

The purpose of this exercise is to make localization may require application architecture understandable to someone who has not studied the library source. First, have a learner predict the effect of a safe invocation before executing it; write down the predicted input, output and any possible side effects. Then change the display language, not the command, and have a second learner repeat the prediction without reading the first answer. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: The documentation establishes help annotations and parser derivation, not a multilingual catalog loader. A team can choose a safe app-controlled locale selection strategy and, where necessary, construct locale-specific parser/help data without changing the public fields. Verify the actual API types before choosing a pattern, especially where type-level strings are compiled into declarations. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 10: Type-level help text cannot always be runtime-swapped

The purpose of this exercise is to make type-level help text cannot always be runtime-swapped understandable to someone who has not studied the library source. Use an intentionally invalid command to examine recovery guidance. Preserve the typed tokens in the report, identify the exact rejection stage, and ask the learner to choose the next permitted action rather than merely translate the displayed error. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: The <?> operator uses a type-level Symbol in documented examples. A runtime locale setting cannot necessarily replace that static annotation on demand. This limit shapes a realistic plan: use distinct builds, generated declarations, or an application-owned help renderer where feasible. Never promise live dynamic substitution in compiled type-level annotations without a tested implementation. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 11: Unicode is accepted at more than one boundary

The purpose of this exercise is to make unicode is accepted at more than one boundary understandable to someone who has not studied the library source. Create two local fixtures: one valid and one that violates the condition under discussion. Test each in the base language and a translated language, comparing the parser result and real files, not just the text on screen. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: A Haskell String can represent non-Latin text, but shell argument encoding, terminal output, filesystem paths and installed locale settings still need practical testing. A path such as 地図 一覧.csv can be passed with quoting, but a terminal displaying broken characters may prevent users from diagnosing errors. Compare exact underlying path values as well as visible output. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Exercise 12: Numbers and locale display must not change types

The purpose of this exercise is to make numbers and locale display must not change types understandable to someone who has not studied the library source. Review a narrow-terminal rendering and a copied command. Ask the learner to identify which components are executable grammar, which are placeholders and which describe behavior. Then paste the command into a disposable environment and verify the claim. In AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, the worked example is atlascatalog –source atlas.csv –limit 25. Use sample inputs only, and keep a record of the version, locale, expected result, actual result and the exact sentence that caused confusion.

The decision at stake is this: A person may expect decimal commas or localized digit grouping, while a CLI flag is parsed as Int or Double according to its parser. Translate the explanation and format reports appropriately, but keep accepted argument syntax explicit. An example should not silently change 2.5 to 2,5 unless the actual parser accepts it and tests prove so. A reviewer should be able to explain why a misleading translation changes the operator’s decision, not merely say that two sentences sound different. If testing reveals an implementation bug, fix that separately and rerun the language review. A completed exercise leaves a small reproducible proof that the documentation matches the product.

Chapter 13 — Frequently asked questions

Does optparse-generic provide built-in translations?

Its documented features concern generic parser derivation and help annotations. Do not assume a runtime locale catalog exists. Design any translated help system against verified APIs and clearly identify application-owned features.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, settle this with a real command and a controlled fixture rather than intuition. A helpful answer names the stable part of Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults, identifies the reader-facing explanation, and shows how to verify the outcome without production data. Where support depends on package version, test the installed release rather than assuming universal behavior.

Does <?> change my parsed value?

The documented Helpful annotation can affect the printed type structure. The wrapped/unwrapped record pattern addresses this when ordinary consumer values are desired.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, settle this with a real command and a controlled fixture rather than intuition. A helpful answer names the stable part of Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults, identifies the reader-facing explanation, and shows how to verify the outcome without production data. Where support depends on package version, test the installed release rather than assuming universal behavior.

Why not translate record field labels?

Field labels can generate public flag names. Renaming them can break callers and scripts. Translate help prose first, and treat a flag rename as an explicit compatibility change.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, settle this with a real command and a controlled fixture rather than intuition. A helpful answer names the stable part of Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults, identifies the reader-facing explanation, and shows how to verify the outcome without production data. Where support depends on package version, test the installed release rather than assuming universal behavior.

Can I put runtime translations inside a type-level Symbol?

Not as an ordinary runtime string substitution. The documented annotation is type-level; a real dynamic strategy needs compatible code design and compilation tests.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, settle this with a real command and a controlled fixture rather than intuition. A helpful answer names the stable part of Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults, identifies the reader-facing explanation, and shows how to verify the outcome without production data. Where support depends on package version, test the installed release rather than assuming universal behavior.

How should a default be translated?

Explain its meaning, units and when it is used; do not alter the value. Test the no-flag invocation against the declared default.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, settle this with a real command and a controlled fixture rather than intuition. A helpful answer names the stable part of Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults, identifies the reader-facing explanation, and shows how to verify the outcome without production data. Where support depends on package version, test the installed release rather than assuming universal behavior.

Should examples use localized decimal commas?

Only if the parser really accepts them. Most dependable guides use the accepted literal syntax in code and explain local display conventions outside the invocation.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, settle this with a real command and a controlled fixture rather than intuition. A helpful answer names the stable part of Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults, identifies the reader-facing explanation, and shows how to verify the outcome without production data. Where support depends on package version, test the installed release rather than assuming universal behavior.

What needs terminal testing?

Help wrapping, UTF-8 input and output, filenames with spaces, non-Latin paths, copied commands, stderr, exit codes and actual output effects.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, settle this with a real command and a controlled fixture rather than intuition. A helpful answer names the stable part of Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults, identifies the reader-facing explanation, and shows how to verify the outcome without production data. Where support depends on package version, test the installed release rather than assuming universal behavior.

What is the quality gate for release?

A clean compile, actual parser behavior assertions, native-language comprehension checks, accurate errors and a stable public command contract.

For AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, settle this with a real command and a controlled fixture rather than intuition. A helpful answer names the stable part of Generic record field names, generated option spellings, type-derived values, positional order, parser behavior and documented defaults, identifies the reader-facing explanation, and shows how to verify the outcome without production data. Where support depends on package version, test the installed release rather than assuming universal behavior.

Chapter 14 — A four-week implementation and review plan

Week 1: inventory the interface

Capture root help, nested help, sample invocations and errors from the released application. Map every visible message to its owner, list supported commands, record exact dependency and runtime versions, and classify input values separately from strings meant for translation. Choose two real reader tasks. A good result for this week is a short baseline document with no uncertainty about what the program actually accepts.

Applied to Haskell optparse-generic, this week’s exit condition must be checked in both code and language. Use atlascatalog –source atlas.csv –limit 25 with a disposable fixture, retain the original command spellings and compare the intended operation with the observed result. Do not advance merely because the text sounds polished; advance when a learner can predict and verify what the tool will do.

Week 2: draft and integrate language support

Choose supported locales and a fallback policy. Translate complete tasks, warnings and recovery instructions instead of isolated words, preserving fixed tokens. Connect application-owned strings to catalog keys or another version-appropriate system, and leave library-owned text identified where override support is unavailable. Ask developers to review every promise about writes, permissions, defaults, file formats and errors.

Applied to Haskell optparse-generic, this week’s exit condition must be checked in both code and language. Use atlascatalog –source atlas.csv –limit 25 with a disposable fixture, retain the original command spellings and compare the intended operation with the observed result. Do not advance merely because the text sounds polished; advance when a learner can predict and verify what the tool will do.

Week 3: behavior and comprehension testing

Run successful and invalid input fixtures under each chosen locale. Compare parsed values, stdout/stderr channels, exit statuses and output effects; also test non-ASCII paths, terminal width and copied code snippets. Ask native-language reviewers to complete the two original tasks without English guidance and record where decisions fail. Correct both functional and wording faults; re-run the baseline tests.

Applied to Haskell optparse-generic, this week’s exit condition must be checked in both code and language. Use atlascatalog –source atlas.csv –limit 25 with a disposable fixture, retain the original command spellings and compare the intended operation with the observed result. Do not advance merely because the text sounds polished; advance when a learner can predict and verify what the tool will do.

Week 4: publish, monitor and maintain

Finalize a short quick-start, supported-version note, option reference, troubleshooting guide and fallback disclosure. Publish only tested examples, with a release checklist signed by engineering and language reviewers. Keep the command contract versioned, record known limitations and add regression fixtures for defects found during real support requests. A translation is complete when a reader can finish the task safely, not when the catalog has no empty cells.

Applied to Haskell optparse-generic, this week’s exit condition must be checked in both code and language. Use atlascatalog –source atlas.csv –limit 25 with a disposable fixture, retain the original command spellings and compare the intended operation with the observed result. Do not advance merely because the text sounds polished; advance when a learner can predict and verify what the tool will do.

Chapter 15 — Professional standard and next step

The best multilingual command-line documentation is boring in the most useful sense: the examples execute as written, the parser behaves consistently, the outputs say what happened and the reader knows how to repair a failure. With Haskell optparse-generic, translation quality depends on respecting how the framework defines commands and values while giving humans accurate descriptions of those same structures.

Start from one small task in AtlasCatalog, an illustrative tool that checks a local geographic-place catalog and produces a read-only coverage report, verify it in the default language, translate its complete explanation and test the same action again. Expand to errors, more commands and additional locales only when earlier behavior stays stable. That sequence makes multilingual support maintainable for new contributors, reviewers and users who cannot ask the original developer what a sentence was supposed to mean.

Primary technical references and related translation guides