From ab613d59fa2fd434f543e0608d48874479d9fac4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6=20=28skjnldsv=29?= Date: Wed, 20 May 2026 09:43:41 +0200 Subject: [PATCH 1/4] docs(design): add UX writing guide for user-facing strings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new writing.rst page to developer_manual/design/ covering tone, message brevity, the "successfully" anti-pattern, button label conventions, and variable/placeholder gotchas for translators. Linked from design/index.rst toctree. Relates to #13884 Signed-off-by: John Molakvoæ (skjnldsv) --- developer_manual/design/index.rst | 1 + developer_manual/design/writing.rst | 117 ++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 developer_manual/design/writing.rst diff --git a/developer_manual/design/index.rst b/developer_manual/design/index.rst index b4ed4cb7e00..6b86074652e 100644 --- a/developer_manual/design/index.rst +++ b/developer_manual/design/index.rst @@ -6,6 +6,7 @@ Interface & interaction design :maxdepth: 2 introduction + writing foundations layout layoutcomponents diff --git a/developer_manual/design/writing.rst b/developer_manual/design/writing.rst new file mode 100644 index 00000000000..c3eb01655cc --- /dev/null +++ b/developer_manual/design/writing.rst @@ -0,0 +1,117 @@ +.. _ux-writing: + +============= +Writing guide +============= + +Consistent, concise wording makes Nextcloud easier to use and easier to translate. +Follow these rules when writing any user-facing string: notifications, dialog messages, button labels, error text, tooltips. + +General rules +------------- + +**Keep messages short.** One idea per sentence. Cut every word that does not add meaning. + +**Use sentence case.** Capitalize only the first word and proper nouns. + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - Avoid + - Prefer + * - Settings Saved Successfully + - Settings saved + * - An Error Has Occurred While Loading The File + - Could not load the file + * - Your changes have been successfully applied to the system + - Changes saved + +**Drop "successfully".** If an action completed, the result speaks for itself. +State what happened, not that it happened without error. + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - Avoid + - Prefer + * - Settings saved successfully + - Settings saved + * - User created successfully + - User created + * - File uploaded successfully + - File uploaded + +**Be specific in error messages.** Tell users what went wrong and, where possible, what to do next. + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - Avoid + - Prefer + * - An error occurred + - Could not save settings. Check your connection and try again. + * - Invalid input + - Password must be at least 8 characters + +**Avoid technical jargon** unless the audience is explicitly technical (e.g. a developer-facing admin panel). +Use plain language for anything end users see. + +Tone +---- + +- **Friendly, not chatty.** Write like a knowledgeable colleague, not a marketing brochure. +- **Direct, not bossy.** Prefer statements over commands in status messages. +- **Neutral, not emotional.** Avoid exclamation marks in status or error text. + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - Avoid + - Prefer + * - Great! Your profile has been updated! + - Profile updated + * - Oops! Something went wrong! + - Could not complete the request + +Button and action labels +------------------------ + +Use **verb + noun** for buttons that trigger an action. The noun can be omitted when context makes it obvious. + +.. list-table:: + :header-rows: 1 + :widths: 50 50 + + * - Avoid + - Prefer + * - OK + - Save settings + * - Submit + - Create account + * - Yes + - Delete file + +For destructive actions use the specific verb so users know exactly what will happen: **Delete**, **Remove**, **Revoke** — not **Confirm** or **OK**. + +Placeholders and variables +-------------------------- + +When a string contains a variable (file name, user name, count), keep the surrounding text short and natural. +Make sure the string still makes sense in all languages — word order differs across languages, so avoid splitting a sentence across two separate strings. + +.. code-block:: php + + // Good — full sentence in one string, variable embedded + $l->t('Shared with %s', [$userName]); + + // Avoid — concatenation breaks translation + $l->t('Shared with ') . $userName; + +Translatable strings +-------------------- + +For implementation details on marking strings as translatable in PHP, JavaScript, and Vue, see :doc:`../basics/translations`. From 993c49a787b344c2c5e8596d1f06303da5afb714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Molakvo=C3=A6=20=28skjnldsv=29?= Date: Wed, 20 May 2026 10:06:40 +0200 Subject: [PATCH 2/4] docs(design): add translator comments section to UX writing guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explains when and how to write TRANSLATORS comments in PHP, JS/TS, Vue templates, and Vue script blocks, with examples from the server codebase. Signed-off-by: John Molakvoæ (skjnldsv) --- developer_manual/design/writing.rst | 49 +++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/developer_manual/design/writing.rst b/developer_manual/design/writing.rst index c3eb01655cc..3f6c55c2293 100644 --- a/developer_manual/design/writing.rst +++ b/developer_manual/design/writing.rst @@ -111,6 +111,55 @@ Make sure the string still makes sense in all languages — word order differs a // Avoid — concatenation breaks translation $l->t('Shared with ') . $userName; +Translator comments +------------------- + +When a string is ambiguous or contains placeholders, add a ``TRANSLATORS`` comment on the line immediately before the translatable string. +The comment is extracted by the translation tooling and shown to translators in Transifex. + +**When to add one:** + +- The string is ambiguous out of context (e.g. a single word with multiple meanings). +- The string contains a placeholder — explain what the placeholder will be replaced with and give an example value where helpful. +- The string describes a UI element or workflow that is not obvious from the text alone. + +**PHP** — place the comment on the line before the ``->t()`` call: + +.. code-block:: php + + // TRANSLATORS The placeholder refers to the software product name, e.g. "Add to your Nextcloud" + $l->t('Add to your %s', [$productName]); + +**JavaScript / TypeScript** — same rule, line before the ``t()`` call: + +.. code-block:: javascript + + // TRANSLATORS: This is the number of hidden files or folders + const hiddenSummary = n('files', '%n hidden', '%n hidden', hidden) + + // TRANSLATORS: {relativeDueDate} will be replaced with a relative time, e.g. "2 hours ago" or "in 3 days" + t('files_reminders', 'We will remind you of this file {relativeDueDate}', { relativeDueDate }) + +**Vue template** — use an HTML comment on the line above the element: + +.. code-block:: html + + + {{ t('theming', 'Plain background') }} + +In the ``