Repository navigation
Commit fabd259
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgH3fGSa9E9qgZfcdFLtAhtm)_
domain:server#2 · os-bill · session_01Utp6CaWLG2RrgKub5oRNjC
## 维护者速读
- 改了什么:设置 → 存储 → 「测试连接」的结果提示按管理员的界面语言显示(成功、下载内容不一致、S3 缺存储桶或区域三种),覆盖平台全部
11 种语言;没给语言或语言不在平台表上时,仍是原来的英文。
- 为什么改:中文控制台点「测试连接」看到的是 `Storage round-trip succeeded
(adapter=local).`,管理员可能读不懂下一步。#30551 已让设置动作拿到调用者语言,本 PR 让存储这个按钮用上它。
- 风险与回滚:只动 service-storage 的 `storage/test`
处理器和一个新文案文件;`ok`、`severity`、探针上传下载删除、运维日志都不变;英文调用方的句子一字不变。回滚即还原本 PR。
- 先看:`packages/services/service-storage/src/storage-test-copy.ts`(文案表与
`storageTestCopyLocaleOf` 语言查找);其次 `storage-service-plugin.ts` 里
`storage/test` 的四处 `copy.` 调用。
- 两分钟验证:`pnpm --filter @objectstack/service-storage exec vitest run
--maxWorkers=2 src/storage-test-locale.test.ts`,预期 10 个全绿,第一个用例的消息是
`存储连接测试成功(适配器:local)。`
- 需要你做的:无,席位落地。
Refs #30335
Clause-②: no
Metadata-protocol: none
## What changes
The console prints the `storage/test` settings action's `message` as the
toast, bare. Since #30551 the settings action route hands each action
handler the caller's display language as the input's `locale`
(`Accept-Language`, else `?locale`; `settings-routes.ts`
`requestLocaleOf`). The storage handler now writes its answer in that
language.
- New `packages/services/service-storage/src/storage-test-copy.ts`: one
entry per language on the platform locale table (`PLATFORM_LOCALES`):
`en`, `zh-CN`, `zh-Hant`, `es-ES`, `ar`, `fr`, `pt-BR`, `ru`, `de`,
`ja-JP`, `ko`. The four codes this package's bundles already used keep
their keys. Four sentences each: success (still names the adapter),
probe read back not the one written, S3 settings missing a bucket or a
region, and a lead-in for an adapter's own error.
- `storage/test` reads `locale` from the handler input, the same source
as the mail test notice in #30551. The adapter's own error text (S3 SDK,
file system) stays verbatim: alone in English, as before; in another
language behind the lead-in (`存储连接测试失败:…`), so the reader knows the rest
is the adapter's untranslated report.
- `buildAdapterFromValues` throws a new `S3SettingsIncompleteError` with
the same English message as before, so the settings re-apply path and
its `warn` log line are byte-identical; only the `storage/test` answer
reads the type to localise the refusal.
- Unchanged: `ok`, `severity`, the adapter name, the probe and its
cleanup, every `ctx.logger` line, and every sentence an English or
locale-less caller gets.
**Where the strings live, and one deviation from the precedent.** The
precedent is #30376 (`mfa-required-enrollment-predicate.ts`): a settings
handler's prose sits in a module-level copy table beside its code, not
in the package's `translations/` bundles (those carry object metadata).
This PR follows it, with one difference: the lookup does not use
`@objectstack/core`'s `resolveLocale`. With both `zh-CN` and `zh-Hant`
in one table, that ladder's base-language and first-variant steps answer
`zh-TW` by key order, which is the trap the platform table's own reader
warns about (`packages/spec/src/system/platform-locales.ts`, the
`platformLocaleTagOf` note). So `storageTestCopyLocaleOf` reads the
caller's code through `platformLocaleTagOf` (aliases `zh-TW`, `pt`,
`en-US`; table tags `zh-Hans`, `ja`), then drops one subtag at a time
(RFC 4647 lookup: `fr-CA` → `fr`, `zh-Hant-TW` → `zh-Hant`), and falls
back to English. This is the gap #30538 names (`resolveBundleLocale` /
`resolveLocale` do not read `platformLocaleTagOf`); once #30538 lands
this module can go back to the shared resolver.
## Tests
New `packages/services/service-storage/src/storage-test-locale.test.ts`,
10 cases, all through the REAL handler the plugin registers, on a real
local adapter, with the input `locale` set or absent:
- zh-CN success sentence, `ok: true`, `severity: 'info'`; en-US success
is the old English sentence;
- no locale, `tr-TR` (not on the table) and `''` answer the old English
sentence;
- `zh` resolves to the zh-CN copy;
- zh-CN probe mismatch (`ok: false`, `severity: 'error'`), and the probe
object is still removed;
- zh-CN incomplete S3 settings; no locale keeps the English S3 refusal;
- zh-CN adapter error = lead-in + the exact English adapter text;
- the table carries all 11 languages, every key in every language,
placeholders verbatim, no non-English entry copied from English, and
every `PLATFORM_LOCALE_TAGS` tag finds its own entry;
- 24 code → entry mappings (aliases, table tags, shortened subtags,
unknown → English).
Existing pins in `storage-service-plugin.test.ts` and
`storage-service-plugin.probe-cleanup-store.test.ts` (English messages,
no locale) pass unchanged.
## Acceptance notes
- Measured before the change on the real plugin handler (base
`c23eafa8`): `locale: 'zh-CN'` and no locale both answered `Storage
round-trip succeeded (adapter=local).`; mismatch `Probe download did not
match upload.`; S3 `StorageServicePlugin: S3 adapter requires s3_bucket
and s3_region`.
- `Clause-②: no`: nothing outside this package's own tests matches the
English text (`git grep -n "round-trip succeeded\|did not match upload"`
hits only `service-storage`). The console prints the message and reads
`ok`.
- Arabic copy carries no bidi control characters; direction is the
console's `dir`.
- An end-to-end pin through `SettingsService` + routes was not added
here: service-storage has no service-settings dependency, and #30551
pins the route → handler `locale` hop.
## Verification
All on head `47c43908c` (merge of `main` at `bdbaf80c`, which carries
#30551).
<details><summary>Local runs</summary>
- `pnpm --filter @objectstack/service-storage test`: Test Files 73
passed (73), Tests 1353 passed (1353).
- `pnpm --filter @objectstack/service-storage typecheck`: exit 0
(`check:test-typecheck: OK`).
- `node scripts/check-i18n-bundles.mjs`: exit 0 (10 packages, all
bundles in sync).
- `node scripts/pm/dispatch-gates.mjs --commands`: 62 derived families,
all 62 exit 0; `--ran`: 62 derived, 62 run, 0 NOT-MEASURED.
- `eslint --no-inline-config` on the three changed source files: exit 0.
- Full dogfood under the verify lock (`pnpm --filter
'@objectstack/dogfood^...' build && pnpm --filter @objectstack/dogfood
test`): `VERDICT command-exit 0`, Test Files 420 passed, 3 skipped
(423); Tests 3496 passed, 36 skipped (3532).
</details>
<details><summary>Ablations (scripts/ablation-replace.mjs, each
restored, git diff HEAD empty after)</summary>
- A1 handler ignores the input `locale`: 5 failed, 5 passed (the five zh
cases).
- A2 fallback `en` → `zh-CN`: 4 failed (no-locale English, no-locale S3,
the lead-in case, the mapping pin).
- A3 S3 type check off: 1 failed (zh-CN incomplete S3).
- A4 drop the `ko` entry: 1 failed (all 11 languages pin).
- A5 no subtag shortening: 1 failed (mapping pin).
</details>
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01Utp6CaWLG2RrgKub5oRNjC
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent c5101a0 commit fabd259
4 files changed
Lines changed: 396 additions & 6 deletions
File tree
- .changeset
- packages/services/service-storage/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
| 90 | + | |
90 | 91 | | |
91 | 92 | | |
92 | 93 | | |
| |||
286 | 287 | | |
287 | 288 | | |
288 | 289 | | |
289 | | - | |
| 290 | + | |
290 | 291 | | |
291 | 292 | | |
292 | 293 | | |
| |||
814 | 815 | | |
815 | 816 | | |
816 | 817 | | |
817 | | - | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
818 | 823 | | |
819 | 824 | | |
820 | 825 | | |
| |||
851 | 856 | | |
852 | 857 | | |
853 | 858 | | |
854 | | - | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
855 | 863 | | |
856 | 864 | | |
857 | 865 | | |
| |||
900 | 908 | | |
901 | 909 | | |
902 | 910 | | |
903 | | - | |
| 911 | + | |
904 | 912 | | |
905 | 913 | | |
906 | 914 | | |
907 | 915 | | |
908 | 916 | | |
909 | 917 | | |
910 | | - | |
| 918 | + | |
911 | 919 | | |
912 | 920 | | |
913 | 921 | | |
914 | | - | |
| 922 | + | |
915 | 923 | | |
916 | 924 | | |
917 | 925 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
0 commit comments