skip to content

What does the # language: header at the top of a Cucumber feature file change, and what breaks when it is missing?

level: middleimportance: nice to knowfreq 19%

answer

  1. A comment-shaped header on line one
  2. Keywords are translated, step text is not
  3. Dialect tables ship in gherkin-languages.json
  4. No header means the English keyword table

basics

~20 s

The header selects the Gherkin dialect for that one file, changing only the keywords the parser accepts. Step text and step definitions are untouched. Without it the parser assumes English, so localized keywords fail to parse.

solid answer

~40 s

`# language: fr` on the first line of a `.feature` file tells the Gherkin parser to accept the French keyword table instead of the English one, so the file may say `Fonctionnalité:`, `Contexte:`, `Scénario:`, `Quand` and `Alors`. The keyword tables come from the Gherkin project's `gherkin-languages.json` and are the same in Cucumber-JVM, cucumber-js, Behave and SpecFlow/Reqnroll. It changes **keywords only**: the step text after the keyword, your step-definition code and expressions, and tag names are all untouched - and because the step keyword is stripped before a step is matched, translating keywords never affects which step definition binds. The header is per file, must sit above the feature header, and there is no auto-detection: if it is missing or misplaced, the parser uses English and a localized keyword becomes a syntax error.

code

gherkin · 9 lines
gherkin
# language: fr
Fonctionnalité: Commande de repas scolaires

  Contexte:
    Étant donné que la cantine peut préparer 318 repas

  Scénario: Commande acceptée avant la clôture
    Quand un parent commande 2 repas à 09:41
    Alors la commande est acceptée

go deeper

for a junior

Know that a feature file can be written in a language other than English, and that the choice is made by a header on the first line rather than by a setting somewhere in the build.

for a middle

Explain exactly what the header does and does not reach: keywords yes, step text and glue code no. Say where the header must sit and what the parser does when it is absent - English keywords, then a syntax error on the first localized keyword.

for a senior

Show judgement about when localization pays for itself. It earns its cost when domain experts read the files in their own language; otherwise it buys tooling friction with editor plugins, snippet generation and report viewers for no reader benefit.

for a principal

Own the convention across teams and locales: one dialect per suite or per team, how mixed-language step text is prevented from fragmenting the shared vocabulary, and whether the readership actually justifies translating the keywords at all.

## What the header is, and how the dialect is chosen Gherkin is localized. The keywords the parser accepts — `Feature`, `Background`, `Scenario`, `Examples`, `Given`, `When`, `Then`, `And`, `But` — have translations in a large number of languages, and Cucumber picks which set applies **per file** from a header written in comment form on the first line: ``` # language: fr Fonctionnalité: Commande de repas scolaires ``` The header looks like a comment because it *is* comment-shaped — `#` followed by `language:` and a language code. It must come at the top of the file, above the feature header. There is no auto-detection: without the header the parser uses the default dialect, English. The keyword tables themselves are not invented per implementation. They live in the Gherkin project's own `gherkin-languages.json`, which every Cucumber implementation ships, so `# language: fr` means the same keywords in Cucumber-JVM, cucumber-js, Behave and SpecFlow/Reqnroll. ## What it changes — and what it does not The header changes **the vocabulary the parser recognises**, and nothing else. | Element | Translated by the header? | |---|---| | `Feature`, `Rule`, `Background`, `Scenario`, `Examples` keywords | yes | | `Given` / `When` / `Then` / `And` / `But` step keywords | yes | | The `*` bullet step keyword | no — it is valid in every dialect | | The **text** of a step, after the keyword | no — you write it in whatever language you like | | Step-definition code, expressions and parameter types | no | | Tag names | no — tags are names your team invents | | Table and doc-string syntax | no — `\|` and the triple-quote delimiter are universal | The consequence people miss: because the step keyword is stripped before a step is matched to a step definition, **translating keywords does not change your glue layer at all**. A French feature file whose steps read `Quand un parent commande 2 repas` needs a step definition whose expression matches `un parent commande 2 repas`. It is the step *text* — which the header never touches — that decides whether your glue matches. So a team writing French keywords with English step text is perfectly valid, and a team writing English keywords with French step text is equally valid; the header only governs the first word of each line. An extra subtlety worth knowing: in some dialects a step keyword is not followed by a space at all, because the language does not use one. The keyword table, not a "split on the first space" rule, defines where the keyword ends and the step text begins. ## When the header is missing, misspelled or in the wrong place If a file uses localized keywords and the header is absent, misspelled, or written below the `Feature` line, the parser falls back to English keywords. `Fonctionnalité:` then matches no known keyword, and the file fails to parse — Cucumber reports a syntax error for that file rather than running its scenarios or reporting them as undefined. The failure is loud, which is the good news: you find out at parse time, not through a silently skipped feature. Because the header is per file, a suite can mix dialects — one file in French, another in English — and each is parsed with its own keyword table. There is no way to write two dialects inside one file. ## Practical guidance - **Pick one dialect per suite** and enforce it in review. On a school-meal ordering service where a kitchen-operations team writes scenarios in French and a platform team writes them in English, the parse still works, but the suite reads as two products and the shared step text drifts into two vocabularies. - **Localize the keywords only if the readers are non-English speakers.** The value of a dialect is that a domain expert can read the file. If everyone who reads it works in English, translated keywords buy nothing and cost you tooling friction — editor plugins, snippet generation and third-party report viewers all handle the default dialect best. - **Never localize half a file.** Since the dialect is chosen once per file, a single English `Scenario:` in a French file simply does not parse. - **Remember the header is the first line.** A tag line or a licence comment pushed above it is the usual cause of a mysterious "this worked yesterday" parse failure after a header-stamping script runs over the repository. Interviewers rarely gate an offer on this, but it is a clean signal: a candidate who knows the header changes keywords and not step text has understood how a step reaches its definition.

  • Does changing the dialect change how a step is matched to its step definition?
    No. The step keyword is stripped before matching, so only the step text is offered to the expression. A French file whose step reads `Quand un parent commande 2 repas` needs an expression matching `un parent commande 2 repas`. Keywords and glue code are independent - you can translate one without touching the other.
  • Can two feature files in the same suite use different dialects?
    Yes. The header is per file, so one file can be French and the next English, and each is parsed with its own keyword table. What you cannot do is mix dialects inside one file: the dialect is chosen once, so a single English `Scenario:` line in a French file will not parse.

saying these in an interview costs you the question

  • Thinks the header translates step text as well as keywords
  • Believes Cucumber detects the dialect from the file content
  • Puts the language header below the feature header
  • Says localized keywords require localized step definitions
  • Assumes one header sets the dialect for the whole suite