Normalized magic link signin response for all inputs#26752
Normalized magic link signin response for all inputs#26752kevinansfield merged 1 commit intomainfrom
Conversation
WalkthroughAPI magic-link and OTC flows were changed to avoid revealing whether an email belongs to a member: requests for non-existent emails now return success (201) and, when OTC is requested, a synthetic otc_ref (UUID) is returned instead of throwing a member-not-found error. Verification error code for missing tokenValue was renamed from INVALID_OTC_REF to INVALID_OTC. Portal UI messages were updated to prefixed "If you have an account, ..." variants and the explicit "No member exists with this e-mail address. Please sign up first." message was removed from special handling. Tests and i18n files were updated accordingly. Possibly related PRs
Suggested labelsaffects:i18n Suggested reviewersaileen 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ast-grep (0.41.0)ghost/core/test/unit/server/services/members/members-api/controllers/router-controller.test.jsComment |
There was a problem hiding this comment.
Note
Due to the large number of review comments, Critical severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/portal/test/data-attributes.test.js (1)
1000-1019:⚠️ Potential issue | 🟡 MinorClarify test name to reflect actual error being tested.
The test is named "handles error when email does not exist," but per the API changes, the signin endpoint now returns status 201 regardless of member existence. The e2e tests confirm that non-existent emails receive a 201 response. This test mocks a 400 error with the message "Failed to send magic link email," which represents a different failure scenario—not a non-existent email check.
Rename the test to reflect the actual error condition it covers (e.g., "handles server error response from API" or "handles failed magic link send"), or remove it if this error path is no longer relevant.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/portal/test/data-attributes.test.js` around lines 1000 - 1019, The test name "handles error when email does not exist" is misleading because the mocked failure is a 400 server error for sending the magic link; update the test title to reflect the actual condition (e.g., "handles server error response from API" or "handles failed magic link send") and keep the existing assertions, or remove the test if that error path is no longer relevant; locate the test using the test block containing getMockData(), formSubmitHandler, window.fetch mocks and errorEl assertions and rename or delete that test accordingly.
🟠 Major comments (27)
ghost/i18n/locales/fa/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorRestore the account-conditional wording in this translation.
The Persian value currently says the login link was sent, which drops the new “If you have an account” caveat from the source string and changes the meaning of the privacy-preserving copy introduced by this PR. Please keep that conditional phrasing in the translation as well.
Based on learnings, Ghost translation reviews should stay scoped to PR-related strings, and translators should only change translated values without altering the intended source meaning.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/fa/portal.json` at line 111, The translated Persian value for the source string "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." incorrectly reads as a definitive past action (drops the conditional "If you have an account"); update the translation value in portal.json to restore the conditional phrasing (start with "اگر حساب کاربری دارید" or equivalent), and keep the rest of the message including the "3 minutes" and "check your spam folder" parts so the translation preserves the original privacy-preserving meaning and timing details.ghost/i18n/locales/lv/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorKeep the new account-conditional wording in the Latvian copy.
Line 111 drops “If you have an account” and turns this back into a definite “the login link has been sent” message. That weakens the PR’s account-enumeration mitigation for Latvian users. Please keep the conditional wording in the translation as well.
As per coding guidelines, translators should only modify the translated values and must not change the keys or placeholder styles, and this change is directly related to the PR’s primary objective.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/lv/portal.json` at line 111, The translated value for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." must retain the conditional prefix, so restore the Latvian equivalent of "If you have an account" at the start of the translation (do not change the key or any placeholder styles); update the current translation "Pieteikšanās saite ir nosūtīta uz jūsu iesūtni. Ja tas nepienāk 3 minūšu laikā, noteikti pārbaudiet surogātpasta mapi." to include the conditional phrase (e.g., prepend the Latvian for "If you have an account,"), preserving punctuation and sentence structure.ghost/i18n/locales/sv/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorPreserve the new account-conditional wording in Swedish.
Both translations drop the new
If you have an accountguard and now state that the link/email was definitely sent. That makes the Swedish UI inaccurate for unknown addresses and weakens the privacy-preserving behavior this PR is introducing.Suggested wording
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "En inloggningslänk har skickats till din inkorg. Om den inte anländer inom 3 minuter, kontrollera din skräppostmapp.", - "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Ett e-postmeddelande har skickats till {submittedEmailOrInbox}. Klicka på länken i meddelandet eller ange din kod nedan.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Om du har ett konto har en inloggningslänk skickats till din inkorg. Om den inte kommer inom 3 minuter, kontrollera din skräppostmapp.", + "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Om du har ett konto har ett e-postmeddelande skickats till {submittedEmailOrInbox}. Klicka på länken i meddelandet eller ange din kod nedan.",Based on learnings: In Ghost Portal, avoid suggesting translation-string changes unless directly related to the PR's primary objective.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/sv/portal.json` around lines 111 - 112, Update the two Swedish translations to preserve the account-conditional prefix "If you have an account" so the UI remains privacy-preserving: locate the entries whose English keys are "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." and change their Swedish values to begin with "Om du har ett konto," followed by the existing translations (e.g., "Om du har ett konto, en inloggningslänk har skickats till din inkorg..." and "Om du har ett konto, ett e-postmeddelande har skickats till {submittedEmailOrInbox}...") so the guard is preserved exactly as in the English source.ghost/i18n/locales/th/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorRestore the account-conditional wording in the Thai translation.
The new source string adds “If you have an account” to avoid claiming that a login link was definitely sent. The Thai value drops that condition and still says the link was sent, which changes the meaning of this PR’s copy update for Thai users. Based on learnings, this suggestion is directly tied to the PR’s primary objective, and in locale files only translated values should change.
💬 Suggested translation update
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "ลิงค์เข้าสู่ระบบถูกส่งไปยังกล่องจดหมายของคุณแล้ว หากไม่ได้รับภายใน 3 นาที โปรดตรวจสอบโฟลเดอร์สแปมของคุณ", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "หากคุณมีบัญชีอยู่แล้ว ลิงก์เข้าสู่ระบบจะถูกส่งไปยังกล่องจดหมายของคุณ หากไม่ได้รับภายใน 3 นาที โปรดตรวจสอบโฟลเดอร์สแปมของคุณ",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/th/portal.json` at line 111, The Thai translation for the source key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." drops the conditional "If you have an account" and thus changes meaning; update the Thai value to restore that condition (prepend or include "หากคุณมีบัญชี" / equivalent) while keeping the rest of the message about the 3-minute wait and spam folder, and only change the translated value in the key for portal.json.ghost/i18n/locales/is/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorPreserve the new account-conditional wording in the Icelandic translation.
Line 111 drops the new “If you have an account” condition and turns the message back into an unconditional “a login link has been sent”. That weakens the privacy-focused behavior this PR is introducing for Icelandic users.
💬 Suggested translation update
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Innskráningarhlekkur hefur verið sendur á netfangið þitt. Ef hann er ekki kominn innan 3ja mínútna skaltu athuga spam-möppuna.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ef þú ert með aðgang hefur innskráningarhlekkur verið sendur á netfangið þitt. Ef hann er ekki kominn innan 3ja mínútna skaltu athuga spam-möppuna.",Based on learnings, avoid suggesting translation-string changes unless directly related to the PR's primary objective; this one is, because the PR is normalizing sign-in responses to avoid revealing account existence.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/is/portal.json` at line 111, Update the Icelandic translation for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." so it preserves the conditional "If you have an account" wording (i.e., does not assert that a link was sent unconditionally); locate the entry currently mapped to "Innskráningarhlekkur hefur verið sendur á netfangið þitt. Ef hann er ekki kominn innan 3ja mínútna skaltu athuga spam-möppuna." and modify it to an Icelandic string that explicitly starts with the equivalent of "If you have an account" (for example using "Ef þú átt aðgang/ef þú átt reikning" phrasing) while keeping the rest of the message about checking the inbox and spam folder intact.ghost/i18n/locales/el/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorRestore the account-conditional wording in the Greek translation.
The new source string intentionally says “If you have an account…” so the UI doesn’t claim an email was sent for unknown addresses. The Greek value dropped that qualifier, so Line 111 still tells users a login link was sent unconditionally and no longer matches the new signin behavior.
Suggested translation update
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ένας σύνδεσμος σύνδεσης έχει σταλεί στα εισερχόμενά σας. Αν δεν φτάσει σε 3 λεπτά, ελέγξτε τον φάκελο ανεπιθύμητης αλληλογραφίας σας.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Αν έχετε λογαριασμό, ένας σύνδεσμος σύνδεσης έχει σταλεί στα εισερχόμενά σας. Αν δεν φτάσει σε 3 λεπτά, ελέγξτε τον φάκελο ανεπιθύμητης αλληλογραφίας σας.",Based on learnings, translation-string changes in
apps/portalshould only be suggested when they are directly tied to the PR objective, which this wording change is.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/el/portal.json` at line 111, Restore the account-conditional phrasing in the Greek translation for the source string "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." — update the value in portal.json (the translation for that exact English key) to include the equivalent of "If you have an account" (e.g., "Εάν έχετε λογαριασμό, ένας σύνδεσμος σύνδεσης έχει σταλεί στα εισερχόμενά σας. Αν δεν φτάσει σε 3 λεπτά, ελέγξτε τον φάκελο ανεπιθύμητης αλληλογραφίας σας.") so the Greek string matches the source's conditional behavior.ghost/i18n/locales/ro/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorRomanian translation missing the "If you have an account" conditional prefix.
The key includes "If you have an account, ..." but the Romanian translation omits this important prefix. The translation currently reads:
"Un link de autentificare a fost trimis în inbox-ul tău..."
This should include the conditional to align with the PR objective of preventing information disclosure about member existence. Consider updating to:
"Dacă ai un cont, un link de autentificare a fost trimis în inbox-ul tău..."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/ro/portal.json` at line 111, Update the Romanian translation for the portal message key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." so it preserves the conditional prefix; replace the current value ("Un link de autentificare a fost trimis în inbox-ul tău. Dacă nu ajunge în 3 minute, asigură-te că verifici folderul de spam.") with the corrected string "Dacă ai un cont, un link de autentificare a fost trimis în inbox-ul tău. Dacă nu ajunge în 3 minute, asigură-te că verifici folderul de spam." to avoid leaking membership information.ghost/i18n/locales/sr-Cyrl/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorTranslations omit the account-conditional phrasing.
The new English keys include "If you have an account, ..." to avoid disclosing member existence, but the Serbian translations omit this conditional phrase entirely:
- Line 111: Translation says "Линк за пријаву је послат..." (A login link has been sent...) instead of "Ако имате налог, линк за пријаву је послат..."
- Line 112: Translation says "Email је послат..." (An email has been sent...) instead of "Ако имате налог, email је послат..."
This defeats the security purpose of this PR since Serbian users will see messaging that implies an account definitely exists.
Proposed fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Линк за пријаву је послат у Ваш inbox. Ако не стигне у року од 3 минута, проверите фасциклу за нежељену пошту.", - "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Email је послат на {submittedEmailOrInbox}. Кликните на линк унутар њега или унесите код испод.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ако имате налог, линк за пријаву је послат у Ваш inbox. Ако не стигне у року од 3 минута, проверите фасциклу за нежељену пошту.", + "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Ако имате налог, email је послат на {submittedEmailOrInbox}. Кликните на линк унутар њега или унесите код испод.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/sr-Cyrl/portal.json` around lines 111 - 112, The Serbian translations for the portal messages must preserve the account-conditional phrasing present in the English keys; update the values for the keys "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." so they begin with the equivalent conditional phrase (e.g., "Ако имате налог, ...") before the existing translated text, keeping placeholders like {submittedEmailOrInbox} intact and matching the original sentence meaning and punctuation.ghost/i18n/locales/nl/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorRestore the conditional wording in the Dutch success message.
Line 111 currently says the email was sent unconditionally (
Je hebt ... ontvangen), but this flow now returns the same success response even when no member exists and no email is sent. The Dutch copy needs to keep the “If you have an account, …” qualifier so it matches the normalized behavior.Based on learnings, Portal translation feedback should stay scoped to the PR’s primary objective, and this wording is directly part of that objective.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/nl/portal.json` at line 111, Restore the conditional phrasing for the Dutch translation of the portal success message: locate the JSON entry whose key is "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and change the Dutch value so it preserves the "If you have an account, ..." qualifier (e.g. start with "Als je een account hebt, ...") rather than stating the email was sent unconditionally; update the value in portal.json accordingly.ghost/i18n/locales/sw/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorPreserve the new conditional wording in the Swahili copy.
This translation drops “If you have an account,” and reverts to the old unconditional message. That makes the Swahili flow say an email was sent even when no member exists, which is the behavior this PR is trying to avoid.
Suggested fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Kiungo cha kuingia kimetumwa kwenye inbox yako. Kama hakifiki ndani ya dakika 3, hakikisha unakagua folda yako ya spam.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ikiwa una akaunti, kiungo cha kuingia kimetumwa kwenye kikasha chako. Kama hakifiki ndani ya dakika 3, hakikisha unakagua folda yako ya spam.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/sw/portal.json` at line 111, The Swahili translation for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." removed the conditional "If you have an account,"; restore that conditional by prepending an equivalent Swahili phrase (e.g. "Kama una akaunti, ") to the existing translation so the string reads something like "Kama una akaunti, kiungo cha kuingia kimetumwa kwenye inbox yako. Kama hakifiki ndani ya dakika 3, hakikisha unakagua folda yako ya spam." so the message remains conditional when no member exists.ghost/i18n/locales/ca/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorRestore the account-conditional wording here.
This translation drops
If you have an account,, so Catalan users are told an email was definitely sent even when the backend intentionally sends nothing for unknown addresses. That changes the behavior this PR is normalizing.Suggested fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "S'ha enviat un enllaç d'inici de sessió al teu correu electrònic. Si no t'arriba en 3 minuts, revisa la teva carpeta de correu brossa.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Si tens un compte, s'ha enviat un enllaç d'inici de sessió al teu correu electrònic. Si no t'arriba en 3 minuts, revisa la teva carpeta de correu brossa.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/ca/portal.json` at line 111, Restore the original account-conditional prefix in the Catalan translation for the string keyed by "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." — prepend "Si tens un compte," (or equivalent Catalan phrasing) so the translated value mirrors the English conditional wording and does not imply an email was definitely sent for unknown addresses.ghost/i18n/locales/tr/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorTurkish translations are missing the "If you have an account" conditional prefix.
Both translations omit the critical "If you have an account" / "Hesabınız varsa" prefix that is present in the English keys. This conditional framing is the core security improvement of this PR—without it, Turkish users will still see messaging that implies an account definitely exists, defeating the email enumeration protection.
Proposed fix to add the conditional prefix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Gelen kutuna bir giriş bağlantısı gönderildi. Eğer 3 dakika içinde ulaşmazsa spam klasörünü kontrol ettiğinden emin ol.", - "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "{submittedEmailOrInbox} adresinize bir ileti gönderildi. İleti içerisindeki bağlantıya tıklayın veya kodu aşağıya girin.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Hesabınız varsa, gelen kutunuza bir giriş bağlantısı gönderildi. Eğer 3 dakika içinde ulaşmazsa spam klasörünü kontrol ettiğinizden emin olun.", + "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Hesabınız varsa, {submittedEmailOrInbox} adresinize bir ileti gönderildi. İleti içerisindeki bağlantıya tıklayın veya kodu aşağıya girin.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/tr/portal.json` around lines 111 - 112, The Turkish translations for the keys starting with "If you have an account" are missing the conditional prefix; update the two values that currently start with "Gelen kutuna..." and "{submittedEmailOrInbox} adresinize..." to prepend the conditional phrase "Hesabınız varsa, " so they read "Hesabınız varsa, Gelen kutuna..." and "Hesabınız varsa, {submittedEmailOrInbox} adresinize..." respectively, preserving the existing punctuation and the {submittedEmailOrInbox} placeholder exactly as written.ghost/i18n/locales/cs/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorRestore the account-conditional wording.
The Czech value drops the leading “If you have an account,” so this locale still claims the login link was sent unconditionally. Please keep that qualifier to match the new non-enumerating signin flow.
💬 Suggested change
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Odkaz pro přihlášení byl odeslán do vaší e-mailové schránky. Pokud nepřijde do 3 minut, zkontrolujte prosím svou složku nevyžádaných zpráv (spam).", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Pokud máte účet, odkaz pro přihlášení byl odeslán do vaší e-mailové schránky. Pokud nepřijde do 3 minut, zkontrolujte prosím svou složku nevyžádaných zpráv (spam).",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/cs/portal.json` at line 111, Restore the conditional clause in the Czech translation for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." by prepending the equivalent of "If you have an account," to the current value so it reads: "If you have an account, a login link has been sent..." in Czech (i.e., add the missing leading conditional phrase to the string in portal.json to match the English source and retain the existing rest of the sentence and punctuation).ghost/i18n/locales/sr/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorRestore the account-conditional wording in these Serbian translations.
Both values drop the new
If you have an account, ...qualifier, so this locale now tells nonexistent members that a link/email was sent even when nothing is sent. That breaks the normalization this PR is introducing.Suggested fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Link za prijavu je poslat u Vaš inbox. Ako ne stigne u roku od 3 minuta, proverite fasciklu za neželjenu poštu.", - "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Email je poslat na {submittedEmailOrInbox}. Kliknite na link unutar njega ili unesite kod ispod.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ako imate nalog, link za prijavu je poslat u Vaš inbox. Ako ne stigne u roku od 3 minuta, proverite fasciklu za neželjenu poštu.", + "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Ako imate nalog, email je poslat na {submittedEmailOrInbox}. Kliknite na link unutar njega ili unesite kod ispod.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/sr/portal.json` around lines 111 - 112, Restore the account-conditional phrasing in the Serbian translations for the two keys matching the English source strings "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." — update their Serbian values to explicitly start with an equivalent of "Ako imate nalog," (or the correct formal Serbian casing) so the translated messages preserve the conditional "If you have an account" qualifier rather than asserting that an email/link was sent to everyone.ghost/i18n/locales/bs/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorKeep the account-conditional wording in the Bosnian copy.
Line 111 drops the new “If you have an account” qualifier, so this locale still tells users the login email was sent unconditionally. That contradicts the normalized signin behavior this PR is introducing.
✏️ Suggested adjustment
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Link za prijavu poslan je na tvoju Email adresu. Ako ne stigne u roku od 3 minute, provjeri spam folder.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ako imaš račun, link za prijavu poslan je na tvoju Email adresu. Ako ne stigne u roku od 3 minute, provjeri spam folder.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/bs/portal.json` at line 111, The Bosnian translation for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." was changed to an unconditional statement; update the value to retain the account-conditional phrasing (i.e. include the equivalent of "If you have an account," at the start) so it matches the normalized signin behavior and the source key; edit the string value for that same key (the long English sentence) to a Bosnian sentence that begins with the conditional phrase while keeping the rest of the message about the login link and checking spam.ghost/i18n/locales/ms/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorThe Malay copy needs the new account condition too.
Line 111 now tells the user the login link was sent unconditionally, which no longer matches the source semantics when the address is unknown. Please preserve the conditional wording in this locale.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/ms/portal.json` at line 111, The Malay translation for the source string "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." currently drops the conditional "If you have an account" and reads as unconditional; update the value in portal.json so it preserves the conditional wording (i.e., include a Malay equivalent of "If you have an account," at the start) so the translated key matches the source semantics exactly.ghost/i18n/locales/eo/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorThe Esperanto translation needs to keep the new conditional framing.
Line 111 says the login link was sent outright, which no longer matches the source behavior for unknown emails. Please keep the localized wording conditional as well.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/eo/portal.json` at line 111, The translated string for the English source key starting "If you have an account, a login link has been sent to your inbox..." must preserve the conditional phrasing; replace the current Esperanto "Sendis ensalutan ligilon al via enirkesto..." with a conditional formulation such as "Se vi havas konton, estis sendita ligilo por ensaluto al via enirkesto. Se ĝi ne alvenas post 3 minutoj, nepre kontrolu vian trudmesaĝdosieron." so the message matches the source behavior for unknown emails and keeps the same follow-up clause.ghost/i18n/locales/af/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorThe Afrikaans translation should remain conditional.
Line 111 currently says the sign-in link was sent as a fact, but the new source copy only says that conditionally. Please keep that distinction here so this locale matches the PR’s behavior.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/af/portal.json` at line 111, The Afrikaans translation for the source string "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." is currently rendered as a factual statement; update the locale value so it remains conditional and matches the source copy (i.e., preserve the "If you have an account..." conditional phrasing) for the same key in portal.json so behavior aligns with the PR.ghost/i18n/locales/bg/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorKeep the new account-conditional wording in Bulgarian.
Line 111 and Line 112 drop the “If you have an account” qualifier, so this locale still tells users the link/email was sent unconditionally even when no member exists. Please preserve the conditional framing in the translation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/bg/portal.json` around lines 111 - 112, The Bulgarian translations for the message keys "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." removed the conditional “If you have an account” framing; update the two values so they begin with an equivalent Bulgarian conditional phrase (preserving the existing translated content and placeholders like {submittedEmailOrInbox}) to match the source keys and retain the account-conditional wording.ghost/i18n/locales/hr/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorThe Croatian copy should keep the new account-qualified promise.
Line 111 drops the new condition and now guarantees that the login email was sent. That changes the product message for this locale and no longer matches the normalized non-disclosing flow.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/hr/portal.json` at line 111, The translated value for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." currently guarantees the email was sent; update the Croatian string in portal.json so it preserves the conditional "If you have an account" (i.e., make it a non-disclosing phrasing such as "Ako imate račun, link za prijavu je poslan na vašu adresu e-pošte..." and keep the spam-folder clause) to match the original intent and normalized non-disclosing flow.ghost/i18n/locales/ru/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorThe Russian translations lost the new conditional meaning.
Line 111 and Line 112 both read as unconditional “sent” confirmations, but these strings now need to be careful not to promise delivery for unknown accounts. Please keep the account-qualified phrasing in the localized values.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/ru/portal.json` around lines 111 - 112, The Russian translations for the two keys "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." currently assert delivery unconditionally; update the localized values to preserve the conditional phrasing (e.g., start both with "Если у вас есть аккаунт," or equivalent) so they do not promise email delivery for unknown addresses while keeping the rest of the meaning (mention {submittedEmailOrInbox} placeholder in the second string and the spam/check timeframe note in the first).ghost/i18n/locales/de/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorPreserve the conditional meaning in the German copy.
Line 111 and Line 112 now state that the login link/email was sent as a fact, but the new source strings only promise that conditionally. Without that qualifier, German users get different behavior messaging from the rest of the product.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/de/portal.json` around lines 111 - 112, The German translations for the two source strings "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." were translated as definitive statements; restore the conditional phrasing by prepending or otherwise including the equivalent of "If you have an account," (e.g., "Wenn du ein Konto hast, ...") in both German values so the messages match the original conditional meaning used elsewhere in the product and keep the placeholder {submittedEmailOrInbox} intact in the second string.ghost/i18n/locales/fi/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorPreserve the privacy-safe qualifier in both Finnish messages.
Both values remove the “If you have an account” condition, so the localized UI now states that a link/email was sent even when the backend intentionally does not send one for unknown addresses. These translations need to carry the same conditional wording as the new source strings.
Based on learnings: In Ghost Portal (apps/portal), avoid suggesting changes to translation strings (wrapped in
t()) unless directly related to the PR's primary objective.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/fi/portal.json` around lines 111 - 112, Update the two Finnish translations to preserve the privacy-safe qualifier "If you have an account" at the start of each message so they match the source intent: for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." prepend the equivalent Finnish phrase (e.g. "Jos sinulla on tili,") and keep the rest of the sentence and timing/spam text intact; for "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." likewise prepend the same qualifier and preserve the {submittedEmailOrInbox} placeholder and the remainder of the instruction.ghost/i18n/locales/pl/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorPreserve the account-conditional qualifier in this translation.
This string reverts to the old unconditional wording, so Polish users are told the login link was sent even in the new “201 with no email for unknown members” path. The translated value should keep the “If you have an account” condition.
Based on learnings: In Ghost Portal (apps/portal), avoid suggesting changes to translation strings (wrapped in
t()) unless directly related to the PR's primary objective.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/pl/portal.json` at line 111, The Polish translation for the source string "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." lost the leading conditional; update the translation value for that exact source string so it preserves the "If you have an account" qualifier (e.g. start with "Jeśli masz konto," or equivalent) so the message remains conditional for the "201 with no email for unknown members" flow used by t().ghost/i18n/locales/kz/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorKeep the new account-conditional wording in the localized copy.
This value drops the “If you have an account” qualifier, so the localized UI still says a login link was sent even when the backend intentionally returns
201without sending anything for unknown addresses. Please preserve that qualifier in the translation.Based on learnings: In Ghost Portal (apps/portal), avoid suggesting changes to translation strings (wrapped in
t()) unless directly related to the PR's primary objective.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/kz/portal.json` at line 111, The localized Kazakh string dropped the leading conditional “If you have an account” from the source message; update the translation for the English source "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." so it preserves the account-conditional qualifier (e.g., start with a Kazakh equivalent of "If you have an account, ...") in the value currently set for that source string in portal.json; keep the string as a direct translation of the original t(...) key and do not alter the key or surrounding code.ghost/i18n/locales/et/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟠 MajorThis translation needs to keep the new conditional phrasing.
The new key is privacy-safe, but this value still states that the login link was sent unconditionally. That leaves Estonian users with the old behavior in the UI even though the backend now intentionally avoids sending email for unknown addresses.
Based on learnings: In Ghost Portal (apps/portal), avoid suggesting changes to translation strings (wrapped in
t()) unless directly related to the PR's primary objective.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/et/portal.json` at line 111, The Estonian translation for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." must keep the privacy-safe conditional phrasing used by the new key; update the value in portal.json so it explicitly conditions sending on account existence (e.g. start with "Kui teil on konto, ...") rather than unconditionally stating the link was sent, and retain the timing/spam-folder guidance and natural Estonian wording; edit the value for that exact source string in portal.json to reflect this conditional form.ghost/i18n/locales/ar/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟠 MajorKeep the new account-conditional wording in the Arabic copy.
Both translated values drop the “If you have an account” qualifier, which means the UI still claims an email/link was sent for all sign-in attempts. That contradicts the new behavior where unknown addresses still get
201but no email is sent.Based on learnings: In Ghost Portal (apps/portal), avoid suggesting changes to translation strings (wrapped in
t()) unless directly related to the PR's primary objective.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/ar/portal.json` around lines 111 - 112, The Arabic translations for the two portal strings have dropped the leading conditional "If you have an account" and must be updated to preserve that qualifier; locate the translation entries matching the English source keys "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.", prepend the Arabic equivalent of "If you have an account," to each translated value (keeping placeholders like {submittedEmailOrInbox} intact) and ensure no other unrelated translation strings are changed.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a296469a-0afe-4e59-82d1-8f49f3d02e71
⛔ Files ignored due to path filters (1)
ghost/core/test/e2e-api/members/__snapshots__/send-magic-link.test.js.snapis excluded by!**/*.snap
📒 Files selected for processing (70)
apps/portal/src/components/pages/magic-link-page.jsapps/portal/src/utils/errors.jsapps/portal/test/data-attributes.test.jsghost/core/core/server/services/members/members-api/controllers/router-controller.jsghost/core/test/e2e-api/members/send-magic-link.test.jsghost/core/test/unit/server/services/members/members-api/controllers/router-controller.test.jsghost/core/test/utils/e2e-framework-mock-manager.jsghost/i18n/locales/af/portal.jsonghost/i18n/locales/ar/portal.jsonghost/i18n/locales/bg/portal.jsonghost/i18n/locales/bn/portal.jsonghost/i18n/locales/bs/portal.jsonghost/i18n/locales/ca/portal.jsonghost/i18n/locales/context.jsonghost/i18n/locales/cs/portal.jsonghost/i18n/locales/da/portal.jsonghost/i18n/locales/de-CH/portal.jsonghost/i18n/locales/de/portal.jsonghost/i18n/locales/el/portal.jsonghost/i18n/locales/en/portal.jsonghost/i18n/locales/eo/portal.jsonghost/i18n/locales/es/portal.jsonghost/i18n/locales/et/portal.jsonghost/i18n/locales/eu/portal.jsonghost/i18n/locales/fa/portal.jsonghost/i18n/locales/fi/portal.jsonghost/i18n/locales/fr/portal.jsonghost/i18n/locales/gd/portal.jsonghost/i18n/locales/he/portal.jsonghost/i18n/locales/hi/portal.jsonghost/i18n/locales/hr/portal.jsonghost/i18n/locales/hu/portal.jsonghost/i18n/locales/id/portal.jsonghost/i18n/locales/is/portal.jsonghost/i18n/locales/it/portal.jsonghost/i18n/locales/ja/portal.jsonghost/i18n/locales/ko/portal.jsonghost/i18n/locales/kz/portal.jsonghost/i18n/locales/lt/portal.jsonghost/i18n/locales/lv/portal.jsonghost/i18n/locales/mk/portal.jsonghost/i18n/locales/mn/portal.jsonghost/i18n/locales/ms/portal.jsonghost/i18n/locales/nb/portal.jsonghost/i18n/locales/ne/portal.jsonghost/i18n/locales/nl/portal.jsonghost/i18n/locales/nn/portal.jsonghost/i18n/locales/pa/portal.jsonghost/i18n/locales/pl/portal.jsonghost/i18n/locales/pt-BR/portal.jsonghost/i18n/locales/pt/portal.jsonghost/i18n/locales/ro/portal.jsonghost/i18n/locales/ru/portal.jsonghost/i18n/locales/si/portal.jsonghost/i18n/locales/sk/portal.jsonghost/i18n/locales/sl/portal.jsonghost/i18n/locales/sq/portal.jsonghost/i18n/locales/sr-Cyrl/portal.jsonghost/i18n/locales/sr/portal.jsonghost/i18n/locales/sv/portal.jsonghost/i18n/locales/sw/portal.jsonghost/i18n/locales/ta/portal.jsonghost/i18n/locales/th/portal.jsonghost/i18n/locales/tr/portal.jsonghost/i18n/locales/uk/portal.jsonghost/i18n/locales/ur/portal.jsonghost/i18n/locales/uz/portal.jsonghost/i18n/locales/vi/portal.jsonghost/i18n/locales/zh-Hant/portal.jsonghost/i18n/locales/zh/portal.json
💤 Files with no reviewable changes (1)
- apps/portal/src/utils/errors.js
The signin endpoint now returns a consistent 201 response regardless of whether the provided email matches an existing member. If no member is found, no email is sent. This aligns signin behavior with the existing signup flow.
ade226c to
27c067f
Compare
There was a problem hiding this comment.
Actionable comments posted: 15
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/portal/test/data-attributes.test.js (1)
1003-1018:⚠️ Potential issue | 🟡 MinorThis test still asserts the pre-normalization error path.
/send-magic-link/now returns success for unknown emails, andformSubmitHandlertreats anyokresponse as the success branch. Keepingok: falsehere means this test is still locking the custom-form flow to the old contract.🧪 Suggested update
window.fetch .mockResolvedValueOnce({ ok: true, text: async () => 'testtoken' }) .mockResolvedValueOnce({ - ok: false, - json: async () => ({errors: [{message: 'Failed to send magic link email'}]}), - status: 400 + ok: true, + json: async () => ({}) }); await formSubmitHandler({event, form, errorEl, siteUrl, submitHandler}); expect(window.fetch).toHaveBeenCalledTimes(2); - expect(form.classList.add).toHaveBeenCalledWith('error'); - expect(errorEl.innerText).toBe('Failed to send magic link email'); + expect(form.classList.add).toHaveBeenCalledWith('success'); + expect(errorEl.innerText).toBe('');🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/portal/test/data-attributes.test.js` around lines 1003 - 1018, The test is still mocking the second fetch as ok: false (old contract) but the code path now treats any ok response as success; update the second mockResolvedValueOnce to return ok: true with an appropriate body (text/json) and then change the assertions to expect the success behavior of formSubmitHandler (e.g., do not expect form.classList.add('error') and errorEl.innerText should be empty or unchanged), referencing the formSubmitHandler function and the /send-magic-link response mock so the test covers the normalized-success branch.
🟡 Minor comments (9)
ghost/i18n/locales/pt/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟡 MinorPortuguese translation is missing the "If you have an account" prefix.
The English key was updated to include "If you have an account, " to avoid confirming whether an email exists (the core objective of this PR). However, the Portuguese translation still reads "Um link de acesso foi enviado para o seu email..." (A login link has been sent to your email...) without the conditional prefix.
Consider updating the translation to include the prefix, e.g., "Se tiver uma conta, um link de acesso foi enviado..."
Line 112's empty value is expected and will be filled in a separate translation PR.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/pt/portal.json` around lines 111 - 112, The Portuguese translation for the key "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." is missing the conditional prefix; update the existing translation for the similar key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." (and the empty value for the new key when filling it) to include the prefix "Se tiver uma conta, " so the message reads e.g. "Se tiver uma conta, um link de acesso foi enviado para o seu email..." ensuring both keys consistently start with the conditional phrase.ghost/i18n/locales/de/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟡 MinorGerman translations are missing the "If you have an account" conditional prefix.
The new English strings begin with "If you have an account, ..." to align with the PR's goal of not revealing whether an email exists. However, the German translations omit this conditional prefix:
- Line 111: Translates as "A login link has been sent..." instead of "If you have an account, a login link has been sent..."
- Line 112: Translates as "An email has been sent..." instead of "If you have an account, an email has been sent..."
Consider updating the translations to include the conditional prefix, e.g.:
- "Wenn du ein Konto hast, wurde ein Login-Link an dein Postfach gesendet..."
- "Wenn du ein Konto hast, wurde eine E-Mail an {submittedEmailOrInbox} gesendet..."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/de/portal.json` around lines 111 - 112, The German translations for the two portal messages are missing the conditional prefix "If you have an account," causing them to reveal existence; update the translations for the source keys "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." to include the conditional prefix (e.g. start with "Wenn du ein Konto hast,"), preserve the existing placeholders like {submittedEmailOrInbox}, and keep the rest of the German phrasing and punctuation consistent.ghost/i18n/locales/nb/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟡 MinorKeep the privacy-preserving qualifier in the Norwegian copy.
Line 111 still says a login link was sent, which drops the new “If you have an account” qualifier introduced by this PR. That makes the nb locale inconsistent with the normalized signin behavior.
✏️ Proposed fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "En påloggingslenke har blitt sendt til innboksen din. Hvis den ikke kommer innen 3 minutter, må du sjekke søppelposten din.", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Hvis du har en konto, har en påloggingslenke blitt sendt til innboksen din. Hvis den ikke kommer innen 3 minutter, må du sjekke søppelposten din.",🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/nb/portal.json` at line 111, The Norwegian translation for the signin message should preserve the privacy-preserving qualifier "If you have an account"; update the value for the key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." so it begins with the equivalent of "Hvis du har en konto," (for example: "Hvis du har en konto, har en påloggingslenke blitt sendt til innboksen din. Hvis den ikke kommer innen 3 minutter, må du sjekke søppelposten din.") to match the normalized signin behavior.ghost/i18n/locales/ko/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟡 MinorKeep the new Korean copy conditional and complete.
Line 111 drops the “If you have an account” qualifier, so this locale now says a login email was definitely sent even when no member exists. Line 112 is also blank, which will fall back to English on the OTC path. Please keep the conditional wording in both new strings so Korean matches the normalized signin behavior.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/ko/portal.json` around lines 111 - 112, The Korean translations for the keys "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." must retain the conditional phrase "If you have an account" and the second string must be completed (it is currently empty); update the translation for the first key to include the conditional "계정이 있는 경우" phrasing and provide a full Korean translation for the second key that preserves the placeholder {submittedEmailOrInbox} and instructs users to click the link or enter the code, mirroring the normalized signin behavior used elsewhere (adjust wording in the strings matching these exact English keys).ghost/i18n/locales/bn/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟡 MinorTranslate the new conditional wording here as well.
Line 111 still uses the old unconditional Bengali copy, so this locale loses the new “If you have an account” qualifier introduced by the PR. That means Bengali users will still be told a login link was sent even when no email was actually sent.
Suggested fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "একটি লগইন লিঙ্ক আপনার ইনবক্সে পাঠানো হয়েছে। যদি এটি ৩ মিনিটের মধ্যে না পৌঁছায়, তবে আপনার স্প্যাম ফোল্ডার চেক করুন।", + "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "যদি আপনার একটি অ্যাকাউন্ট থাকে, তবে একটি লগইন লিঙ্ক আপনার ইনবক্সে পাঠানো হয়েছে। যদি এটি ৩ মিনিটের মধ্যে না পৌঁছায়, তবে আপনার স্প্যাম ফোল্ডার চেক করুন।",Based on learnings: In Ghost Portal, avoid suggesting changes to translation strings unless directly related to the PR's primary objective, and this wording change is directly tied to the signin normalization behavior.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/bn/portal.json` at line 111, Update the Bengali translation for the login-link message to match the new conditional English phrasing "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." — replace the current unconditional Bengali string ("একটি লগইন লিঙ্ক আপনার ইনবক্সে পাঠানো হয়েছে...") with a translation that begins with the equivalent of "If you have an account" so the message only implies a sent link conditionally.ghost/i18n/locales/eu/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟡 MinorThe Basque translation on line 111 is missing the conditional prefix "Kontu bat baduzu" ("If you have an account").
The English key begins with "If you have an account, a login link..." but the Basque translation translates only the second part: "Saioa hasteko esteka bat bidali da zure postontzira..." (A login link has been sent...). The conditional prefix is required to maintain the PR's security objective of avoiding member existence disclosure for Basque-speaking users. Add "Kontu bat baduzu," at the beginning of the Basque translation to match the English key.
Line 112's empty translation is expected and will be filled in a separate PR.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/eu/portal.json` around lines 111 - 112, The Basque translation for the English key "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." is missing the conditional prefix; update the Basque value that currently starts "Saioa hasteko esteka bat bidali da zure postontzira..." by prepending "Kontu bat baduzu, " (keeping existing sentence and punctuation) so it mirrors the English key and preserves the non-disclosure conditional phrasing.ghost/i18n/locales/sl/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟡 MinorKeep the new account-conditional wording in the Slovenian copy.
This translation drops the “If you have an account” qualifier, so Slovenian users still see an unconditional “the login link was sent” message. That changes the privacy-preserving copy introduced by this PR.
Based on learnings: When source English text is modified, the corresponding translations should be updated to match.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/sl/portal.json` at line 111, The Slovenian translation for the login-link message has dropped the conditional opener and must be updated to match the English source’s privacy-preserving wording; modify the value for the string "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." in portal.json so it includes an equivalent of "If you have an account," (e.g., reinstate a leading conditional phrase in Slovenian) while keeping the rest of the sentence about the 3-minute arrival and checking spam.ghost/i18n/locales/th/portal.json-111-111 (1)
111-111:⚠️ Potential issue | 🟡 MinorPreserve the conditional in the Thai string.
This reads as an unconditional “the login link has been sent”, which loses the new “If you have an account” guard introduced by this PR.
Based on learnings: When source English text is modified, the corresponding translations should be updated to match.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/th/portal.json` at line 111, The Thai translation for the source string "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." removes the initial conditional; update the value in the portal.json entry for that exact source string so it preserves the "If you have an account" guard (i.e., translate the conditional phrase first, then the rest of the sentence and the spam-folder clause) so the Thai mirrors the English conditional structure.ghost/i18n/locales/ar/portal.json-111-112 (1)
111-112:⚠️ Potential issue | 🟡 MinorThese Arabic strings drop the new privacy-preserving qualifier.
Both translations start with an unconditional “تم إرسال…”, so the new “If you have an account” wording is lost here even though that is the message change this PR is making.
Based on learnings: When source English text is modified, the corresponding translations should be updated to match.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@ghost/i18n/locales/ar/portal.json` around lines 111 - 112, Update the two Arabic translations to preserve the privacy-preserving qualifier "If you have an account" from the source strings; specifically change the translation for "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." and for "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below." so they begin with an Arabic equivalent of "If you have an account," (e.g., "إذا كان لديك حساب،") and then include the rest of the message and the placeholder {submittedEmailOrInbox} unchanged where applicable, preserving punctuation and meaning.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@ghost/core/core/server/services/members/members-api/controllers/router-controller.js`:
- Around line 889-892: The current !member branch returns quickly (just
crypto.randomUUID()) which leaks existence via latency; make the no-member path
perform the same async work as the existing-member path to equalize timing.
Specifically, when includeOTC is true and member is falsy, still await the same
async operation used for real members (or an internal helper that mimics its
latency) instead of returning immediately—refer to the existing
_sendEmailWithMagicLink call and ensure the no-member flow awaits a comparable
Promise before returning the fake otcRef so response time cannot be used to
enumerate accounts.
In `@ghost/i18n/locales/bg/portal.json`:
- Around line 111-112: The Bulgarian translations for the keys "If you have an
account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." and "If you have an account, an
email has been sent to {submittedEmailOrInbox}. Click the link inside or enter
your code below." are missing the conditional prefix; update the corresponding
values in portal.json by prepending the Bulgarian conditional phrase (e.g., "Ако
имате профил, ") to each translation while preserving the rest of the sentence,
punctuation and the {submittedEmailOrInbox} placeholder exactly as in the source
strings so the security intent (preventing email enumeration) is maintained.
In `@ghost/i18n/locales/bs/portal.json`:
- Around line 111-112: The Bosnian translations removed the conditional “If you
have an account” and lost the placeholder in the second key; update the
translated values for the keys "If you have an account, a login link has been
sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your
spam folder." and "If you have an account, an email has been sent to
{submittedEmailOrInbox}. Click the link inside or enter your code below." so
they retain the conditional phrasing (include the equivalent of “If you have an
account”) and do not alter the placeholder token {submittedEmailOrInbox}; only
modify the right-hand translated strings in portal.json.
In `@ghost/i18n/locales/fr/portal.json`:
- Around line 111-112: The French translations for the two portal messages are
missing the required conditional prefix "If you have an account" which must be
preserved to avoid revealing account existence; update the translations for the
keys "If you have an account, a login link has been sent to your inbox. If it
doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you
have an account, an email has been sent to {submittedEmailOrInbox}. Click the
link inside or enter your code below." by prepending "Si vous avez un compte, "
to each French value (so the first becomes "Si vous avez un compte, Un lien de
connexion..." and the second becomes "Si vous avez un compte, Un e-mail a été
envoyé..."), ensuring punctuation and spacing match existing French phrasing.
In `@ghost/i18n/locales/he/portal.json`:
- Line 111: The Hebrew translation for the message keyed by the English text "If
you have an account, a login link has been sent to your inbox. If it doesn't
arrive in 3 minutes, be sure to check your spam folder." currently drops the
privacy-neutral qualifier and states the link was sent unconditionally; update
the Hebrew string to include an explicit privacy-neutral qualifier equivalent to
"If you have an account" (i.e., prepend or rephrase so it reads conditionally)
so the message does not reveal whether the submitted email exists, keeping the
rest of the sentence about delivery time and spam checking intact.
In `@ghost/i18n/locales/hu/portal.json`:
- Line 111: The Hungarian translation for the key "If you have an account, a
login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be
sure to check your spam folder." should preserve the conditional hedge "If you
have an account" — update the value string so it mirrors the original English
conditional (e.g., start with "Ha van fiókod, ..." or equivalent) rather than
stating the link definitively was sent; locate that exact key in portal.json and
replace the Hungarian sentence to include the hedge while keeping the remainder
about checking spam/3 minutes intact.
In `@ghost/i18n/locales/ja/portal.json`:
- Line 111: The Japanese translation for the key "If you have an account, a
login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be
sure to check your spam folder." omits the conditional prefix; update the
translation to include the conditional phrase at the start (e.g.,
"アカウントをお持ちの場合、ログインリンクが受信箱に送信されました。3分以内にメールが届かない場合は、迷惑メールのフォルダーをご確認ください。") so it
preserves the original non-disclosure intent and matches the English source.
In `@ghost/i18n/locales/mk/portal.json`:
- Line 111: Update the Macedonian translation value for the key "If you have an
account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." in
ghost/i18n/locales/mk/portal.json to include the conditional hedge equivalent of
"If you have an account," (e.g., prepend or incorporate a Macedonian phrase
meaning "If you have an account") so the string remains conditional rather than
asserting delivery; keep the rest of the guidance about the 3-minute wait and
spam folder intact and preserve punctuation/formatting consistent with other
locale entries.
In `@ghost/i18n/locales/nn/portal.json`:
- Line 111: The translated value for the English key "If you have an account, a
login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be
sure to check your spam folder." is missing the conditional prefix and thus
reveals account existence; update the Norwegian Nynorsk translation in
portal.json to begin with a conditional phrase equivalent to "If you have an
account" (e.g., "Viss du har ein konto, ...") and keep the rest of the sentence
meaning intact and neutral (adjust "Ei innlogginslenke har blitt sendt til
innboksen din. Sjekk søppelposten din om lenka ikkje kjem innan 3 minutt." to
include the prefix) so the string matches the English intent and preserves
privacy.
In `@ghost/i18n/locales/pl/portal.json`:
- Line 111: The Polish translation for the key "If you have an account, a login
link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to
check your spam folder." removed the conditional phrase and must be restored;
update the value in portal.json (locale pl) to include the equivalent of "If you
have an account," at the start (e.g. "Jeśli masz konto, link do logowania został
wysłany do Twojej skrzynki odbiorczej. Jeśli nie dotrze w ciągu 3 minut, sprawdź
folder spam.") so the message remains conditional and consistent with the
normalized signin messaging.
In `@ghost/i18n/locales/ro/portal.json`:
- Line 111: The Romanian translation for the portal JSON key "If you have an
account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." is missing the conditional prefix;
update the value string in portal.json to include the conditional "Dacă ai un
cont," at the start (for example: "Dacă ai un cont, un link de autentificare a
fost trimis în inbox-ul tău. Dacă nu ajunge în 3 minute, asigură-te că verifici
folderul de spam.") so it matches the English key's privacy-preserving intent.
In `@ghost/i18n/locales/ru/portal.json`:
- Around line 111-112: The Russian translations for the two portal messages have
dropped the security-critical prefix "If you have an account", so update the
translations for the keys matching the English source strings "If you have an
account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." and "If you have an account, an
email has been sent to {submittedEmailOrInbox}. Click the link inside or enter
your code below." to include the equivalent Russian prefix (e.g., "Если у вас
есть аккаунт, ...") at the start of each translated value so the conditional
wording is preserved.
In `@ghost/i18n/locales/sv/portal.json`:
- Around line 111-112: The Swedish translations for the two English source
strings "If you have an account, a login link has been sent to your inbox. If it
doesn't arrive in 3 minutes, be sure to check your spam folder." and "If you
have an account, an email has been sent to {submittedEmailOrInbox}. Click the
link inside or enter your code below." were changed to assert the email was
sent; revert them to include the conditional hedge "If you have an account,"
(e.g. start each Swedish string with "Om du har ett konto" and preserve
placeholders like {submittedEmailOrInbox} and the original punctuation and
second-sentence advice) so the Swedish copy matches the PR’s
privacy/normalization behavior.
In `@ghost/i18n/locales/sw/portal.json`:
- Line 111: The Swahili translation for the source string "If you have an
account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." lost the conditional "If you have
an account" and now reads as an unconditional statement; update the translation
in the key that maps to that exact English source string so it preserves the
conditional phrasing (e.g., start with "Ikiwa una akaunti, ..." and then convey
the rest about the login link and checking spam) while keeping the same
timing/3-minute detail and tone.
In `@ghost/i18n/locales/tr/portal.json`:
- Around line 111-112: The Turkish translations for the two keys matching the
English source strings "If you have an account, a login link has been sent to
your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam
folder." and "If you have an account, an email has been sent to
{submittedEmailOrInbox}. Click the link inside or enter your code below." are
missing the conditional prefix; update the corresponding values by prepending
"Hesabınız varsa, " to each translation (ensure correct punctuation and spacing,
and keep the {submittedEmailOrInbox} placeholder intact for the second string)
so the messages do not leak account existence.
---
Outside diff comments:
In `@apps/portal/test/data-attributes.test.js`:
- Around line 1003-1018: The test is still mocking the second fetch as ok: false
(old contract) but the code path now treats any ok response as success; update
the second mockResolvedValueOnce to return ok: true with an appropriate body
(text/json) and then change the assertions to expect the success behavior of
formSubmitHandler (e.g., do not expect form.classList.add('error') and
errorEl.innerText should be empty or unchanged), referencing the
formSubmitHandler function and the /send-magic-link response mock so the test
covers the normalized-success branch.
---
Minor comments:
In `@ghost/i18n/locales/ar/portal.json`:
- Around line 111-112: Update the two Arabic translations to preserve the
privacy-preserving qualifier "If you have an account" from the source strings;
specifically change the translation for "If you have an account, a login link
has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check
your spam folder." and for "If you have an account, an email has been sent to
{submittedEmailOrInbox}. Click the link inside or enter your code below." so
they begin with an Arabic equivalent of "If you have an account," (e.g., "إذا
كان لديك حساب،") and then include the rest of the message and the placeholder
{submittedEmailOrInbox} unchanged where applicable, preserving punctuation and
meaning.
In `@ghost/i18n/locales/bn/portal.json`:
- Line 111: Update the Bengali translation for the login-link message to match
the new conditional English phrasing "If you have an account, a login link has
been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check
your spam folder." — replace the current unconditional Bengali string ("একটি
লগইন লিঙ্ক আপনার ইনবক্সে পাঠানো হয়েছে...") with a translation that begins with
the equivalent of "If you have an account" so the message only implies a sent
link conditionally.
In `@ghost/i18n/locales/de/portal.json`:
- Around line 111-112: The German translations for the two portal messages are
missing the conditional prefix "If you have an account," causing them to reveal
existence; update the translations for the source keys "If you have an account,
a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be
sure to check your spam folder." and "If you have an account, an email has been
sent to {submittedEmailOrInbox}. Click the link inside or enter your code
below." to include the conditional prefix (e.g. start with "Wenn du ein Konto
hast,"), preserve the existing placeholders like {submittedEmailOrInbox}, and
keep the rest of the German phrasing and punctuation consistent.
In `@ghost/i18n/locales/eu/portal.json`:
- Around line 111-112: The Basque translation for the English key "If you have
an account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." is missing the conditional prefix;
update the Basque value that currently starts "Saioa hasteko esteka bat bidali
da zure postontzira..." by prepending "Kontu bat baduzu, " (keeping existing
sentence and punctuation) so it mirrors the English key and preserves the
non-disclosure conditional phrasing.
In `@ghost/i18n/locales/ko/portal.json`:
- Around line 111-112: The Korean translations for the keys "If you have an
account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." and "If you have an account, an
email has been sent to {submittedEmailOrInbox}. Click the link inside or enter
your code below." must retain the conditional phrase "If you have an account"
and the second string must be completed (it is currently empty); update the
translation for the first key to include the conditional "계정이 있는 경우" phrasing
and provide a full Korean translation for the second key that preserves the
placeholder {submittedEmailOrInbox} and instructs users to click the link or
enter the code, mirroring the normalized signin behavior used elsewhere (adjust
wording in the strings matching these exact English keys).
In `@ghost/i18n/locales/nb/portal.json`:
- Line 111: The Norwegian translation for the signin message should preserve the
privacy-preserving qualifier "If you have an account"; update the value for the
key "If you have an account, a login link has been sent to your inbox. If it
doesn't arrive in 3 minutes, be sure to check your spam folder." so it begins
with the equivalent of "Hvis du har en konto," (for example: "Hvis du har en
konto, har en påloggingslenke blitt sendt til innboksen din. Hvis den ikke
kommer innen 3 minutter, må du sjekke søppelposten din.") to match the
normalized signin behavior.
In `@ghost/i18n/locales/pt/portal.json`:
- Around line 111-112: The Portuguese translation for the key "If you have an
account, an email has been sent to {submittedEmailOrInbox}. Click the link
inside or enter your code below." is missing the conditional prefix; update the
existing translation for the similar key "If you have an account, a login link
has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check
your spam folder." (and the empty value for the new key when filling it) to
include the prefix "Se tiver uma conta, " so the message reads e.g. "Se tiver
uma conta, um link de acesso foi enviado para o seu email..." ensuring both keys
consistently start with the conditional phrase.
In `@ghost/i18n/locales/sl/portal.json`:
- Line 111: The Slovenian translation for the login-link message has dropped the
conditional opener and must be updated to match the English source’s
privacy-preserving wording; modify the value for the string "If you have an
account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." in portal.json so it includes an
equivalent of "If you have an account," (e.g., reinstate a leading conditional
phrase in Slovenian) while keeping the rest of the sentence about the 3-minute
arrival and checking spam.
In `@ghost/i18n/locales/th/portal.json`:
- Line 111: The Thai translation for the source string "If you have an account,
a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be
sure to check your spam folder." removes the initial conditional; update the
value in the portal.json entry for that exact source string so it preserves the
"If you have an account" guard (i.e., translate the conditional phrase first,
then the rest of the sentence and the spam-folder clause) so the Thai mirrors
the English conditional structure.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: c89a0e20-0a63-4775-8ebe-99bbea095d95
⛔ Files ignored due to path filters (1)
ghost/core/test/e2e-api/members/__snapshots__/send-magic-link.test.js.snapis excluded by!**/*.snap
📒 Files selected for processing (72)
apps/portal/package.jsonapps/portal/src/components/pages/magic-link-page.jsapps/portal/src/utils/errors.jsapps/portal/test/data-attributes.test.jsghost/core/core/server/services/members/members-api/controllers/router-controller.jsghost/core/core/shared/config/defaults.jsonghost/core/test/e2e-api/members/send-magic-link.test.jsghost/core/test/unit/server/services/members/members-api/controllers/router-controller.test.jsghost/core/test/utils/e2e-framework-mock-manager.jsghost/i18n/locales/af/portal.jsonghost/i18n/locales/ar/portal.jsonghost/i18n/locales/bg/portal.jsonghost/i18n/locales/bn/portal.jsonghost/i18n/locales/bs/portal.jsonghost/i18n/locales/ca/portal.jsonghost/i18n/locales/context.jsonghost/i18n/locales/cs/portal.jsonghost/i18n/locales/da/portal.jsonghost/i18n/locales/de-CH/portal.jsonghost/i18n/locales/de/portal.jsonghost/i18n/locales/el/portal.jsonghost/i18n/locales/en/portal.jsonghost/i18n/locales/eo/portal.jsonghost/i18n/locales/es/portal.jsonghost/i18n/locales/et/portal.jsonghost/i18n/locales/eu/portal.jsonghost/i18n/locales/fa/portal.jsonghost/i18n/locales/fi/portal.jsonghost/i18n/locales/fr/portal.jsonghost/i18n/locales/gd/portal.jsonghost/i18n/locales/he/portal.jsonghost/i18n/locales/hi/portal.jsonghost/i18n/locales/hr/portal.jsonghost/i18n/locales/hu/portal.jsonghost/i18n/locales/id/portal.jsonghost/i18n/locales/is/portal.jsonghost/i18n/locales/it/portal.jsonghost/i18n/locales/ja/portal.jsonghost/i18n/locales/ko/portal.jsonghost/i18n/locales/kz/portal.jsonghost/i18n/locales/lt/portal.jsonghost/i18n/locales/lv/portal.jsonghost/i18n/locales/mk/portal.jsonghost/i18n/locales/mn/portal.jsonghost/i18n/locales/ms/portal.jsonghost/i18n/locales/nb/portal.jsonghost/i18n/locales/ne/portal.jsonghost/i18n/locales/nl/portal.jsonghost/i18n/locales/nn/portal.jsonghost/i18n/locales/pa/portal.jsonghost/i18n/locales/pl/portal.jsonghost/i18n/locales/pt-BR/portal.jsonghost/i18n/locales/pt/portal.jsonghost/i18n/locales/ro/portal.jsonghost/i18n/locales/ru/portal.jsonghost/i18n/locales/si/portal.jsonghost/i18n/locales/sk/portal.jsonghost/i18n/locales/sl/portal.jsonghost/i18n/locales/sq/portal.jsonghost/i18n/locales/sr-Cyrl/portal.jsonghost/i18n/locales/sr/portal.jsonghost/i18n/locales/sv/portal.jsonghost/i18n/locales/sw/portal.jsonghost/i18n/locales/ta/portal.jsonghost/i18n/locales/th/portal.jsonghost/i18n/locales/tr/portal.jsonghost/i18n/locales/uk/portal.jsonghost/i18n/locales/ur/portal.jsonghost/i18n/locales/uz/portal.jsonghost/i18n/locales/vi/portal.jsonghost/i18n/locales/zh-Hant/portal.jsonghost/i18n/locales/zh/portal.json
💤 Files with no reviewable changes (1)
- apps/portal/src/utils/errors.js
✅ Files skipped from review due to trivial changes (2)
- apps/portal/package.json
- ghost/core/core/shared/config/defaults.json
🚧 Files skipped from review as they are similar to previous changes (38)
- apps/portal/src/components/pages/magic-link-page.js
- ghost/i18n/locales/mn/portal.json
- ghost/i18n/locales/ms/portal.json
- ghost/i18n/locales/hr/portal.json
- ghost/core/test/utils/e2e-framework-mock-manager.js
- ghost/i18n/locales/hi/portal.json
- ghost/i18n/locales/ca/portal.json
- ghost/i18n/locales/si/portal.json
- ghost/i18n/locales/cs/portal.json
- ghost/i18n/locales/de-CH/portal.json
- ghost/i18n/locales/zh/portal.json
- ghost/i18n/locales/lt/portal.json
- ghost/i18n/locales/sr/portal.json
- ghost/i18n/locales/es/portal.json
- ghost/i18n/locales/pt-BR/portal.json
- ghost/i18n/locales/sq/portal.json
- ghost/i18n/locales/ur/portal.json
- ghost/i18n/locales/lv/portal.json
- ghost/i18n/locales/kz/portal.json
- ghost/i18n/locales/da/portal.json
- ghost/i18n/locales/uk/portal.json
- ghost/i18n/locales/et/portal.json
- ghost/i18n/locales/fi/portal.json
- ghost/i18n/locales/af/portal.json
- ghost/i18n/locales/ta/portal.json
- ghost/i18n/locales/sk/portal.json
- ghost/i18n/locales/it/portal.json
- ghost/i18n/locales/gd/portal.json
- ghost/i18n/locales/el/portal.json
- ghost/i18n/locales/vi/portal.json
- ghost/i18n/locales/nl/portal.json
- ghost/i18n/locales/is/portal.json
- ghost/i18n/locales/context.json
- ghost/i18n/locales/id/portal.json
- ghost/i18n/locales/eo/portal.json
- ghost/i18n/locales/zh-Hant/portal.json
- ghost/i18n/locales/fa/portal.json
- ghost/i18n/locales/uz/portal.json
| if (!member) { | ||
| throw new errors.BadRequestError({ | ||
| message: this._allowSelfSignup() ? tpl(messages.memberNotFoundSignUp) : tpl(messages.memberNotFound) | ||
| }); | ||
| // Return a fake otcRef when OTC was requested so the response | ||
| // shape is identical regardless of whether a member exists | ||
| return includeOTC ? {otcRef: crypto.randomUUID()} : {}; |
There was a problem hiding this comment.
This still exposes member existence through latency.
If anti-enumeration is the goal, the !member branch is still observably faster than the real-member branch because it only generates a UUID and returns, while the existing-member path awaits _sendEmailWithMagicLink(...). The body/status match, but latency can still leak whether the account exists.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@ghost/core/core/server/services/members/members-api/controllers/router-controller.js`
around lines 889 - 892, The current !member branch returns quickly (just
crypto.randomUUID()) which leaks existence via latency; make the no-member path
perform the same async work as the existing-member path to equalize timing.
Specifically, when includeOTC is true and member is falsy, still await the same
async operation used for real members (or an internal helper that mimics its
latency) instead of returning immediately—refer to the existing
_sendEmailWithMagicLink call and ensure the no-member flow awaits a comparable
Promise before returning the fake otcRef so response time cannot be used to
enumerate accounts.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Линк за влизане беше изпратен на имейла ви. Ако не пристигне до 3 минути, проверете папката за спам.", | ||
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Изпратен е имейл до {submittedEmailOrInbox}. Щракнете върху линка в него или въведете кода си по-долу.", |
There was a problem hiding this comment.
Bulgarian translations are missing the critical "If you have an account" conditional prefix.
Both translations omit the conditional phrase that is the core of this security change:
- Line 111: Bulgarian says "Линк за влизане беше изпратен..." (A login link has been sent...) instead of including "Ако имате профил, ..." (If you have an account, ...)
- Line 112: Bulgarian says "Изпратен е имейл до..." (An email has been sent to...) instead of including "Ако имате профил, ..." (If you have an account, ...)
Without the conditional prefix, Bulgarian-speaking users will see a message implying an email was definitely sent, which defeats the PR's purpose of preventing email enumeration.
Suggested fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Линк за влизане беше изпратен на имейла ви. Ако не пристигне до 3 минути, проверете папката за спам.",
- "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Изпратен е имейл до {submittedEmailOrInbox}. Щракнете върху линка в него или въведете кода си по-долу.",
+ "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ако имате профил, линк за влизане е изпратен на имейла ви. Ако не пристигне до 3 минути, проверете папката за спам.",
+ "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Ако имате профил, изпратен е имейл до {submittedEmailOrInbox}. Щракнете върху линка в него или въведете кода си по-долу.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Линк за влизане беше изпратен на имейла ви. Ако не пристигне до 3 минути, проверете папката за спам.", | |
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Изпратен е имейл до {submittedEmailOrInbox}. Щракнете върху линка в него или въведете кода си по-долу.", | |
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ако имате профил, линк за влизане е изпратен на имейла ви. Ако не пристигне до 3 минути, проверете папката за спам.", | |
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Ако имате профил, изпратен е имейл до {submittedEmailOrInbox}. Щракнете върху линка в него или въведете кода си по-долу.", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/bg/portal.json` around lines 111 - 112, The Bulgarian
translations for the keys "If you have an account, a login link has been sent to
your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam
folder." and "If you have an account, an email has been sent to
{submittedEmailOrInbox}. Click the link inside or enter your code below." are
missing the conditional prefix; update the corresponding values in portal.json
by prepending the Bulgarian conditional phrase (e.g., "Ако имате профил, ") to
each translation while preserving the rest of the sentence, punctuation and the
{submittedEmailOrInbox} placeholder exactly as in the source strings so the
security intent (preventing email enumeration) is maintained.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Link za prijavu poslan je na tvoju Email adresu. Ako ne stigne u roku od 3 minute, provjeri spam folder.", | ||
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "", |
There was a problem hiding this comment.
Keep the Bosnian sign-in copy account-agnostic.
Line 111 drops the equivalent of “If you have an account, …” and again tells the user the login link was sent unconditionally. That undermines the normalization this PR is introducing for bs users. Please preserve the conditional wording here, and keep {submittedEmailOrInbox} unchanged when translating Line 112.
Based on learnings: translators should only modify the translated values and must not change the keys or placeholder styles.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/bs/portal.json` around lines 111 - 112, The Bosnian
translations removed the conditional “If you have an account” and lost the
placeholder in the second key; update the translated values for the keys "If you
have an account, a login link has been sent to your inbox. If it doesn't arrive
in 3 minutes, be sure to check your spam folder." and "If you have an account,
an email has been sent to {submittedEmailOrInbox}. Click the link inside or
enter your code below." so they retain the conditional phrasing (include the
equivalent of “If you have an account”) and do not alter the placeholder token
{submittedEmailOrInbox}; only modify the right-hand translated strings in
portal.json.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Un lien de connexion a été envoyé dans votre boîte de réception. S’il n’arrive pas dans les 3 minutes, vérifiez votre dossier d'indésirables.", | ||
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Un e-mail a été envoyé à {submittedEmailOrInbox}. Cliquez sur le lien contenu dans l'e-mail ou saisissez le code ci-dessous.", |
There was a problem hiding this comment.
French translations are missing the conditional "If you have an account" phrase.
The core purpose of this PR is to prefix messages with "If you have an account" to avoid revealing whether an email belongs to an existing member. However, both French translations omit this conditional:
- Line 111: Missing "Si vous avez un compte, " at the start
- Line 112: Missing "Si vous avez un compte, " at the start
This defeats the privacy protection for French-speaking users.
Proposed fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Un lien de connexion a été envoyé dans votre boîte de réception. S'il n'arrive pas dans les 3 minutes, vérifiez votre dossier d'indésirables.",
- "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Un e-mail a été envoyé à {submittedEmailOrInbox}. Cliquez sur le lien contenu dans l'e-mail ou saisissez le code ci-dessous.",
+ "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Si vous avez un compte, un lien de connexion a été envoyé dans votre boîte de réception. S'il n'arrive pas dans les 3 minutes, vérifiez votre dossier d'indésirables.",
+ "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Si vous avez un compte, un e-mail a été envoyé à {submittedEmailOrInbox}. Cliquez sur le lien contenu dans l'e-mail ou saisissez le code ci-dessous.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Un lien de connexion a été envoyé dans votre boîte de réception. S’il n’arrive pas dans les 3 minutes, vérifiez votre dossier d'indésirables.", | |
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Un e-mail a été envoyé à {submittedEmailOrInbox}. Cliquez sur le lien contenu dans l'e-mail ou saisissez le code ci-dessous.", | |
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Si vous avez un compte, un lien de connexion a été envoyé dans votre boîte de réception. S'il n'arrive pas dans les 3 minutes, vérifiez votre dossier d'indésirables.", | |
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Si vous avez un compte, un e-mail a été envoyé à {submittedEmailOrInbox}. Cliquez sur le lien contenu dans l'e-mail ou saisissez le code ci-dessous.", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/fr/portal.json` around lines 111 - 112, The French
translations for the two portal messages are missing the required conditional
prefix "If you have an account" which must be preserved to avoid revealing
account existence; update the translations for the keys "If you have an account,
a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be
sure to check your spam folder." and "If you have an account, an email has been
sent to {submittedEmailOrInbox}. Click the link inside or enter your code
below." by prepending "Si vous avez un compte, " to each French value (so the
first becomes "Si vous avez un compte, Un lien de connexion..." and the second
becomes "Si vous avez un compte, Un e-mail a été envoyé..."), ensuring
punctuation and spacing match existing French phrasing.
| "If the spam complaint was accidental, or you would like to begin receiving emails again, you can resubscribe to emails by clicking the button on the previous screen.": "אם תלונת הספאם הייתה בטעות, או שתרצו להתחיל לקבל מיילים שוב, ניתן להירשם מחדש למיילים על ידי לחיצה על הכפתור במסך הקודם.", | ||
| "If you cancel your subscription now, you will continue to have access until {periodEnd}.": "אם תבטלו את המנוי כעת, תמשיכו לקבל גישה עד {periodEnd}.", | ||
| "If you have a corporate or government email account, reach out to your IT department and ask them to allow emails to be received from {senderEmail}": "אם יש לכם חשבון מייל עסקי או ממשלתי, פנו למחלקת ה-IT שלכם ובקשו מהם לאפשר קבלת מיילים מאת {senderEmail}", | ||
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "לינק לכניסה נשלח לתיבת המייל שלכם. במידה ואינו מגיע תוך 3 דקות, בדקו את תיבת הספאם שלכם.", |
There was a problem hiding this comment.
Preserve the privacy-neutral qualifier in the Hebrew copy.
Line 111 drops the “If you have an account” condition and reverts to an unconditional “a login link has been sent” message. That undermines this PR’s goal of not revealing whether the submitted email exists for Hebrew users.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/he/portal.json` at line 111, The Hebrew translation for
the message keyed by the English text "If you have an account, a login link has
been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check
your spam folder." currently drops the privacy-neutral qualifier and states the
link was sent unconditionally; update the Hebrew string to include an explicit
privacy-neutral qualifier equivalent to "If you have an account" (i.e., prepend
or rephrase so it reads conditionally) so the message does not reveal whether
the submitted email exists, keeping the rest of the sentence about delivery time
and spam checking intact.
| "If the spam complaint was accidental, or you would like to begin receiving emails again, you can resubscribe to emails by clicking the button on the previous screen.": "Dacă sesizarea privind spam-ul a fost accidentală, sau doriți să începeți din nou să primiți emailuri, vă puteți reabona la emailuri făcând clic pe butonul de pe ecranul anterior.", | ||
| "If you cancel your subscription now, you will continue to have access until {periodEnd}.": "Dacă anulați abonamentul acum, veți continua să aveți acces până la {periodEnd}.", | ||
| "If you have a corporate or government email account, reach out to your IT department and ask them to allow emails to be received from {senderEmail}": "Dacă aveți un cont de email corporativ sau guvernamental, contactați departamentul IT și cereți-le să permită primirea emailurilor de la {senderEmail}", | ||
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Un link de autentificare a fost trimis în inbox-ul tău. Dacă nu ajunge în 3 minute, asigură-te că verifici folderul de spam.", |
There was a problem hiding this comment.
Romanian translation is missing the conditional prefix "If you have an account".
The English key explicitly starts with "If you have an account," but the Romanian translation omits this conditional, directly stating "Un link de autentificare a fost trimis..." This defeats the PR's privacy-preserving intent for Romanian users.
The translation should include the conditional prefix, e.g., "Dacă ai un cont, un link de autentificare a fost trimis în inbox-ul tău..."
Proposed fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Un link de autentificare a fost trimis în inbox-ul tău. Dacă nu ajunge în 3 minute, asigură-te că verifici folderul de spam.",
+ "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Dacă ai un cont, un link de autentificare a fost trimis în inbox-ul tău. Dacă nu ajunge în 3 minute, asigură-te că verifici folderul de spam.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Un link de autentificare a fost trimis în inbox-ul tău. Dacă nu ajunge în 3 minute, asigură-te că verifici folderul de spam.", | |
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Dacă ai un cont, un link de autentificare a fost trimis în inbox-ul tău. Dacă nu ajunge în 3 minute, asigură-te că verifici folderul de spam.", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/ro/portal.json` at line 111, The Romanian translation for
the portal JSON key "If you have an account, a login link has been sent to your
inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder." is
missing the conditional prefix; update the value string in portal.json to
include the conditional "Dacă ai un cont," at the start (for example: "Dacă ai
un cont, un link de autentificare a fost trimis în inbox-ul tău. Dacă nu ajunge
în 3 minute, asigură-te că verifici folderul de spam.") so it matches the
English key's privacy-preserving intent.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ссылка для входа была отправлена вам на email. Если письмо не пришло в течение 3 минут, проверьте папку «Спам».", | ||
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Письмо отправлено на адрес {submittedEmailOrInbox}. Нажмите на ссылку в письме или введите код ниже.", |
There was a problem hiding this comment.
Russian translations are missing the "If you have an account" prefix.
The PR's security improvement depends on the conditional "If you have an account" phrasing to avoid revealing whether an email is registered. However, both Russian translations omit this prefix:
- Line 111: Translates to "A login link has been sent to your email..." instead of "If you have an account, a login link has been sent..."
- Line 112: Translates to "An email has been sent to..." instead of "If you have an account, an email has been sent..."
This defeats the email enumeration protection for Russian-speaking users.
Suggested fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ссылка для входа была отправлена вам на email. Если письмо не пришло в течение 3 минут, проверьте папку «Спам».",
- "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Письмо отправлено на адрес {submittedEmailOrInbox}. Нажмите на ссылку в письме или введите код ниже.",
+ "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Если у вас есть аккаунт, ссылка для входа была отправлена вам на email. Если письмо не пришло в течение 3 минут, проверьте папку «Спам».",
+ "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Если у вас есть аккаунт, письмо отправлено на адрес {submittedEmailOrInbox}. Нажмите на ссылку в письме или введите код ниже.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Ссылка для входа была отправлена вам на email. Если письмо не пришло в течение 3 минут, проверьте папку «Спам».", | |
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Письмо отправлено на адрес {submittedEmailOrInbox}. Нажмите на ссылку в письме или введите код ниже.", | |
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Если у вас есть аккаунт, ссылка для входа была отправлена вам на email. Если письмо не пришло в течение 3 минут, проверьте папку «Спам».", | |
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Если у вас есть аккаунт, письмо отправлено на адрес {submittedEmailOrInbox}. Нажмите на ссылку в письме или введите код ниже.", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/ru/portal.json` around lines 111 - 112, The Russian
translations for the two portal messages have dropped the security-critical
prefix "If you have an account", so update the translations for the keys
matching the English source strings "If you have an account, a login link has
been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check
your spam folder." and "If you have an account, an email has been sent to
{submittedEmailOrInbox}. Click the link inside or enter your code below." to
include the equivalent Russian prefix (e.g., "Если у вас есть аккаунт, ...") at
the start of each translated value so the conditional wording is preserved.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "En inloggningslänk har skickats till din inkorg. Om den inte anländer inom 3 minuter, kontrollera din skräppostmapp.", | ||
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Ett e-postmeddelande har skickats till {submittedEmailOrInbox}. Klicka på länken i meddelandet eller ange din kod nedan.", |
There was a problem hiding this comment.
Restore the conditional wording in these Swedish strings.
Both translations drop the new If you have an account, hedge and now assert that the login email was sent. That’s no longer true for unknown addresses in this flow, so the Swedish UI misses the PR’s normalization/privacy behavior and gives inaccurate feedback.
💬 Suggested translation update
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "En inloggningslänk har skickats till din inkorg. Om den inte anländer inom 3 minuter, kontrollera din skräppostmapp.",
- "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Ett e-postmeddelande har skickats till {submittedEmailOrInbox}. Klicka på länken i meddelandet eller ange din kod nedan.",
+ "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Om du har ett konto har en inloggningslänk skickats till din inkorg. Om den inte kommer inom 3 minuter, kontrollera skräppostmappen.",
+ "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Om du har ett konto har ett e-postmeddelande skickats till {submittedEmailOrInbox}. Klicka på länken i meddelandet eller ange koden nedan.",Based on learnings, translation-string changes should only be suggested when directly related to the PR objective, and this one is.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/sv/portal.json` around lines 111 - 112, The Swedish
translations for the two English source strings "If you have an account, a login
link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to
check your spam folder." and "If you have an account, an email has been sent to
{submittedEmailOrInbox}. Click the link inside or enter your code below." were
changed to assert the email was sent; revert them to include the conditional
hedge "If you have an account," (e.g. start each Swedish string with "Om du har
ett konto" and preserve placeholders like {submittedEmailOrInbox} and the
original punctuation and second-sentence advice) so the Swedish copy matches the
PR’s privacy/normalization behavior.
| "If the spam complaint was accidental, or you would like to begin receiving emails again, you can resubscribe to emails by clicking the button on the previous screen.": "Ikiwa malalamiko ya spam yalikuwa ya bahati mbaya, au ungependa kuanza kupokea barua pepe tena, unaweza kujiandikisha tena kwa barua pepe kwa kubofya kitufe kwenye skrini iliyopita.", | ||
| "If you cancel your subscription now, you will continue to have access until {periodEnd}.": "Ikiwa utaghairi usajili wako sasa, utaendelea kupata huduma hadi {periodEnd}.", | ||
| "If you have a corporate or government email account, reach out to your IT department and ask them to allow emails to be received from {senderEmail}": "Ikiwa una akaunti ya barua pepe ya kampuni au serikali, wasiliana na idara yako ya IT na uwaombe waruhusu kupokea barua pepe kutoka {senderEmail}", | ||
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Kiungo cha kuingia kimetumwa kwenye inbox yako. Kama hakifiki ndani ya dakika 3, hakikisha unakagua folda yako ya spam.", |
There was a problem hiding this comment.
Keep the new conditional meaning in this translation.
This value still reads like the old unconditional success message, so Swahili users would be told a login link was sent even when the backend intentionally sends nothing for unknown emails. Please update the translation to preserve the “If you have an account, …” wording from the source string.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/sw/portal.json` at line 111, The Swahili translation for
the source string "If you have an account, a login link has been sent to your
inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder."
lost the conditional "If you have an account" and now reads as an unconditional
statement; update the translation in the key that maps to that exact English
source string so it preserves the conditional phrasing (e.g., start with "Ikiwa
una akaunti, ..." and then convey the rest about the login link and checking
spam) while keeping the same timing/3-minute detail and tone.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Gelen kutuna bir giriş bağlantısı gönderildi. Eğer 3 dakika içinde ulaşmazsa spam klasörünü kontrol ettiğinden emin ol.", | ||
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "{submittedEmailOrInbox} adresinize bir ileti gönderildi. İleti içerisindeki bağlantıya tıklayın veya kodu aşağıya girin.", |
There was a problem hiding this comment.
Turkish translations are missing the conditional "If you have an account" prefix.
Both translations omit the critical "Hesabınız varsa, " (If you have an account,) prefix from the English keys:
- Line 111: Turkish says "A login link has been sent..." instead of "If you have an account, a login link has been sent..."
- Line 112: Turkish says "An email has been sent..." instead of "If you have an account, an email has been sent..."
This undermines the PR's security goal of not confirming whether an account exists. The conditional prefix is intentional to avoid leaking account existence information.
Suggested fix
- "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Gelen kutuna bir giriş bağlantısı gönderildi. Eğer 3 dakika içinde ulaşmazsa spam klasörünü kontrol ettiğinden emin ol.",
- "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "{submittedEmailOrInbox} adresinize bir ileti gönderildi. İleti içerisindeki bağlantıya tıklayın veya kodu aşağıya girin.",
+ "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Hesabınız varsa, gelen kutunuza bir giriş bağlantısı gönderildi. Eğer 3 dakika içinde ulaşmazsa spam klasörünü kontrol ettiğinizden emin olun.",
+ "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Hesabınız varsa, {submittedEmailOrInbox} adresinize bir ileti gönderildi. İleti içerisindeki bağlantıya tıklayın veya kodu aşağıya girin.",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Gelen kutuna bir giriş bağlantısı gönderildi. Eğer 3 dakika içinde ulaşmazsa spam klasörünü kontrol ettiğinden emin ol.", | |
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "{submittedEmailOrInbox} adresinize bir ileti gönderildi. İleti içerisindeki bağlantıya tıklayın veya kodu aşağıya girin.", | |
| "If you have an account, a login link has been sent to your inbox. If it doesn't arrive in 3 minutes, be sure to check your spam folder.": "Hesabınız varsa, gelen kutunuza bir giriş bağlantısı gönderildi. Eğer 3 dakika içinde ulaşmazsa spam klasörünü kontrol ettiğinizden emin olun.", | |
| "If you have an account, an email has been sent to {submittedEmailOrInbox}. Click the link inside or enter your code below.": "Hesabınız varsa, {submittedEmailOrInbox} adresinize bir ileti gönderildi. İleti içerisindeki bağlantıya tıklayın veya kodu aşağıya girin.", |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@ghost/i18n/locales/tr/portal.json` around lines 111 - 112, The Turkish
translations for the two keys matching the English source strings "If you have
an account, a login link has been sent to your inbox. If it doesn't arrive in 3
minutes, be sure to check your spam folder." and "If you have an account, an
email has been sent to {submittedEmailOrInbox}. Click the link inside or enter
your code below." are missing the conditional prefix; update the corresponding
values by prepending "Hesabınız varsa, " to each translation (ensure correct
punctuation and spacing, and keep the {submittedEmailOrInbox} placeholder intact
for the second string) so the messages do not leak account existence.
https://linear.app/ghost/issue/GVA-647/ The signin endpoint now returns a consistent 201 response regardless of whether the provided email matches an existing member. If no member is found, no email is sent. This aligns signin behavior with the existing signup flow.
The signin endpoint now returns a consistent 201 response regardless
of whether the provided email matches an existing member. If no member
is found, no email is sent. This aligns signin behavior with the
existing signup flow.