Problem/Motivation
Currently the /related/ endpoints (/jsonapi/node/{id}/{field}) only pass their target entities through the swapped access checker. That leaves two gaps:
No strict negotiation. A related target with no translation in an accepted language silently falls back to the untranslated entity, instead of a strict miss. The client asked for a language it accepts; it receives one it did not, unlabelled.
Language cache poisoning. The related response does not declare the response-level headers (Accept-Language cache context). Because of that, a cold no-selector response is stored by the Dynamic Page Cache without language variance and served to a later Accept-Language request for the same URL.
Steps to reproduce
A translatable content type with a to-one entity reference field; source node A references target C, where C has en + fr translations (no de). Uninstall the Internal Page Cache to isolate this, leaving the Dynamic Page Cache on.
-
GET /jsonapi/node/{A}/{field} with Accept-Language: fr.
Expected: C in fr.
Actual: C in en (fallback / a cached default). -
GET … with Accept-Language: de.
Expected: 406 Not Acceptable.
Actual: C in en (silent fallback). -
GET … with ?langCode=de.
Expected: 404 Not Found.
Actual: C in en. -
GET … with no header (warms the cache), then GET … with Accept-Language: fr.
Actual: the second request is served the cached default (en).
Proposed resolution
Issue fork jsonapi_multilingual-3612537
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #2
lauriiiComment #3
lauriiiComment #6
lauriii