This is an automated email from the ASF dual-hosted git repository.

bbovenzi pushed a commit to branch v3-3-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v3-3-test by this push:
     new addfc8511f8 [v3-3-test] UI: Fix preventRunningTasks showing as raw 
i18n key in Clear Task dialogs (#71045) (#71240)
addfc8511f8 is described below

commit addfc8511f81273215f8c4e0c85636a581abe851
Author: github-actions[bot] 
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Aug 6 12:53:01 2026 -0400

    [v3-3-test] UI: Fix preventRunningTasks showing as raw i18n key in Clear 
Task dialogs (#71045) (#71240)
    
    * UI: Add missing preventRunningTasks translation for Italian and Thai
    
    The Italian and Thai locale files were missing the
    runAndTaskActions.options.preventRunningTasks key that was added to
    the English locale, so users on those locales saw the raw
    translation key instead of localized text in the clear task dialogs.
    
    * UI: Bust the translation cache when the version lookup fails
    
    The i18n loadPath is cache-busted with the running Airflow version, but
    on a failed VersionService.getVersion() call it silently fell back to
    an un-versioned request. Behind a caching CDN or browser cache (e.g. a
    managed deployment like Astronomer), that can serve a translation
    bundle cached from before a key was added, so newer keys render as raw
    i18n keys (see #71007) while older, already-cached keys translate
    fine. Fall back to a timestamp instead so the cache is always busted.
    
    * Apply suggestion from @bbovenzi
    
    ---------
    (cherry picked from commit 3dd137020958d69fc1d6f386ab5e0765ddd15dab)
    
    Co-authored-by: krystianpl26 
<[email protected]>
    Co-authored-by: krystianpl26 <[email protected]>
    Co-authored-by: Brent Bovenzi <[email protected]>
    Co-authored-by: Brent Bovenzi <[email protected]>
---
 .../src/airflow/ui/public/i18n/locales/it/dags.json  |  1 +
 .../src/airflow/ui/public/i18n/locales/th/dags.json  |  1 +
 airflow-core/src/airflow/ui/src/i18n/config.test.ts  | 20 ++++++++++++++++++--
 airflow-core/src/airflow/ui/src/i18n/config.ts       | 18 +++++++++++-------
 4 files changed, 31 insertions(+), 9 deletions(-)

diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/it/dags.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/it/dags.json
index 6c6ab552ddc..29258d25869 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/it/dags.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/it/dags.json
@@ -61,6 +61,7 @@
       "future": "Futuro",
       "onlyFailed": "Pulisci solo le task fallite",
       "past": "Passato",
+      "preventRunningTasks": "Impedisci la riesecuzione se la task è in 
esecuzione",
       "queueNew": "Inserisci nuove task",
       "runOnLatestVersion": "Esegui con l'ultima versione del bundle",
       "upstream": "Upstream"
diff --git a/airflow-core/src/airflow/ui/public/i18n/locales/th/dags.json 
b/airflow-core/src/airflow/ui/public/i18n/locales/th/dags.json
index 9b1ce043e8f..106ded489ec 100644
--- a/airflow-core/src/airflow/ui/public/i18n/locales/th/dags.json
+++ b/airflow-core/src/airflow/ui/public/i18n/locales/th/dags.json
@@ -61,6 +61,7 @@
       "future": "งานในอนาคต",
       "onlyFailed": "ล้างเฉพาะงานที่ล้มเหลว",
       "past": "งานในอดีต",
+      "preventRunningTasks": "ป้องกันการรันซ้ำหากงานกำลังทำงาน",
       "queueNew": "จัดคิวงานใหม่",
       "runOnLatestVersion": "ทำงานด้วยเวอร์ชันล่าสุดของชุดรวม (Bundle)",
       "upstream": "งานก่อนหน้า"
diff --git a/airflow-core/src/airflow/ui/src/i18n/config.test.ts 
b/airflow-core/src/airflow/ui/src/i18n/config.test.ts
index 9a49276fd33..fabde912791 100644
--- a/airflow-core/src/airflow/ui/src/i18n/config.test.ts
+++ b/airflow-core/src/airflow/ui/src/i18n/config.test.ts
@@ -17,9 +17,11 @@
  * under the License.
  */
 import { createInstance } from "i18next";
-import { describe, expect, it } from "vitest";
+import { describe, expect, it, vi } from "vitest";
 
-import { convertDetectedLanguage, i18nBaseOptions } from "./config";
+import { VersionService } from "openapi/requests/services.gen";
+
+import { convertDetectedLanguage, i18nBaseOptions, resolveI18nVersion } from 
"./config";
 
 // getBestMatchFromCodes is the resolver i18next runs on the array the
 // LanguageDetector returns. It is not part of i18next's public types
@@ -89,3 +91,17 @@ describe("i18n language resolution", () => {
     expect(await resolveLanguage(["hi-IN", "en"])).toBe("hi");
   });
 });
+
+describe("resolveI18nVersion", () => {
+  it("resolves to the running version", async () => {
+    vi.spyOn(VersionService, "getVersion").mockResolvedValueOnce({ 
git_version: null, version: "3.2.2" });
+
+    await expect(resolveI18nVersion()).resolves.toBe("3.2.2");
+  });
+
+  it("falls back to a cache-busting value, not an empty string, when the 
version lookup fails", async () => {
+    vi.spyOn(VersionService, "getVersion").mockRejectedValueOnce(new 
Error("network error"));
+
+    await expect(resolveI18nVersion()).resolves.not.toBe("");
+  });
+});
diff --git a/airflow-core/src/airflow/ui/src/i18n/config.ts 
b/airflow-core/src/airflow/ui/src/i18n/config.ts
index 20b2970d9af..8b4ce747c6e 100644
--- a/airflow-core/src/airflow/ui/src/i18n/config.ts
+++ b/airflow-core/src/airflow/ui/src/i18n/config.ts
@@ -144,12 +144,16 @@ const initI18n = (version: string) => {
     });
 };
 
-void VersionService.getVersion()
-  .then((data) => {
-    initI18n(data.version);
-  })
-  .catch(() => {
-    initI18n("");
-  });
+// Falling back to an empty version on failure would drop the `?v=` cache
+// buster from the translation loadPath, letting a CDN/browser keep serving a
+// translation bundle cached from before the running version, indefinitely
+// missing any keys added since. A timestamp isn't the true version, but it
+// still busts the cache on every retry.
+export const resolveI18nVersion = (): Promise<string> =>
+  VersionService.getVersion()
+    .then((data) => data.version)
+    .catch(() => Date.now().toString());
+
+void resolveI18nVersion().then(initI18n);
 
 export { default } from "i18next";

Reply via email to