GroupSetting.WeightedPolicies makes default policy selection pick the
allowed policy with the most remaining MaxTotalSize headroom that fits
the file (upstream #2178 item 2). Directory/user preferences still win;
uncapped and suspended policies are excluded from the weighing.
Generated with Devin
@ -224,6 +224,7 @@ Order = user-visible value first; each ships with backend + UI + tests.
- [x] Per-user blob relocation (upstream #2729/misc) — `RelocateEntityService` gains a third scope `src_user_id` (mutually exclusive with `entity_ids`/`src_policy_id`); `NewRelocateUserTask` selects entities by `created_by` with the same cursor-resumable transfer path; admin user editor gains a "Relocate files" button opening the relocate dialog prefilled with the user scope; en+zh locales
- [x] Tencent Captcha (upstream #2178) — `captcha_type=tcaptcha` now performs real verification: `pkg/tcaptcha` calls Tencent Cloud `DescribeCaptchaResult` with full TC3-HMAC-SHA256 request signing (CaptchaAppId/AppSecretKey + SecretId/SecretKey, CaptchaType 9, client IP propagated); login/register/forgot-password flows emit `{ticket, randstr}` from the TCaptcha.js popup widget via a new `TCaptcha` verify-button component; admin Captcha section gains the provider option + four credential fields; en+zh locales
- [x] Localized admin strings (#25/#2691) — `setting.Provider.Localized` resolves any `<key>_i18n` JSON map by language tag (exact → bare primary subtag → wildcard `*` → base value); `SiteBasicLocalized` covers site name/title/description; consumed by site config, announcement endpoint, share-preview OG tags, index.html placeholders, WOPI breadcrumb, and email templates (recipient language); SKU gains `name_i18n`/`des_i18n` columns resolved per buyer language in the shop; admin gets a reusable `LocalizedFields` accordion (per-language inputs) wired into site name/description/announcement and SKU name/description; en+zh locales
- [x] Weighted policy selection (upstream #2178 item 2) — `GroupSetting.WeightedPolicies` spreads uploads across the group's allowed policies by free capacity: `pickByFreeCapacity` picks the member with the most remaining `MaxTotalSize` headroom that fits the file (uncapped/suspended members not weighed); explicit directory/user preferences still win; size-aware `getPreferredPolicyForSize` wired into both upload paths; admin group editor gains a switch, en+zh locales
"switchablePoliciesDes":"Policies members of this group can freely switch to. The default policy above is always available.",
"weightedPolicies":"Weighted policy selection",
"weightedPoliciesDes":"When enabled, uploads without an explicit policy preference are routed to the allowed policy with the most free capacity that fits the file. Only policies with a total capacity limit are weighed.",
"sharePublicList":"Public share directory",
"sharePublicListDes":"When enabled, users can opt their share links into the public directory (Discover page). Password-protected shares cannot be listed."