Skip to content
This repository has been archived by the owner on Jun 2, 2021. It is now read-only.

Translation/i18n of tags and product info #94

Open
cusspvz opened this issue Jun 30, 2017 · 15 comments
Open

Translation/i18n of tags and product info #94

cusspvz opened this issue Jun 30, 2017 · 15 comments
Labels
enhancement For issues that describe a feature that needs to be added, changed, or removed, but is not a bug

Comments

@cusspvz
Copy link

cusspvz commented Jun 30, 2017

Hey guys,

I was messing around with reaction for a little bit and it is awesome. I already knew it for a long time but you guys are taking it to a next level and thank you for that.

Inspite, I have a doubt on a feature, since I don't have completely sure if it is possible: Are the tags and product information supporting i18n / locales?

Just to let it clear, I was able to change the locale of the interface but I didn't found a way to internationalize tags and/or product info (such as title, description, etc).

If it's not possible, I'm willing to help and contribute on it. Thanks!

@spencern
Copy link

spencern commented Jul 5, 2017

Hi @cusspvz

Currently Reaction does not support locales or i18n for user generated content. Contributions would be very welcome.

@cusspvz
Copy link
Author

cusspvz commented Jul 17, 2017

I'm interested on developing it. Is there a way we can schedule a Skype talk to discuss a PR approach?

@aaronjudd
Copy link

@cusspvz we have public group video chats on a regular schedule, see: https://docs.reactioncommerce.com/reaction-docs/master/community-channels (core/components would be a good place to discuss..)

@aaronjudd
Copy link

This is actually part of a series of epics in the publishing workflow that are in progress.

Conceptually, I've been discussing supporting multiple languages for content, products by storing independent entries for each language in a normalized "catalog" collection. The translations process being handled via our publishing workflow, where the scope of the "Publish" button would trigger an event flow allowing translation packages (lingohub, yandex, gengo, transifex,etc) to return translated content, synchronously updating to the normalized catalog when translations completed.

@janat08
Copy link

janat08 commented Aug 16, 2017

I imagine #2641 may have to be reliable, if you were to let admin translate himself where app would need to register language change to reconfigure field bindings. I suppose google with it's AI is better translator.

@PolGuixe
Copy link

PolGuixe commented Oct 8, 2018

Any progress in this field? What is the current state?

@aldeed
Copy link

aldeed commented Jul 9, 2019

I'm going to move this to the feature request repo. I believe the current status is that this would be implemented as alternative catalogs, but further discussion would be needed.

@aldeed aldeed transferred this issue from reactioncommerce/reaction Jul 9, 2019
@aldeed aldeed added the enhancement For issues that describe a feature that needs to be added, changed, or removed, but is not a bug label May 1, 2020
@loan-laux
Copy link

Implementation guidance from @aldeed, copy/pasted for everyone to see:

I think you could follow the model we came up with for surcharge messages. Search “surcharges” plugin code for “messagesByLanguage” to get an idea. Basically store an array of language codes with message, and the GraphQL field should accept a language argument that causes the translated message to be returned.

On the update side, I think we’re just accepting and overwriting the whole array. Maybe there are some other pattern ideas that could make it easier to update for just one language.

Having a common pattern here will be key. That may allow different parts of the UI to reuse a single multi-language input component.

A good first step would be documenting the approach used for surcharge messages as a general spec and getting agreement / buy-in on that plan. Then it’s pretty easy to start implementing the spec in various plugins.

Hopefully this can be done in a backwards compatible way. I don’t even necessarily think a migration would be needed quite yet. Resolvers could check for translated strings in a new “ByLanguage” field with fallback to the old field name.

@loan-laux
Copy link

@aldeed Do we really want a language argument for each field? Why not just pass a language argument as part of the query parameters and automatically get all the fields translated?

I think it would be redundant and counter-productive for developers to have to specify the language for each translatable field. I don't think anyone will want to have a product's title in english but its description in french, for example... But I might be missing a possible use case here.

@aldeed
Copy link

aldeed commented May 15, 2020

@loan-laux It is not so much because we thought you might want different languages but because we originally tried having an argument at query/mutation level but then you had to do a bunch of transformation in each query and reimplement the same thing everywhere, which ended up being pretty inelegant and ugly.

For example, if there are 20 queries or mutations that return Product type, you would need to implement a language argument for each one, and do the language lookup in each one. But by putting the argument on the translated field itself, all 20 queries and mutations automatically get translation for free.

If I'm misunderstanding and you're proposing something else, let me know.

