Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to manage i18n resource with API / JSON-LD / Hydra ? #127

Closed
MLKiiwy opened this issue Jun 18, 2015 · 11 comments
Closed

How to manage i18n resource with API / JSON-LD / Hydra ? #127

MLKiiwy opened this issue Jun 18, 2015 · 11 comments

Comments

@MLKiiwy
Copy link
Contributor

MLKiiwy commented Jun 18, 2015

Imagine you have a "Country" (http://schema.org/Country) resource in your API.
How to manage i18N on it ?

Here is a detailed solution, i have design based on experience, and the JSON-LD spec.
Tell me if you think this is a good idea ?
If you think it's not ... tell me why ?

How to get a specific locale on a resource ? (=GET)

My solution

Add a GET specific parameter "locale"
Why ?

  • Simple (this is the way used in FB graph api for example)
  • One URL = One localized resource (like wikipedia, better for indexing or caching)
  • use of @language specified in JSON-LD spec
  • use @container:@language

Sample 1 : No locale specified

GET http://api.example.com/countries/1

{
  "@context": {
    "@base" : "http://schema.org",
    "name" : {
      "@container": "@language"
    }
  },
  "@type": "Country",
  "@id": "/countries/1",
  "name": {
    "fr-FR" : "Angleterre",
    "en" : "England"
  }
}

=> Will return resource with all locale data

Sample 2 : Use specific localization

GET http://api.example.com/countries/1?locale=fr-FR

{
  "@context": "http://schema.org",
  "@type": "Country",
  "@id": "/countries/1",
  "@language": "fr-FR",
  "name": "Angleterre"
}

=> Will return resource with requested locale

Note we use locale (on request + response) in W3C format (IETF's BCP 47), see http://www.w3.org/International/articles/language-tags/
It's the format used also with JSON-LD.

Sample 3 : Error localization don't exist

GET http://api.example.com/countries/1?locale=es-CA

{
  "@context": "/contexts/LocalizationError",
  "@type": "LocalizationError",
  "hydra:title": "An error occurred",
  "hydra:description": "no localization found for locale es-CA"
}

=> Will return code "404 not found", because es-CA localization don't exist in my api.

How to get a specific locale on a list of resource ? (=GET)

My solution :

same as for one resource

Sample 1 : No locale specified

GET http://api.example.com/countries

{
  "@context": {
    "@base" : "http://schema.org",
    "name" : {
      "@container": "@language"
    }
  },
  "@id": "/countries",
  "@type": "hydra:PagedCollection",
  "hydra:totalItems": 1,
  "hydra:itemsPerPage": 3,
  "hydra:firstPage": "/countries",
  "hydra:lastPage": "/countries",
  "hydra:member": [
    {
      "@type": "Country",
      "@id": "/countries/1",
      "name": {
        "fr-FR" : "Angleterre",
        "en" : "England"
      }
    }
  ]
}

=> Will return resources with all available localization

Sample 2 : Use specific localization

GET http://api.example.com/countries?locale=fr-FR

{
  "@context": "http://schema.org",
  "@id": "/countries",
  "@type": "hydra:PagedCollection",
  "@language": "fr-FR",
  "hydra:totalItems": 1,
  "hydra:itemsPerPage": 3,
  "hydra:firstPage": "/countries",
  "hydra:lastPage": "/countries",
  "hydra:member": [
    {
      "@type": "Country",
      "@id": "/countries/1",
      "name": "Angleterre"
    }
  ]
}

=> Will return resource with requested locale

Sample 3 : Error localization don't exist

GET http://api.example.com/countries?locale=es-CA

{
  "@context": "http://schema.org",
  "@id": "/countries",
  "@type": "hydra:PagedCollection",
  "@language": "es-CA",
  "hydra:totalItems": 0,
  "hydra:itemsPerPage": 3,
  "hydra:firstPage": "/countries",
  "hydra:lastPage": "/countries",
  "hydra:member": []
}

How to delete a localized resource ? (=DELETE)

My solution :

same as usual but the localization are also deleted completely

DELETE http://api.example.com/countries/1
=> Will delete country and all associed localization

DELETE http://api.example.com/countries/1?locale=fr-FR
=> Will delete country localization fr-FR only !

How to create a localized resource ? (POST)

My solution :

create with a locale container or indicate the language in context

POST http://api.example.com/countries

{
    "name": {
        "fr-FR" : "Angleterre",
        "en": "England"
    }
}

=> Will create country with two localized value

OR

POST http://api.example.com/countries

{
    "@context": {
        "@language": "fr-FR"
    },
    "name": "Angleterre"
}

=> Will create country with one localized value

How to add a new locale to a localized resource ? (PUT)

My solution :

same as POST, you must specified @language or put all localized data

PUT http://api.example.com/countries/1

{
    "@context" : {
        "@language": "it"
    },
    "name": "Inghilterra"
}

=> Will add or replace locale "it" name for the resource /countries/1

PUT http://api.example.com/countries/1

{
    "name": {
        "fr" : "Angleterre"
    }
}

=> Will delete all localization for name and just have fr localization

How to list all available locale for a resource ?

My solution :

add a specific endpoint to api like :

GET http://api.example.com/countries/1/locales

{
  "@context": "http://schema.org",
  "@id": "/http://api.example.com/countries/1/locales",
  "@type": "hydra:PagedCollection",
  "hydra:totalItems": 2,
  "hydra:itemsPerPage": 3,
  "hydra:firstPage": "/countries",
  "hydra:lastPage": "/countries",
  "hydra:member": [
    {
      "@type": "Locale",
      "@id": "/locale/fr"
    },
    {
      "@type": "Locale",
      "@id": "/locale/en"
    }
  ]
}

=> Will return all available locale for the resource

For the "dev" part :

  • create specific normalizer/denormalizer to manage @language in JSON-LD
  • implements an Interface : LocalizedEntity
  • Create a LocalizedResourceController to manage ?locale param and /locales endpoint
@dunglas
Copy link
Member

dunglas commented Jun 18, 2015

Wow, nice work on that topic! It looks good!

There is just one thing that hurts me: a resource is represented by an URL, so a translation is not a resource by itself but just a part of a resource. So what about issuing a PUT request to remove a lang but not the whole resource as it's just the modification of an existing resource?

3 other small questions:

  • How the language support will be described in the Hydra vocab?
  • Is an integration with DoctrineExtensions / DoctrineExtensionsBundle planned? How they will fit together?
  • What do you think about sending a mail on the Hydra or JSON-LD mailing-list to be sure that everything is OK from a spec point of view?

Cannot wait to see the code 😅

@MLKiiwy
Copy link
Contributor Author

MLKiiwy commented Jun 19, 2015

Yeah, it's a good point of view for the PUT section.

Maybe to remove a translation use DELETE with a new endpoint ? Like the last point.

  • How the language support will be described in the Hydra vocab?

I don't know, it's a real interrogation for me ...

  • Is an integration with DoctrineExtensions / DoctrineExtensionsBundle planned? How they will fit together?

I think the base dev must be independant of these bundle. But we must propose an implementation to use these bundle quickly and simply.

  • What do you think about sending a mail on the Hydra or JSON-LD mailing-list to be sure that everything is OK from a spec point of view?

Good idea, but where is the M-L ?

@MLKiiwy
Copy link
Contributor Author

MLKiiwy commented Jun 19, 2015

I study another possibility to provide the i18n support on a resource.
To add a collection of translation when needed.

For example :

GET http://api.example.com/countries/1?locale=fr-FR

{
  "@context": "http://schema.org",
  "@type": "Country",
  "@id": "/countries/1",
  "@language": "fr-FR",
  "nonLocalizedAttribute": 10,
  "localization": {
    "@type": "CountryLocalization",
    "@id": "/country_localization/1/fr-FR",
    "name": "Angleterre"
  }
}

GET http://api.example.com/countries/1

{
  "@context": "http://schema.org",
  "@type": "Country",
  "@id": "/countries/1",
  "nonLocalizedAttribute": 10,
  "localizations":{ 
     "en": {
         "@type": "CountryLocalization",
         "@id": "/country_localization/1/fr-FR",
         "name": "Angleterre"
      },
     "fr-FR": {
         "@type": "CountryLocalization",
         "@id": "/country_localization/1/fr-FR",
         "name": "England"
      }
}
}

This way he simpler for many reasons, but I think it's not very JSON-LD / Hydra compliant.
It's simpler because :

  • you cut the "localized" part of the resource into separate resource, wich can be managed like other resources.
  • "Like the DB storage"

It's not JSON-LD / Hydra compliant because :

  • you change structure of object ( localization / localizations attribute is dynamical ... ), you cannot use schema.org vocabulary because of that

What do you think about this ?

@MLKiiwy
Copy link
Contributor Author

MLKiiwy commented Jun 19, 2015

@dunglas if you want to view, here is my work but still in dev : https://github.com/MLKiiwy/DunglasApiBundle/tree/tdd-i18n-support

@dunglas
Copy link
Member

dunglas commented Jun 22, 2015

Nice to see progress on that :)

I prefer to keep with the standard: it's the only way to be interoperable with other systems (client-side JSON-LD / Hydra libraries, search engines...).

Maybe the best thing to do is to create thread on the Hydra working group about that. You can register to the mailing list on the Hydra website (you just need a W3C account): http://www.hydra-cg.com/

@nicolasricci
Copy link

@MLKiiwy very interesting approach to handle localized content.
@dunglas is there any plan to include this enhancement in the bundle?

@StephenOTT
Copy link

Any further progress on this?

@Simperfit
Copy link
Contributor

@MLKiiwy have you gone further with this ?

@MLKiiwy
Copy link
Contributor Author

MLKiiwy commented Jun 14, 2017

No sorry, I stop my development on this part because I don't need it anymore :/ but the solution is still valid but must be implement in the new version of api-platform core. maybe as a plugin ...

@dkarlovi
Copy link
Contributor

Is this the "front line" regarding API Platform and I18N or am I missing something somewhere?

@MLKiiwy
Copy link
Contributor Author

MLKiiwy commented Nov 20, 2017

No it was an old subject. I will close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants