restmultilingualhateoas

How to use HATEOAS with localization


For a client to get a resource in a specific language over HTTP I see the following technical implementations for the API:

  1. Query Parameter
  2. Accept-Language Header
  3. URI path segment (e.g. /en/, /de/)
  4. Accept Header and various representation types
  5. Cookie
  6. User preferences stored on the server

The stackoverflow post Multi-lingual REST resources - URL naming suggestions discusses some of the above options.

If the translations are considered a representations of the resource and therefore the recommended Accept-Language header is used I wonder how can this work with HATEOAS?

I can't add the header to the URI. My understanding is that the client should not construct URIs when HATEOAS is used. But this means that there is no option to use header information, like Accept-Language or Accept Header. Is there something I miss or didn't understand correctly?

I wanted to use only the Accept-Language header, but I only can see two option to support HATEOAS in the JSON response to list the links to the available languages: query parameter and URI path segment. E.g.

{
  "className": "Swing Dancing",
  "description": "Learn to dance Lindy Hop for beginners.",
  language": "en",
  "_links": {
    "lang-de": "/classes/5/?lang=de",
    "lang-fr": "/classes/5/fr"
  }
}

Our application supports multi-language for each supported field of a resource. E.g a class can have a title stored only in one language (e.g. English) and the description in multiple languages. It solely depends on the translations the users of the system have entered. The best match for each field according to the user request is returned. E.g. prefered languages in order "FR, DE, EN", Then the result would look like this:

{
  "className": {
    "value": "Swing Dancing",
    "language": "en"
  }
  "description": {
    "value": "Lerne Lindy Hop für Anfänger.",
    "language": "de"
  }
}

Since the class name in the example is only stored in English it is returned in English even when English is not a preference of the user.

My proposed implementation is to support the following options in this order:

  1. Query Parameter
  2. Accept-Language Header
  3. User preferences stored on the server
  4. Application default

If a query parameter is provided it is used first. This allowes fetching a specific language e.g. for staff to edit the content. Supporting the query parameter also allows to use HATEOAS in the response.

Next the Accept-Language is checked. If both contain no information the user preferences are loaded. If the user have no preferences the application default is used.

REST calls should be stateless. I'm unsure about the user preferences. They are not session information and only a constant preference that is fetched using the passed userId. Would that still conform to the REST specification?


Solution

  • I can't add the header to the URI. My understanding is that the client should not construct URIs when HATEOAS is used. But this means that there is no option to use header information, like Accept-Language or Accept Header. Is there something I miss or didn't understand correctly?

    Values for the Accept-Language field, like values for the Accept field, would normally be part of the configuration of the user agent, rather than something we attempt to control via the representations of the resources. See RFC 9110

    Since intelligibility is highly dependent on the individual user, user agents need to allow user control over the linguistic preference (either through configuration of the user agent itself or by defaulting to a user controllable system setting). A user agent that does not provide such control to the user MUST NOT send an Accept-Language header field.


    Roy Fielding, writing in 2006:

    The sites that I produce always separate languages into separate URI trees. Day Software's Communiqué product specializes in multilingual sites and defaults to separate trees.

    In his example

    http://www.day.com/
    

    redirects to the appropriate index...

    http://www.day.com/site/en/index.html
    http://www.day.com/site/de/index.html
    

    Of course, you might reasonably prefer reactive negotiation to proactive negotiation. See RFC 9110.


    The machines don't care if you use path segments or the query part to distinguish a resource that expresses its representations in one language from another.

    The usual constraints do apply: query parameters are more convenient for HTML forms, path parameters are more convenient when you want to leverage relative resolution. If you care to put in the extra work, it's fine to have a supported spelling redirect to the preferred spelling.


    If we want to communicate to the client the language of the resulting representation of a resource, the most straight forward standardized solution is probably an RFC 8288 hreflang parameter paired with an RFC 5646 Language Tag.

    (A quick review of the registered link relations offers alternate as a possible candidate for the relation itself. Probably reasonable, but I'm not confident that it is necessarily "best".)


    To understand the header use better I have a follow up question: The users preferred languages are send via the header. If the user wants to see a resource in a specific language that has not the highest priority or is not in the list of preferences should the client app send a different Accept-Language header for that request or should a query parameter/uri path be used instead?

    If you are trying to keep things simple for yourself: design your resource model with separate resources for each language; include in the representation of each resource links to the parallel resources in the other languages.

    And yes, if your DE representation of the information is a resource with mostly DE representation but an EN title, that's fine (from the perspective of HTTP, which really only cares about the moving-documents-around-the-network bit).

    In the advanced version, extend the simple resource model with additional resources that have multiple representations, with links all around.