Another unrelated thought I had: you'll have to be careful about places where other plugins copy data from Product. For example, publishing copies title, description, etc. over to Catalog. And then Cart and Order items copy some of the CatalogProduct data. At each layer, you would either need to copy the by-language array as well, or at least resolve it to the shop default language. This can be done piece by piece since it really wouldn't be breaking. But it would have to be clear to anyone using this that, for example, the title will revert to shop default language when you add it to the cart.

@loan-laux
Copy link

loan-laux commented May 29, 2020

Okay so I've been diving a bit deeper into this and even wrote a quick POC implementation of @aldeed's proposed plan. I'm convinced that this is the way to go and I wanted to outline how I see this taking shape.

Querying translatable fields

Each GraphQL field that's translatable will accept a language argument on queries. Each field will be returned in the requested language, or will default to the shop's default language if a translation isn't available.

Screen Shot 2020-05-15 at 16 09 06

Screen Shot 2020-05-15 at 16 09 13

Saving and updating translatable fields

When creating or updating products, fieldByLanguage fields will be accepted and preferred, even though the old field fields will still be accepted for backwards compatibility. These fieldByLanguage fields are expected to be an array of objects, each containing a language and a content key, both strings.

Here's what that looks like for the field description, which now becomes descriptionByLanguage.

Screen Shot 2020-05-15 at 16 06 41

Setting a shop's supported languages

We need to have a way to know which languages are supported by each shop, so that language dropdowns don't show the whole list of languages but only the ones that are relevant. There also needs to be a default language selected for each shop.

In the UpdateShopInput and Shop GraphQL schemas, language: String would become defaultLanguage: String, and a new supportedSecondaryLanguages: [Language] would be added.

The Language type would look like this:

type Language {
  "The language code (i.e. 'en' or 'fr')"
  language: String

  "Whether the language should be visible to the public"
  isPublic: Boolean
}

The reason for the isPublic flag is that operators will probably want the ability to add a new language to their shop, but have the ability to fill in their translation fields before the language becomes visible to customers.

In this case, they would add the language as a supported language of the shop, they would update their product and tag informations to add the translations for this language, and they would update the language with isPublic: true when everything is ready for primetime.

When querying shop as a customer, the supportedSecondaryLanguages field would only return languages with isPublic: true.

What about the admin interface?

From the admin interface (whether that is reaction-admin or the new admin), I propose the following UX.

Language picker on product/tag forms

We would implement a language selector on all product and tag-related forms containing translatable fields. The dropdown would only list the languages that are listed as supportedSecondaryLanguages for the shop we're working on.

By default, the default shop language will be selected and the translatable fields will show the values for this language.

Screen Shot 2020-05-29 at 16 33 16

If the operator selects one of the supportedSecondaryLanguages, the translatable fields will show the values for the selected language, and their content in the default language will be shown as a label for reference.

Screen Shot 2020-05-29 at 18 08 28

Selecting supported secondary languages for shops

Under Settings > Shop Localization, we would add a new card with a table for managing supported secondary languages. This table would be inspired by the one we currently have under Settings > Taxes > Custom Tax Rates.

Screen Shot 2020-05-29 at 18 14 55

As it's currently done for the tax rates, we would have a modal to add/edit supported secondary languages and set their visibility.

Screen Shot 2020-05-29 at 18 18 40

@mikemurray since you're working on community contributions this week, what do you think of this approach? Is there anything you would change? If everything looks good, I've already started implementing it and I'll be glad to PR my work. Otherwise, happy to work together on finding a good alternative solution.

@aldeed
Copy link

aldeed commented Jun 2, 2020

@loan-laux Your design overall seems great. My gut says that "supported languages" is too vague of a concept for shops, though. It will mean something different to each person. And it's also probably not necessary for most Reaction installations other than marketplace because you'd usually just hard-code the lists into your UIs. So it feels like maybe it would live in more of a lightweight separate community plugin, and probably should be more specific about each place in the UI rather than just the word "supported". Could be adminProductEditorLanguages, storefrontLanguages, etc. all separate lists, and then you don't need "public" designation either.

Either way I don't think gql mutations should validate against the list for ByLanguage updates. They should allow only valid languages (based on the list in api-utils) but no further validation by shop "allowed" list.

@loan-laux
Copy link

Gotcha @aldeed. Will implement following your guidance.

@karbal
Copy link

karbal commented May 14, 2021

@aldeed I think all plugins can use the locale, so why not pass it in the header with authorization and maybe overwrite when passing it in the query/mutation.

@aldeed
Copy link

aldeed commented May 17, 2021

@karbal In general it is not a good pattern to spread data in multiple places. If a mutation or query needs locale info, it can use normal GQL fields to ask for it. This is easier to document and easier to understand IMO.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement For issues that describe a feature that needs to be added, changed, or removed, but is not a bug
Projects
None yet
Development

No branches or pull requests

8 participants