Skip to content

Commit f4ce10c

Browse files
fix(platform-objects): re-translate the object leaves that contradict their current en source (#20652)
Fixes #20539 Clause-②: no ## What changed A translated leaf in `packages/platform-objects/src/apps/translations/{ja-JP,es-ES,zh-CN}.objects.generated.ts` that a translator wrote by hand keeps its value when its `en` source changes later. Some of those leaves still said what the old source said. This PR measures that set first, then re-translates the leaves whose meaning now **contradicts** the current `en`: **19 leaves** (ja-JP 4, es-ES 11, zh-CN 4). The leaves whose `en` only gained detail or was reworded are listed below and left as written. - Values only. No key is added or dropped, no `en` file is edited, and no provenance companion or echo-decision ledger changes (measured below; the tooling requires none). - `.changeset/20539-stale-authored-object-leaves.md`: `@objectstack/platform-objects` `patch`. - No new gate, per triage. No test pins a translation string. ## The measurement (taken on this branch at base `cd901d7a5`, before any edit) ### Instrument A diff of `en` since each authored leaf's last edit, as the card names it, run over git history: 1. **Population.** Every string leaf of each locale's objects bundle at the ref, minus two classes that are not authored: a leaf byte-equal to the current `en` leaf (an echo, owned by the echo ledgers), and a leaf with a row in the locale's `*.source-hashes.generated.ts` (a recorded byte copy, owned by `check:i18n-stale-fill`). What is left is the authored set. 2. **Last edit.** Walk every first-parent `main` commit that touched the locale bundle, oldest first, parse the object literal at each, and record for each path the commit where its value last changed. Values are compared parsed, so a reformat is not an edit. For a leaf that landed through a merge commit, `en` is also read at the branch side. 3. **Verdict.** Compare `en`'s value for the same path at that commit with `en` today. If they differ, `en` moved after the leaf was last edited, and the leaf is a candidate. Meaning is then judged by hand for each candidate. It reads the `en` **bundle** history rather than the object source files. Today `en` is the source, byte for byte (`pnpm check:i18n` green). Before `8af76aebf` the `en` bundle could lag its source, and that lag only ever adds candidates; it never hides one. The bundle diff is therefore at least as sensitive as a source diff, and it survives object files moving between packages. Full history is required: the checkout was shallow (499 commits) and was unshallowed to 15092 before the run. The same logic, condensed, reproduces the full instrument's candidate sets exactly at `cd901d7a5` and `3fa342501`: ```js // node instrument.mjs REF (run from the repo root; needs full, unshallowed history) import { execFileSync as x } from 'node:child_process'; const REF = process.argv[2] || 'HEAD', D = 'packages/platform-objects/src/apps/translations/'; const git = (...a) => x('git', a, { encoding: 'utf8', maxBuffer: 268435456 }); const leaves = (o, pre = '', m = new Map()) => { for (const [k, v] of Object.entries(o)) { const p = pre ? pre + '.' + k : k; if (typeof v === 'string') m.set(p, v); else if (v && typeof v === 'object') leaves(v, p, m); } return m; }; const at = (rev, f) => { const s = git('show', rev + ':' + D + f); return leaves(new Function('return (' + s.slice(s.indexOf('= {', s.indexOf('export const')) + 2, s.lastIndexOf('};') + 1) + ');')()); }; const enNow = at(REF, 'en.objects.generated.ts'); for (const L of ['ja-JP', 'es-ES', 'zh-CN']) { const f = L + '.objects.generated.ts', last = new Map(); let prev = new Map(); for (const c of git('log', '--first-parent', '--format=%H', REF, '--', D + f).trim().split('\n').reverse()) { const cur = at(c, f); for (const [p, v] of cur) if (prev.get(p) !== v) last.set(p, c); prev = cur; } const recorded = git('show', REF + ':' + D + L + '.source-hashes.generated.ts'); let authored = 0; const cands = []; for (const [p, v] of at(REF, f)) { if (v === enNow.get(p) || recorded.includes('"objects.' + p + '"')) continue; // echo / recorded byte copy authored++; const c = last.get(p), enThen = at(c, 'en.objects.generated.ts').get(p); if (enThen !== enNow.get(p)) cands.push(p + ' @' + c.slice(0, 9)); } console.log(L, 'authored=' + authored, 'candidates=' + cands.length); for (const k of cands) console.log(' ' + k); } ``` Two widening checks ran beside it: - **Penultimate edit.** For each non-candidate, the full instrument also compared `en` at the leaf's previous edit. This catches a sweep that touched a leaf mechanically after `en` had moved. It flagged 12 / 8 / 12 leaves (ja-JP / es-ES / zh-CN). All of them were re-translated in the same commit that moved `en`, so none is stale. - **Retired-term scan.** The since-last-edit instrument cannot see a leaf that was already wrong at its last edit. For the two renames the candidates surfaced (ADR-0057 department to business unit, and v5.0 project to environment), every leaf that carries the locale's word for the retired term (`部門` / `部门` / `departamento` case-insensitive; `プロジェクト` / `项目` / `proyecto`) was compared with the `en` leaf at the same path. A leaf is flagged when `en` does not carry the English term there. ### Known-positive control `sys_two_factor.fields.backup_codes.help`, line 1095 of all four bundles. `en` has read "Backup recovery codes, encrypted at rest (a single opaque ciphertext, not readable JSON)" since `266654d82`. The three translations were last edited at `7bb92056e`, when `en` read "JSON-serialized backup recovery codes". The instrument flags it in **all three** locales, zh-CN included. The retired-term scan's positive is `sys_metadata.fields.environment_id.label`, which both instruments flag. ### Population and radius - **Covered:** the objects bundles of `@objectstack/platform-objects` for ja-JP, es-ES and zh-CN. There are 1529 leaves per locale. Echoes of the current `en` number 43 / 54 / 42, recorded byte copies 0 beyond those, and authored leaves **1486 / 1475 / 1487**. History covered: every first-parent commit since the bundles were created at `6bacbced2` (62 / 62 / 63 commits touching each locale file). - **Not covered:** a leaf that was wrong at its last edit for any reason other than the two renames above; the platform-objects `metadata-forms` bundles; the other eight packages' bundle sets. Raw candidate counts for those are in the acceptance notes. ### Counts per locale | | ja-JP | es-ES | zh-CN | |---|---|---|---| | authored leaves | 1486 | 1475 | 1487 | | candidates (en moved since last edit), before | 17 | 21 | 17 | | of which contradicting, before | 4 | 9 | 4 | | retired-term scan, wrong at authoring, before | 0 | 2 | 0 | | **re-translated here** | **4** | **11** | **4** | | candidates after (at `3fa342501`) | 13 | 12 | 13 | | contradicting after | 0 | 0 | 0 | | retired-term scan after | 0 | 0 | 0 | The after-candidate sets are exactly the before sets minus the re-translated leaves: 0 added, and none of the new values equals its `en` leaf. The 13 / 12 / 13 that remain are the list below. ### The judgment rule A leaf **contradicts** the current `en` when a reader who acts on it would believe something about the current field or object that `en` now says is false. Three cases: - `en` now denies what the leaf asserts; - the object was re-modelled, so the leaf describes a different thing; - the leaf names the record's entity by a term that a rename retired from it. A leaf does **not** contradict when `en` only added detail, narrowed or reworded without retracting what the leaf says, or changed punctuation. ### Re-translated (19) | path | locales | why it contradicted | |---|---|---| | `sys_two_factor.fields.backup_codes.help` | ja-JP, es-ES, zh-CN | Said JSON-serialized, where `en` says "a single opaque ciphertext, not readable JSON" (`266654d82`). | | `sys_notification.description` | ja-JP, es-ES, zh-CN | Said "per-user notification inbox entries". ADR-0030 re-modelled the object as one event row per `emit()`, carrying no recipient; the object header says it "was previously a per-user inbox". | | `sys_job_run.description` | ja-JP, es-ES, zh-CN | Said "audit trail". `ca19ee81f` changed the source to "history" because the object is job-run history and not the audit trail, which is `sys_audit_log` (the binding ruling that commit cites). | | `sys_metadata.fields.environment_id.label` | ja-JP, es-ES, zh-CN | Said "Project (deprecated)" for the `environment_id` column. The v5.0 rename project to environment has no aliases. | | `sys_business_unit.fields.manager_user_id.help`, `.effective_from.help`, `.effective_to.help`, `sys_business_unit_member.description`, `sys_business_unit_member.fields.is_primary.help` | es-ES | Named the business unit a *departamento*, where `en` says business unit (ADR-0057 D2; department is now one `kind` of business unit). `61ed5c7c9` renamed these in `en`, ja-JP and zh-CN and missed es-ES. | | `sys_business_unit.fields.manager_user_id.label`, `sys_business_unit.fields.id.label` | es-ES | Same rename: "Responsable del departamento" and "ID de departamento" against `en` "Business Unit Head" and "Business Unit ID". These were wrong when authored (`e16f2a830`), so the since-last-edit instrument cannot see them; the retired-term scan found them. | New values: ja-JP 保存時に暗号化されたバックアップ回復コード(単一の不透明な暗号文であり、読み取り可能な JSON ではありません) · 通知イベント — emit() 1 回につき 1 行(ADR-0030 レイヤー 2 の入口) · バックグラウンドジョブの実行履歴 · 環境(非推奨). zh-CN 备用恢复码,静态存储时加密(单个不透明密文,而非可读的 JSON) · 通知事件——每次 emit() 产生一行(ADR-0030 第 2 层入口) · 后台任务执行历史 · 环境(已废弃). es-ES uses *unidad de negocio*, the word the bundle already uses for the object and its `parent_business_unit_id` / `business_unit_id` labels; the rest is in the diff. ### Stale but not contradicting (listed, left as written) | path | locales | what `en` did | |---|---|---| | `sys_team.fields.organization_id.help` | all three | Added "Null in single-tenant; auto-stamped in multi-tenant." | | `sys_business_unit.fields.organization_id.help` | all three | Added the same sentence. | | `sys_business_unit.description` | all three | Reworded and extended (canonical BU tree, data-partition role, kind examples). "Hierarchical org tree node" is still true. | | `sys_business_unit_member.fields.is_primary.help` | ja-JP, zh-CN | Nothing to fix: the leaf already says business units. It was translated ahead of `en` at `61ed5c7c9`. | | `sys_oauth_application.fields.client_secret.help` | all three | Added the enforcement citation and "shown once". The leaf's "hashed at rest" is still true. | | `sys_notification.label` / `.pluralLabel` | all three | Narrowed "Notification" to "Notification Event". The less specific word is not false, and nothing else in these bundles carries it: `sys_inbox_message` is "Inbox Message", in its own package. | | `sys_notification.fields.actor_id.help` | all three | Reworded "the notification" to "the event". | | `sys_email.fields.headers_json.help` | all three | Added "Never returned on the generic data path…". The leaf does not claim that it is. | | `sys_email.fields.error.help` | all three | Widened from transport errors to transport or pre-delivery validation errors. The leaf is narrower but not contradicted. This is the closest call. | | `sys_metadata_history.description` | all three | Reframed as a durable event log of overlay changes. "Version history" is still true, and the source never retracted the audit wording: `59261af32` calls the row the audit row. | | `sys_metadata_history.fields.metadata.help` | all three | Added "(null for deletes)". | | `sys_metadata_history.fields.change_note.help` | all three | Added a trailing period. | `sys_notification.description`, the second example the card names, was measured stale and contradicting in all three locales. It is re-translated above. ## Dispatch hypotheses, measured - **H1 held.** The control is live at `f1e921ab8e` and at base `cd901d7a5`, at line 1095 of all four files, and zh-CN is in the set. - **H2 falsified.** Neither companion records an authored object leaf. `*.source-hashes.generated.ts` records only byte copies: 43 / 54 / 42 rows, each an echo of the current `en`. `*.source-hashes.ts` is the hand table for `apps` / `dashboards` / `pages` only: 130 rows each, 0 under `objects`. So "recorded hash differs" names nothing here, and the instrument had to be git history. - **H3 held: values only.** Measured that no companion changes. `collectFilledFromHashes` records a leaf only when its value equals the current source or a recorded digest. At `3fa342501`, `node scripts/check-i18n-bundles.mjs --write --filter=platform-objects` rewrote the bundle set byte-identical (`git status` empty). Control: with ja-JP `sys_job_run.description` set to the `en` string (via `scripts/ablation-replace.mjs`), `pnpm check:i18n` goes red with `platform-objects DRIFTED (1)`. Restored after: blob equals HEAD, and `git diff HEAD` is empty. - **H4 falsified for this set.** No echo-decision ledger row, and no test file under `packages/platform-objects`, names any of the 19 paths (`git grep` exit 1). The old values appear nowhere outside the bundles (exit 1). Both controls hit: a path pinned in the es-ES ledger, and `Cc` in the ja-JP ledger. No pin moved. ## Verification (all at `3fa342501`) - `node scripts/pm/dispatch-gates.mjs --commands` (no paths) derived 55 commands, and all 55 exit 0. `--ran` printed "55 derived famil(ies) accounted for — 55 run, 0 NOT-MEASURED". `pnpm check:dual-build-cjs-loads` first refused with exit 3 (nine unrelated packages had no `dist/`). Those were built and the gate re-ran: exit 0. - Named by the dispatch: `pnpm check:i18n` ("OK (9 package(s) — all bundles in sync…)"), `pnpm check:i18n-stale-fill` ("OK (10 bundle set(s) — no new stale fills, 0 baselined)"), `pnpm check:nul-bytes`, `pnpm check:published-files` and `pnpm check:cross-package-test-inputs` all exit 0. - `pnpm --filter @objectstack/platform-objects test`: 58 files, 942 tests passed. `pnpm --filter @objectstack/platform-objects typecheck`: exit 0. - Lint, narrowed to the three edited bundles: `eslint --no-inline-config --format json` read 3 files, 0 errors, 0 warnings. `ESLint#isPathIgnored` answers `false` for all three, read from the repo's own config. The config never enables type-aware linting (no `parserOptions.project`), so a change to string values in these files cannot move the verdict on any other file. The full `pnpm lint` run is left to CI. ## Acceptance notes - **Beyond the radius** (raw instrument counts at `cd901d7a5`; meaning judged only where noted): - platform-objects `metadata-forms`: 9 / 9 / 6; - plugin-approvals: 17 / 17 / 16. All of these are `en` options moving from the machine value to a title (`pending` to `Pending`), with no change of meaning; - plugin-audit: 3 / 3 / 3; - plugin-security: 7 / 5 / 7; - plugin-webhooks: 3 / 3 / 3; - plugin-sharing and the three services: 0. Read by hand and reported to the seat as one family finding: plugin-webhooks `sys_webhook.fields.definition_json.help` in all three locales says the JSON carries the full headers and auth config, where `en` says credentials are NOT stored there. plugin-audit `sys_activity.fields.environment_id.label` still says Project. The metadata-forms `permission` section still promises custom context variables, and the `agent` section still promises tools; `en` dropped both. - `bu-rename-consistency.test.ts` spells its es-ES term as the case-sensitive `/Departamento/`. That is why the two lowercase es-ES labels re-translated here (field labels, which the test's header says it asserts) passed it. This PR fixes the values. The test's blind spot remains, and a case-insensitive `/departamento/i` would close it. That edit is outside this card's file surface and is not made here. - The history walk needed full history. The shared object store was unshallowed (`git fetch --unshallow origin main`), which every worktree on this clone now sees. --- _Generated by [Claude Code](https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent d7631d5 commit f4ce10c

4 files changed

Lines changed: 46 additions & 19 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
'@objectstack/platform-objects': patch
3+
---
4+
5+
fix(platform-objects): the ja-JP, es-ES and zh-CN object help, descriptions and labels that contradicted their current English source are re-translated (#20539)
6+
7+
Clause-②: no
8+
9+
A translated object leaf that a translator wrote by hand is kept as written
10+
when its English source changes later, so some leaves went on saying what the
11+
old source said. On a ja-JP, es-ES or zh-CN console the `sys_two_factor` record
12+
page described `backup_codes` as JSON-serialized, where the English help says
13+
the codes are one opaque ciphertext and not readable JSON.
14+
15+
Nineteen leaves whose meaning contradicted the current English now match it:
16+
17+
- all three locales: `sys_two_factor.backup_codes` help (an opaque ciphertext,
18+
not JSON), the `sys_notification` description (one notification event per
19+
`emit()`, not a per-user inbox entry), the `sys_job_run` description (job run
20+
history, not an audit trail), and the `sys_metadata.environment_id` label
21+
(Environment, not Project);
22+
- es-ES only: seven `sys_business_unit` / `sys_business_unit_member` labels and
23+
help texts that still named the business unit a department.
24+
25+
Leaves whose English source only gained detail or was reworded, without
26+
retracting what the translation says, are unchanged. Values only: no key is
27+
added or removed, and no provenance table changes.

‎packages/platform-objects/src/apps/translations/es-ES.objects.generated.ts‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -897,27 +897,27 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
897897
help: "Ámbito del tenant."
898898
},
899899
manager_user_id: {
900-
label: "Responsable del departamento",
901-
help: "Usuario responsable de esta unidad organizativa (responsable o jefe de departamento)."
900+
label: "Responsable de la unidad de negocio",
901+
help: "Usuario responsable de esta unidad organizativa (responsable o jefe de la unidad de negocio)."
902902
},
903903
active: {
904904
label: "Activo",
905905
help: "Si es falso, los miembros no se expanden en las consultas del grafo."
906906
},
907907
effective_from: {
908908
label: "Vigente desde",
909-
help: "Momento en que este departamento entró en funcionamiento (sincronización HRIS)."
909+
help: "Momento en que esta unidad de negocio entró en funcionamiento (sincronización HRIS)."
910910
},
911911
effective_to: {
912912
label: "Vigente hasta",
913-
help: "Momento en que este departamento se retiró (sincronización HRIS)."
913+
help: "Momento en que esta unidad de negocio se retiró (sincronización HRIS)."
914914
},
915915
external_ref: {
916916
label: "Referencia externa",
917917
help: "ID en el HRIS ascendente (Workday / SAP HR / 北森)."
918918
},
919919
id: {
920-
label: "ID de departamento"
920+
label: "ID de unidad de negocio"
921921
},
922922
created_at: {
923923
label: "Creado el"
@@ -947,7 +947,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
947947
sys_business_unit_member: {
948948
label: "Miembro de unidad de negocio",
949949
pluralLabel: "Miembros de unidad de negocio",
950-
description: "Asignación de usuario a un departamento (compatible con organizaciones matriciales y con vigencia temporal).",
950+
description: "Asignación de usuario a una unidad de negocio (compatible con organizaciones matriciales y con vigencia temporal).",
951951
fields: {
952952
id: {
953953
label: "ID de miembro"
@@ -973,7 +973,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
973973
},
974974
is_primary: {
975975
label: "Asignación principal",
976-
help: "Cuando el usuario pertenece a varios departamentos, este marca el canónico para los informes."
976+
help: "Cuando el usuario pertenece a varias unidades de negocio, este campo marca la canónica para los informes."
977977
},
978978
effective_from: {
979979
label: "Vigente desde"
@@ -1092,7 +1092,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
10921092
},
10931093
backup_codes: {
10941094
label: "Códigos de respaldo",
1095-
help: "Códigos de recuperación de respaldo serializados en JSON."
1095+
help: "Códigos de recuperación de respaldo, cifrados en reposo (un único texto cifrado opaco, no JSON legible)."
10961096
},
10971097
verified: {
10981098
label: "Verificado",
@@ -2372,7 +2372,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
23722372
sys_notification: {
23732373
label: "Notificación",
23742374
pluralLabel: "Notificaciones",
2375-
description: "Entradas del buzón de notificaciones por usuario",
2375+
description: "Eventos de notificación: una fila por cada emit() (entrada de la capa 2 de ADR-0030)",
23762376
fields: {
23772377
id: {
23782378
label: "ID de notificación"
@@ -2710,7 +2710,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
27102710
sys_job_run: {
27112711
label: "Ejecución de tarea",
27122712
pluralLabel: "Ejecuciones de tarea",
2713-
description: "Registro de auditoría de ejecución de tareas en segundo plano",
2713+
description: "Historial de ejecución de tareas en segundo plano",
27142714
fields: {
27152715
id: {
27162716
label: "ID de ejecución"
@@ -2999,7 +2999,7 @@ export const esESObjects: NonNullable<TranslationData['objects']> = {
29992999
help: "Organización para el aislamiento multi-tenant."
30003000
},
30013001
environment_id: {
3002-
label: "Proyecto (obsoleto)",
3002+
label: "Entorno (obsoleto)",
30033003
help: "OBSOLETO. Use organization_id para el aislamiento del tenant."
30043004
},
30053005
version: {

‎packages/platform-objects/src/apps/translations/ja-JP.objects.generated.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ export const jaJPObjects: NonNullable<TranslationData['objects']> = {
10921092
},
10931093
backup_codes: {
10941094
label: "バックアップコード",
1095-
help: "JSON シリアライズされたバックアップ回復コード"
1095+
help: "保存時に暗号化されたバックアップ回復コード(単一の不透明な暗号文であり、読み取り可能な JSON ではありません)"
10961096
},
10971097
verified: {
10981098
label: "確認済み",
@@ -2372,7 +2372,7 @@ export const jaJPObjects: NonNullable<TranslationData['objects']> = {
23722372
sys_notification: {
23732373
label: "通知",
23742374
pluralLabel: "通知",
2375-
description: "ユーザーごとの通知受信ボックスエントリ",
2375+
description: "通知イベント — emit() 1 回につき 1 行(ADR-0030 レイヤー 2 の入口)",
23762376
fields: {
23772377
id: {
23782378
label: "通知 ID"
@@ -2710,7 +2710,7 @@ export const jaJPObjects: NonNullable<TranslationData['objects']> = {
27102710
sys_job_run: {
27112711
label: "ジョブ実行",
27122712
pluralLabel: "ジョブ実行",
2713-
description: "バックグラウンドジョブ実行の監査証跡",
2713+
description: "バックグラウンドジョブの実行履歴",
27142714
fields: {
27152715
id: {
27162716
label: "実行 ID"
@@ -2999,7 +2999,7 @@ export const jaJPObjects: NonNullable<TranslationData['objects']> = {
29992999
help: "マルチテナント分離のための組織。"
30003000
},
30013001
environment_id: {
3002-
label: "プロジェクト(非推奨)",
3002+
label: "環境(非推奨)",
30033003
help: "非推奨。テナント分離には organization_id を使用してください。"
30043004
},
30053005
version: {

‎packages/platform-objects/src/apps/translations/zh-CN.objects.generated.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ export const zhCNObjects: NonNullable<TranslationData['objects']> = {
10921092
},
10931093
backup_codes: {
10941094
label: "备用恢复码",
1095-
help: "JSON 序列化的备用恢复码"
1095+
help: "备用恢复码,静态存储时加密(单个不透明密文,而非可读的 JSON)"
10961096
},
10971097
verified: {
10981098
label: "已验证",
@@ -2372,7 +2372,7 @@ export const zhCNObjects: NonNullable<TranslationData['objects']> = {
23722372
sys_notification: {
23732373
label: "通知",
23742374
pluralLabel: "通知",
2375-
description: "按用户存储的通知收件箱条目",
2375+
description: "通知事件——每次 emit() 产生一行(ADR-0030 第 2 层入口)",
23762376
fields: {
23772377
id: {
23782378
label: "通知 ID"
@@ -2710,7 +2710,7 @@ export const zhCNObjects: NonNullable<TranslationData['objects']> = {
27102710
sys_job_run: {
27112711
label: "任务执行",
27122712
pluralLabel: "任务执行",
2713-
description: "后台任务执行审计记录",
2713+
description: "后台任务执行历史",
27142714
fields: {
27152715
id: {
27162716
label: "执行 ID"
@@ -2999,7 +2999,7 @@ export const zhCNObjects: NonNullable<TranslationData['objects']> = {
29992999
help: "用于多租户隔离的组织。"
30003000
},
30013001
environment_id: {
3002-
label: "项目(已废弃)",
3002+
label: "环境(已废弃)",
30033003
help: "已废弃。请使用 organization_id 进行租户隔离。"
30043004
},
30053005
version: {

0 commit comments

Comments
 (0)