Pushkal-Gupta opened a new pull request, #75326:
URL: https://github.com/apache/airflow/pull/75326

   Seven labels in the UI show a translation key instead of a sentence.
   
   Set a pool name longer than 256 characters and the validation error reads:
   
   > pools.form.rules.nameMaxLength
   
   It should read "Name can contain a maximum of 256 characters". That string 
already exists, and is already translated into all 21 languages. The form just 
asks for it by the wrong name.
   
   ## What a user sees today
   
   Each of these keys is missing from the `en` bundles, so i18next renders the 
key itself:
   
   | Where | Key asked for | What is shown |
   | --- | --- | --- |
   | Pool form validation | `admin:pools.form.rules.nameMaxLength` | 
`pools.form.rules.nameMaxLength` |
   | Config form error | `common:error.unknown` | `error.unknown` |
   | Connection form error | `common:error.unknown` | `error.unknown` |
   | Dag code page | `dag:dagDetails.bundleVersion` | 
`dagDetails.bundleVersion` |
   | XCom column header | `dashboard:timestamp` | `timestamp` |
   | Table sort button | `components:sort` | `sort` |
   | Dag schedule | `dags:schedule.asset` | `schedule.asset` |
   
   Those are real outputs, read off an i18next instance built from the `en` 
bundles.
   
   ## Three different causes
   
   **Two ask for a string that exists under another name.** 
`pools.form.nameMaxLength` and `common:error.defaultMessage` are both present 
and translated in all 21 locales, so correcting the call restores the text in 
every language at once.
   
   In `PoolForm.tsx` the line above already gets it right:
   
   ```js
   required: translate("pools.form.nameRequired"),
   validate: (_value) => _value.length <= 256 || 
translate("pools.form.rules.nameMaxLength"),
   ```
   
   The extra `rules.` reads like it came from the `rules: {}` object the call 
sits in. No locale has ever defined `pools.form.rules`, and `common:error` has 
`defaultMessage` but never had `unknown`.
   
   **Three were never written.** `dagDetails.bundleVersion`, 
`xcom.columns.timestamp` and `components:sort` do not exist in any locale, so 
this adds them to `en` and leaves the other languages to translators, as usual. 
The XCom header was also reaching into the `dashboard` namespace for a column 
title; it now sits with the `dag`, `key` and `value` headers it belongs to.
   
   **One is a comparison that can never be true.** `Schedule.tsx` chose between 
two views with:
   
   ```js
   timetableSummary === translate("schedule.asset")
   ```
   
   `timetableSummary` comes from the server as 
`AssetTriggeredTimetable.summary`, which is the fixed literal `"Asset"`. 
Comparing it to a translated string is wrong even with the key in place, 
because a translator localising that word would break the check in their 
language. With the key missing it compares against `"schedule.asset"` and never 
matches. It now compares against the literal, with a comment recording where 
the value comes from.
   
   This one has stayed hidden because the `||` before it means the asset view 
still appeared whenever `asset_expression` was set.
   
   ## The test
   
   `locales.test.ts` gains one check: walk every `.ts` and `.tsx` file under 
`src/`, collect the namespaces each file loads and every literal key it passes 
to `translate(...)`, and assert i18next can resolve them. It fails without this 
change and names all seven. Keys built by interpolation are skipped, as they 
only exist at run time.
   
   It asks i18next rather than reimplementing the lookup, which turned out to 
matter. My first attempt reported 52 failures, nearly all wrong, because a 
hand-rolled check misses three things the real resolver handles:
   
   - plural-only keys, stored as `foo_one` and `foo_other` with no plain `foo`
   - flat keys that contain dots, like `"limitedList.allItems"` in 
`components.json`
   - a file listing several namespaces, all of which i18next searches, not just 
the first
   
   `exists(key, { count: 1 })` gets all three right. The counter-placeholder 
tests already in this file build an instance the same way.
   
   Nothing checked this before. `locales.test.ts` only verified counter 
formatting, which is why seven keys could drift.
   
   ## Checks
   
   - 1961 UI tests pass, 239 files
   - `eslint` and `tsc` clean
   - the new check reports 0 missing of 1256 keys after the change, 7 before
   
   ---
   
   ##### Was generative AI tooling used to co-author this PR?
   
   - [X] Yes - Claude Code (Opus 5)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to