reaction-component-library icon indicating copy to clipboard operation
reaction-component-library copied to clipboard

No i18n support: components should provide an object with Labels as props

Open janus-reith opened this issue 5 years ago • 23 comments

Some components render localized text, but provide no way to alter it outside of the component. Example: https://github.com/reactioncommerce/reaction-component-library/blob/33651f18c8dae7333fb3a019ac6bb878657c70fe/package/src/components/CartSummary/v1/CartSummary.js#L196

The component library should not be responsible for i18n itself. It could accept an object with labels as props, in a similar manner compnents are passed and overrriden. The current strings could serve as fallback.

janus-reith avatar Apr 12 '19 10:04 janus-reith

This is a known deficiency that will eventually have a solution. The workaround in the meantime is to override the entire component using the components context, providing a version of it that you've modified to use whatever i18n solution your app uses.

aldeed avatar Apr 12 '19 20:04 aldeed

Yes, that would work in the meantime, thank you. Would you accept PRs that would allow passing own strings(so still i18n-library-agnostic), or does this need further internal discussion?

janus-reith avatar Apr 16 '19 08:04 janus-reith

@nnnnat Any thoughts here? Some components already accept label overrides (e.g., otherAddressLabel prop on AddressChoice). I think it makes sense to accept PRs that do this same thing for other components that have English text built into them. It's the simplest way to support translations without buying into any particular framework.

aldeed avatar Apr 16 '19 17:04 aldeed

Can labels be added for this issue? I think its a fairly easy starting issue.

HarisSpahija avatar Oct 01 '19 10:10 HarisSpahija

Hey, this issue doesn't seem to get a lot of traction. When it comes to components every single component that has text would need to get an extra prop for translation. Is there any possibilty where we can slowly tackle this issue by doing components in batches? Also, could I be assigned to this issue? We already did a big part when it comes to translations in our component library.

HarisSpahija avatar Oct 16 '19 09:10 HarisSpahija

Did you guys ever make any progress on this issue @nnnnat @aldeed ?

HarisSpahija avatar Oct 16 '19 09:10 HarisSpahija

@HarisSpahija please feel free to create PRs to this repo that add label overrides for component text. We'd prefer 1 component per PR and not in batches just to keep reviews on our side shorter.

nnnnat avatar Oct 16 '19 18:10 nnnnat

@nnnnat could you check if the current PR's are viable to be implemented?

HarisSpahija avatar Oct 28 '19 15:10 HarisSpahija

@HarisSpahija I approved PRs. One needs a small change. Someone with ability to override the snyk checks will have to merge them, or you can merge master into them after the Snyk-related PRs have been merged.

aldeed avatar Nov 13 '19 03:11 aldeed

Some components have strings that are possibly gramatically different in other languages. For example:

<StockWarning />

return <Span className={className}>Only {inventoryQuantity} in stock</Span>;

In Dutch one would say "Slechts 7 op voorraad", while in Bosnian you could say: "7 Na Lageru". Grammar should be counted in when implementing i18next.

HarisSpahijaPon avatar Nov 21 '19 12:11 HarisSpahijaPon

All components should have translation options now with a couple of exceptions. @janus-reith we could move to adding i18n to example-storefront now

HarisSpahijaPon avatar Nov 21 '19 13:11 HarisSpahijaPon

@HarisSpahijaPon For those that need interpolation, you can update to take a fn prop instead.

// default props
getLowStockText: (data) => `Only ${data.inventoryQuantity} in stock`

const { getLowStockText } = this.props;

return <Span className={className}>{getLowStockText({ inventoryQuantity })}</Span>;

When using in translated app, you'd pass through to i18next in the function prop:

getLowStockText={(data) => i18next.t("lowStockText", data)}

And your translation file would have "Only {{inventoryQuantity}} in stock" as the English value, for example.

See https://www.i18next.com/translation-function/interpolation

aldeed avatar Nov 26 '19 21:11 aldeed

okay thanks! I will update them @aldeed

HarisSpahijaPon avatar Nov 27 '19 09:11 HarisSpahijaPon

I think pretty much all components except the interpolation items have been set now. Is it time to implement a basic example to the storefront for i18n?

@janus-reith , would you be interested in helping with this issue? I am not sure what exactly is needed to make a sufficient example for users to test. Would be cool if we can implement it before 3.0 release.

HarisSpahijaPon avatar Nov 29 '19 19:11 HarisSpahijaPon

@HarisSpahijaPon Great work, sure we can collaborate on this.

janus-reith avatar Nov 30 '19 14:11 janus-reith

Hey guys @HarisSpahijaPon @janus-reith , I'm also interested in collaborating on this, please let me know how i can help.

CristianCucunuba avatar Dec 04 '19 23:12 CristianCucunuba

@CristianCucunuba Id say check out this issue: https://github.com/reactioncommerce/example-storefront/issues/524

You could fork the master branch and create an example using the new label props to show translations. I think its best if we start with one component and one language. Preferably English.

Also there are still some PR's open with some labels needing to be adjusted. Feel free to continue with my PR.

HarisSpahija avatar Dec 09 '19 09:12 HarisSpahija

I noticed that some components are using other components from the component library. Components such as MiniCart make it so labels cannot be passed to MiniCartSummary without either overriding componentContext or passing props from the parent. For example:

 <MiniCartSummary displaySubtotal={summary.itemTotal.displayAmount} />

Can be translated with the override labels

 <MiniCartSummary displaySubtotal={summary.itemTotal.displayAmount} checkoutButtonText={"test"} footerMessageText={"test"}/>

Because the component is nested there is no way we can reach the override labels. This should be fixed in the component library or an extra props should be added to pass nested props.

What do you think would be the right approach to this @aldeed ?

HarisSpahija avatar Dec 09 '19 13:12 HarisSpahija

@HarisSpahija I tend to prefer specific props like miniCartSummaryCheckoutButtonText, etc. which are passed down. This allows specific prop validation whereas a miniCartSummaryProps prop opens the door to hundreds of potential combinations that would need to be tested and supported.

That said, I don't know that Reaction has a specific policy on this. @mikemurray or @nnnnat may have more to say.

It's not quite correct to say there's no way to do it, though. If you use the components context to inject translations for MiniCartSummary (and all components), which would be the best and recommended way, then it will be translated wherever it is used without any need for passing down props. That's really the main reason why this package supports a component context: ability to override nested components.

aldeed avatar Dec 09 '19 20:12 aldeed

I tried setting an override in component context, but I couldnt get the syntax to work without sideffects. Could you elaborate how to do this with an example?

HarisSpahija avatar Dec 10 '19 00:12 HarisSpahija

@HarisSpahija I didn't test this, but it should work as long as you provide a component (e.g. a function that returns JSX).

{
  MiniCartSummary: (props) => <MiniCartSummary checkoutButtonText={i18next.t("MiniCartSummary.checkoutButtonText")} footerMessageText={i18next.t("MiniCartSummary.footerMessageText")} {...props} />
}

You'd have to make a slightly more complicated component that uses useTranslation hook to get a properly reactive version of i18next.t function, but this is the general idea.

aldeed avatar Dec 10 '19 17:12 aldeed

Some components require some references or not every component is listed in the componentContext file, we should refactor those to make it easier for developers to override the components.

HarisSpahijaPon avatar Jan 14 '20 11:01 HarisSpahijaPon

Agree that no components should directly import any other components unless there's clearly no use case for overriding it. Submitting individual GH issues for each case of that would be best.

aldeed avatar Jan 14 '20 17:01 aldeed