-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Description
What is JSON-LD?
JSON-LD stands for “JSON for Linking Data”. It’s developed by W3C and used to build interoperable Web services.
JSON-LD 1.1 provides a non-normative specification for string internationalisation.
JSON-LD is meant to be used in the server responses, providing data that can be processed and normalised with JSON-LD processor, which behaviour can be explored further using JSON-LD Playground.
How can JSON-LD be used for internationalisation?
JSON-LD internationalisation support can be applied to the whole document, or to specific fields only. JSON-LD processor will normalise both the internationalised fields and the non-internationalised fields:
- Field
jobTitle
is set to be in the en language - After processing,
jobTitle
field is a list of maps, each map containing the information of the language and the translated value - For the non-internationalised fields like name, they will be processed similarly, containing a list of maps, each map containing the value, but no language data, as it’s not specified in the context
The way JSON-LD processor works allows us to add more translations for a given field without sacrificing backwards compatibility, by using @container
in the context:
- By setting
@container
as@language
forjobTitle
field, we tell the processor thatjobTitle
field will be a map, containing translated values indexed by the language. jobTitle
changes its form from just a simple string in a previous example to a map mentioned above- Even though
jobTitle
structure has changed, the processed JSON-LD returns a backwards-compatible structure.jobTitle
field is still a list containing a map of the language to the translated value, but containing two elements now.
Could we apply JSON-LD i18n to the existing structure?
TL;DR: No.
Having translations as a map of languages to a map of translations is not compatible with JSON-LD specification.
How to determine which languages to include in the response?
To prevent overfetching, improve the performance and maintain consistent behaviour across our existing store frontend and Shop API, it is required to define a clear way to determine which languages should be included in the server response.
Some inspiration can be found in Locastic/ApiPlatformTranslationBundle and Accept-Language header spec.
I propose to use Accept-Language header and extend its usage to a GET parameter if needed. Accept-Language header accepts either a list of accepted languages or *
as a wildcard for all of them:
- If we get a single language like
en
- return translations only for this language - If we get a list like
en, pl, de
- return translations in those three languages OR preferen
and fallback topl
and then tode
- If we get
*
- return all the possible translations
If the request is made in shop context (eg. user is not logged in / logged in as a shop user), we should filter out the list of languages using the list of languages defined on the channel, accepting only the ones existing in both of those lists.
Okay, what about requests to the server: POST/PUT/PATCH?
It’s time for things to get trickier - setting translations while adding a new translatable resource or updating one.
In the current implementation, the responses from GET requests are almost symmetrical to the payload for POST/PUT requests. If the GET response gets to conform with JSON-LD internationalisation, this would no longer be the case. However, there are two main schema designs to explore:
Translations as the main container for any translatable value
This solution is the same as the currently used - all the translatable data is stored in the translations field, all the non-translatable data is stored at the root level.
{
"code": "JOHN_SMITH",
"translations": {
"en": {
"name": "John Smith",
"title": "Blackmith"
},
"pl": {
"name": "Jan Kowalski",
"title": "Kowal"
}
}
}
Translations embedded in every translatable field
This solution is more similar to the JSON-LD one, with language maps embedded for translatable properties, next to non-translatable ones.
{
"code": "JOHN_SMITH",
"name": {
"en": "John Smith",
"pl": "Jan Kowalski"
},
"title": {
"en": "Blacksmith",
"pl": "Kowal"
}
}
Conclusion?
Further R&D work is needed to define the input schema in our API. JSON-LD looks like a good solution for the output schema in our API.
PoC needs to be made to make sure there are no hidden blocking issues. Collaboration with the API Platform team could be a way to explore more possible solutions, as well as to get some advice regarding the implementation details.
References
- JSON-LD 1.1 specification: https://www.w3.org/TR/json-ld11/
- JSON-LD Playground (live processor): https://json-ld.org/playground/
- JSON-LD benefits & introduction: https://rollout.io/blog/json-ld-building-meaningful-data-apis/
- JSON-LD for developers (practical info): https://datalanguage.com/blog/publishing-json-ld-for-developers
- JSON-LD origin story & critique: http://manu.sporny.org/2014/json-ld-origins-2/