fix(l10n): stop double-escaping the instance name in settings text - #64369
Conversation
t() HTML-escapes placeholder values unless told otherwise. That is right
when the result is handed to v-html, and wrong for these six strings,
because every one of them is rendered as text - {{ }} interpolation,
NcSettingsSection's description, NcInputField's helperText, or an
aria-label. Vue escapes the string again on render, so the entity is what
the user actually reads: an instance called "Foo's Speicher" shows up as
"Foo&nextcloud#39;s Speicher" in the OAuth 2.0 clients section and in four places
in the LDAP wizard.
Turning escaping off for these call sites is safe on two counts. The
results are text bindings, so Vue still escapes them exactly once on
render, and ThemingDefaults::getName() already runs the configured
instance name through strip_tags() before it reaches the theming
capability, so the value cannot carry markup to begin with.
This matches how the rest of the codebase handles text-rendered
placeholders, including the neighbouring user count in UsersTab.vue.
Assisted-by: ClaudeCode:claude-opus-5
Signed-off-by: Tor Valstrom <51440386+torvalstrom@users.noreply.github.com>
fda7b80 to
3246806
Compare
|
Hello there, We hope that the review process is going smooth and is helpful for you. We want to ensure your pull request is reviewed to your satisfaction. If you have a moment, our community management team would very much appreciate your feedback on your experience with this PR review process. Your feedback is valuable to us as we continuously strive to improve our community developer experience. Please take a moment to complete our short survey by clicking on the following link: https://cloud.nextcloud.com/apps/forms/s/i9Ago4EQRZ7TWxjfmeEpPkf6 Thank you for contributing to Nextcloud and we hope to hear from you soon! (If you believe you should not receive this message, you can add yourself to the blocklist.) |
|
/backport to stable35 |
|
/backport to stable34 |
Thanks for the fixes and proactive diligence, @torvalstrom. It's very much appreciated! |
Fixes #39956.
t()HTML-escapes placeholder values unless told otherwise. That is correct when the result is handed tov-html, and wrong for these six strings, because every one of them is rendered as text. Vue escapes the string again on render, so the entity is what the user actually reads.Reproduced with the real library (
@nextcloud/l10n3.4.1), which is all it takes:The first line is what 34.0.2 ships, which matches the screenshot in the issue exactly.
The same bug in five more places
While confirming the OAuth 2.0 one I grepped for other consumers of
getCapabilities().theming.name. Four of the five other call sites have the identical problem, so they are fixed here too rather than left to be re-reported:apps/oauth2/src/views/AdminSettings.vueNcSettingsSection'sdescription→{{ description }}apps/user_ldap/.../UsersTab.vueNcInputField'shelperText→{{ helperText }}apps/user_ldap/.../GroupsTab.vue(×2){{ }}andhelperTextapps/user_ldap/.../LoginTab.vue{{ }}apps/user_ldap/.../AdvancedTab.vuearia-label(The sixth,
twofactor_backupcodes, uses the name to build a filename and never passes it throught(), so it is untouched.)Why disabling escaping is safe here
Two independent reasons, not one:
aria-labelis an attribute and is never parsed as HTML either.ThemingDefaults::getName()already runs the configured instance name throughstrip_tags()before it reaches the theming capability.This also matches the existing idiom in the codebase — including
UsersTab.vueline 55, where the user count in the very same component is already translated with{ escape: false }.Testing
npx eslintclean on all five changed files.@nextcloud/l10n3.4.1 directly, withFoo's Speicher,<b>bold</b>and anonerrorpayload, to confirm both the fix and that nothing here can reach an HTML sink.npm run buildand the Playwright suite.AI (if applicable)
Written with Claude Code (
claude-opus-5); every change was reviewed, built and tested by me before opening the PR, and the measurements quoted above are real command output rather than model claims. Commits carryAssisted-by: ClaudeCode:claude-opus-5.