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

feat: i18nify SDK integrated for Amount component #2003

Merged
merged 18 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/purple-flies-end.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
'@razorpay/blade': minor
---

**feat: Added internationalization in Amount component via i18nify.
References**

- **i18nify-js:** https://www.npmjs.com/package/@razorpay/i18nify-js
- **i18nify-react:** https://www.npmjs.com/package/@razorpay/i18nify-react

**What changes ?**

1. The `<Amount />` component will now automatically format numbers based on the user's browser locale. For example, `<Amount value={123456.789} currency="INR">` will render `₹1,23,456.79` for browsers with the `en-IN` default locale, whereas it will render `₹123,456.79` for browsers with the `en-US` locale.

2. If you want to enable users to change the locale of your page, add the `@razorpay/i18nify-react` package and wrap your app inside the `I18nProvider`. Utilize the `setI18nState` utility to modify the locale. For more details, please refer to the [documentation](https://www.npmjs.com/package/@razorpay/i18nify-react).

3. Additionally, if you prefer to maintain a fixed locale for your page and amount component, enclose your app within `<I18nProvider initData={{locale: 'locale-you-want'}}>..`. For more details, please refer to the [documentation](https://www.npmjs.com/package/@razorpay/i18nify-react).

**How to update ?**
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shall also update the installation guide with installation of i18nify. its located at packages/blade/docs/guides/Installation.stories.mdx

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I was planning to send this in a separate PR, but we can incorporate these changes into this one.
I'll need your assist to finalize the content and format for inclusion here. @kamleshchandnani

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes please add it in this PR itself because everything is related to Amount in this context. Let me know what exactly do you need help with?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated.


1. Install i18nify as dependency `yarn add @razorpay/i18nify-js`
2. _[Optional]_: Install i18nify-react as dependency to manage state effectively `yarn add @razorpay/i18nify-react`
3. Install latest Blade `yarn add @razorpay/blade@latest`
83 changes: 49 additions & 34 deletions packages/blade/docs/guides/Installation.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,47 +40,62 @@ Before you install the package, make sure that you have performed the following

## ⬇ Add blade to your application

1. Install blade as a dependency.
Blade has a peer dependency on a few libraries, you can skip adding it if you already have it installed in your project.
1. Install blade as a dependency.
Blade has a peer dependency on a few libraries, you can skip adding it if you already have it installed in your project.

- `styled-components`
- `styled-components`
> **Note**
>
> Currently, blade only supports styled-components v5 only

```shell
yarn add @razorpay/blade styled-components@5.3.11
```
2. Follow [this guide](#-install-fonts) to install the fonts.
```shell
yarn add @razorpay/blade styled-components@5.3.11
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this shell block before styled components and put all the dependencies including i18nify in one shell block itself as we have done in React native section below and then you can use bullt points to describe all the dependencies together

Copy link
Contributor Author

@tarun-khanna tarun-khanna Feb 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done
Screenshot 2024-02-12 at 3 02 54 PM

```

3. For **React Native** projects you need to do additional setup for the peer dependencies:
- `@razorpay/i18nify-js`
- Blade uses this library for formatting capabilities in [Amount](https://blade.razorpay.com/?path=/docs/components-amount--docs) and other components based on the locale. Follow [this guide](https://www.npmjs.com/package/@razorpay/i18nify-js) to install it.

```shell
yarn add @floating-ui/react-native@0.10.0 react-native-reanimated@3.4.1 react-native-tab-view@3.5.2 react-native-pager-view@6.2.1 react-native-svg@12.3.0 react-native-gesture-handler@2.9.0 @gorhom/bottom-sheet@4.4.6 @gorhom/portal@1.0.1
```
```shell
yarn add @razorpay/i18nify-js
```

- `react-native-reanimated`
- Follow [this guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation) to install it on Android & iOS which is required by Blade.
- `react-native-svg`
- Follow [this guide](https://github.com/react-native-svg/react-native-svg#with-react-native-cli) to install it on Android & iOS which is required by Blade.
- `react-native-gesture-handler`
- Follow [this guide](https://docs.swmansion.com/react-native-gesture-handler/docs/installation) to install it, note that you don't need to add `<GestureHandlerRootView style={{ flex: 1 }}>` again on the root because BladeProvider already adds that out of the box.
- `@gorhom/bottom-sheet`
- Add this as peer dependency, no need to do additional setup since BladeProvider already sets everything up.
- `@gorhom/portal`
- Add this as peer dependency, no need to do additional setup since BladeProvider already sets everything up.
- `@floating-ui/react-native`
- Add this as peer dependency, no need to do additional setup.
- `react-native-tab-view`
- Add this as peer dependency, no need to do additional setup. This is needed for react-native Tabs component as per [this guide](https://reactnavigation.org/docs/tab-view/#installation).
- `react-native-pager-view`
- Add this as peer dependency, no need to do additional setup. This is needed for react-native Tabs component as per [this guide](https://reactnavigation.org/docs/tab-view/#installation).

And finally run `pod install` command so that blade's RN dependencies are linked to your project:

```shell
cd ios && pod install
```
- `@razorpay/i18nify-react`
- A state management React wrapper for `@razorpay/i18nify-js` that maintains locale state of your page. Follow [this guide](https://www.npmjs.com/package/@razorpay/i18nify-react) to configure and install it.

```shell
yarn add @razorpay/i18nify-react
```

2. Follow [this guide](#-install-fonts) to install the fonts.

3. For **React Native** projects you need to do additional setup for the peer dependencies:

```shell
yarn add @floating-ui/react-native@0.10.0 react-native-reanimated@3.4.1 react-native-tab-view@3.5.2 react-native-pager-view@6.2.1 react-native-svg@12.3.0 react-native-gesture-handler@2.9.0 @gorhom/bottom-sheet@4.4.6 @gorhom/portal@1.0.1
```

- `react-native-reanimated`
- Follow [this guide](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation) to install it on Android & iOS which is required by Blade.
- `react-native-svg`
- Follow [this guide](https://github.com/react-native-svg/react-native-svg#with-react-native-cli) to install it on Android & iOS which is required by Blade.
- `react-native-gesture-handler`
- Follow [this guide](https://docs.swmansion.com/react-native-gesture-handler/docs/installation) to install it, note that you don't need to add `<GestureHandlerRootView style={{ flex: 1 }}>` again on the root because BladeProvider already adds that out of the box.
- `@gorhom/bottom-sheet`
- Add this as peer dependency, no need to do additional setup since BladeProvider already sets everything up.
- `@gorhom/portal`
- Add this as peer dependency, no need to do additional setup since BladeProvider already sets everything up.
- `@floating-ui/react-native`
- Add this as peer dependency, no need to do additional setup.
- `react-native-tab-view`
- Add this as peer dependency, no need to do additional setup. This is needed for react-native Tabs component as per [this guide](https://reactnavigation.org/docs/tab-view/#installation).
- `react-native-pager-view`
- Add this as peer dependency, no need to do additional setup. This is needed for react-native Tabs component as per [this guide](https://reactnavigation.org/docs/tab-view/#installation).

And finally run `pod install` command so that blade's RN dependencies are linked to your project:

```shell
cd ios && pod install
```

## 🔜 Add blade libraries to your Figma project

Expand Down Expand Up @@ -162,4 +177,4 @@ We use 2 fonts. [TASA Orbiter](https://tasatype.localremote.co/) (for our headin
ReactFontManager.getInstance().addCustomFont(this, "TASA Orbiter Display", R.font.tasa);
// rest of the content of the method
}
```
```
7 changes: 5 additions & 2 deletions packages/blade/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,9 @@
"typescript": "4.9",
"typescript-transform-paths": "3.4.6",
"@types/body-scroll-lock": "3.1.0",
"ramda": "0.29.1"
"ramda": "0.29.1",
"@razorpay/i18nify-js": "1.4.0",
"@razorpay/i18nify-react": "4.0.0"
},
"peerDependencies": {
"react": ">=18",
Expand All @@ -283,7 +285,8 @@
"react-native-svg": "^12.3.0",
"react-native-gesture-handler": "^2.9.0",
"@gorhom/bottom-sheet": "^4.4.6",
"@gorhom/portal": "^1.0.14"
"@gorhom/portal": "^1.0.14",
"@razorpay/i18nify-js": "^1.4.0"
},
"peerDependenciesMeta": {
"react-native": {
Expand Down
124 changes: 121 additions & 3 deletions packages/blade/src/components/Amount/Amount.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
import type { StoryFn, Meta } from '@storybook/react';
import { Title } from '@storybook/addon-docs';
import { getCurrencyList } from '@razorpay/i18nify-js/currency';
import { I18nProvider, useI18nContext } from '@razorpay/i18nify-react';
import { useState } from 'react';
import type { AmountProps } from './Amount';
import { Amount as AmountComponent } from './Amount';
import type { AmountHeadingProps, AmountDisplayProps, AmountBodyProps } from './amountTokens';
import { currencyIndicatorMapping } from './amountTokens';
import { getStyledPropsArgTypes } from '~components/Box/BaseBox/storybookArgTypes';
import BaseBox from '~components/Box/BaseBox';
import { Sandbox } from '~utils/storybook/Sandbox';
import { Display, Text } from '~components/Typography';
import StoryPageWrapper from '~utils/storybook/StoryPageWrapper';
import { Box } from '~components/Box';
import { objectKeysWithType } from '~utils/objectKeysWithType';
import { ActionList, ActionListItem } from '~components/ActionList';
import { SelectInput } from '~components/Input/DropdownInputTriggers';
import { Dropdown, DropdownOverlay } from '~components/Dropdown';
import { Divider } from '~components/Divider';
import { Link } from '~components/Link';

const Page = (): React.ReactElement => {
return (
<StoryPageWrapper
componentName="Amount"
componentDescription="Amounts are used to show small amount of color coded metadata, which are ideal for getting user attention."
note="This component only displays the provided value in the specified currency, it does not perform any currency conversion."
note="This component only displays the provided value in the specified currency with the formatting capabilities enabled by @razorpay/i18nify-js (https://www.npmjs.com/package/@razorpay/i18nify-js), it does not perform any currency conversion."
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
note="This component only displays the provided value in the specified currency with the formatting capabilities enabled by @razorpay/i18nify-js (https://www.npmjs.com/package/@razorpay/i18nify-js), it does not perform any currency conversion."
note="This component only displays the provided value in the specified currency with the formatting capabilities enabled by @razorpay/i18nify-react, it does not perform any currency conversion."

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done
Screenshot 2024-02-12 at 3 07 08 PM

figmaURL="https://www.figma.com/file/jubmQL9Z8V7881ayUD95ps/Blade-DSL?type=design&node-id=73328-558626&mode=design&t=JkDSnlo8KJOBJimR-4"
>
<Title>Usage</Title>
Expand All @@ -31,6 +38,22 @@ const Page = (): React.ReactElement => {
export default App;
`}
</Sandbox>
<Box marginBottom="spacing.10">
<Text>
The Amount component automatically formats numbers based on the user's browser locale
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use the propname propsDescription on the StoryPageWrapper component and put this information there you can remove links and only mention i18nify-react. ignore the js since that will go away with the approach we discussed last time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done
Screenshot 2024-02-12 at 3 05 56 PM

Copy link
Collaborator

@kamleshchandnani kamleshchandnani Feb 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you update the messaging a bit? for more details of what? please refer to the documentation of what?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done
Screenshot 2024-02-12 at 3 31 47 PM

enabled by{' '}
<Link href="https://www.npmjs.com/package/@razorpay/i18nify-js">
@razorpay/i18nify-js
</Link>
. To adjust the locale according to your page, add{' '}
<Link href="https://www.npmjs.com/package/@razorpay/i18nify-react">
@razorpay/i18nify-react
</Link>{' '}
library and utilise its hooks for updating the locale. For more details, please refer to
the{' '}
<Link href="https://www.npmjs.com/package/@razorpay/i18nify-react">documentation.</Link>
</Text>
</Box>
</StoryPageWrapper>
);
};
Expand Down Expand Up @@ -176,7 +199,7 @@ HumanizeSuffix.args = {
HumanizeSuffix.storyName = 'Humanize Suffix';

const AmountCurrencyTemplate: StoryFn<typeof AmountComponent> = (args) => {
const values = Object.keys(currencyIndicatorMapping);
const values = Object.keys(getCurrencyList());

return (
<BaseBox justifyContent="flex-start" maxHeight="300px" overflowY="auto">
Expand Down Expand Up @@ -217,3 +240,98 @@ StrikeThrough.args = {
isStrikethrough: true,
};
StrikeThrough.storyName = 'Strike Through';

// TODO: Replace below with i18nify getDefaultLocales API
const localeList = [
{
country: 'India',
locale: 'en-IN',
},
{
country: 'USA',
locale: 'en-US',
},
{
country: 'Malaysia',
locale: 'ms-MY',
},
{
country: 'France',
locale: 'fr-FR',
},
{
country: 'Germany',
locale: 'de-DE',
},
];

const I18nAmountWrapper = (args: AmountProps): JSX.Element => {
const { setI18nState } = useI18nContext();
const [currency, setCurrency] = useState('INR');

return (
<>
<AmountComponent {...args} currency={currency as AmountProps['currency']} />
<Divider marginY="spacing.4" marginTop="spacing.8" />
<Dropdown selectionType="single">
<SelectInput label="Select currency" />
<DropdownOverlay>
<ActionList>
{Object.keys(getCurrencyList()).map((value) => (
<ActionListItem
key={value}
title={value}
value={value}
onClick={({ name }) => {
setCurrency(name);
}}
/>
))}
</ActionList>
</DropdownOverlay>
</Dropdown>
<Divider marginY="spacing.4" />
<Dropdown selectionType="single">
<SelectInput label="Select locale" />
<DropdownOverlay>
<ActionList>
{localeList.map((item) => (
<ActionListItem
key={item.locale}
title={`${item.country}(${item.locale})`}
value={item.locale}
onClick={({ name }) => {
setI18nState?.({ locale: name });
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tarun-khanna this is setting the context at a global amount's level ideally we shall scope it within this story itself?

Why?
I opened the amount story page i.e default Docs page and saw the currency in some default locale then I navigated to the locale story and was playing around with it and then went back to the Docs page of amount and it was pointing to the locale I set under the locale story which was misleading as there's no information mentioned about that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting a state by I18nProvider's setI18nState will always set it globally for i18nify-js. We decided to architect our library in this fashion so to deal with out of sync state issues between sidebar, header, body and other elements as discussed in our earlier meetings.

To deal with this,

  1. We can introduce an internal locale prop hidden to consumers.
  2. Then on locale dropdown click, We don't have to call setI18nState but can maintain an internal locale state which will be passed to the Amount instance used in this story.
  3. We can then pass locale prop to i18nify-js formatNumber api which accepts this locale param for overriding global state.

Thoughts ? @kamleshchandnani

Copy link
Collaborator

@kamleshchandnani kamleshchandnani Feb 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay i'm saying keep it simple from demonstration point of view because right now there's no co-relation to the end consumer that changes in one story is affecting other. what I'm suggesting is wrap another i18n context around just the locale story so the state changes is only affected to that story and not goes all the stories of amount component.

No changes in implementation, just how the story is written

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As discussed earlier, there is no finalised approach here that will resolve this issue so we will be addressing this issue in the next PR. The current one can still go as it is.
Attaching MOM here

cc @kamleshchandnani

}}
/>
))}
</ActionList>
</DropdownOverlay>
</Dropdown>
</>
);
};

const I18nAmountTemplate: StoryFn<typeof AmountComponent> = (args) => {
return (
<I18nProvider>
<BaseBox justifyContent="flex-start" minHeight="300px" overflowY="auto">
<BaseBox
display="flex"
alignItems="baseline"
paddingRight="spacing.3"
paddingTop="spacing.3"
flexDirection="column"
>
<I18nAmountWrapper {...args} />
</BaseBox>
</BaseBox>
</I18nProvider>
);
};

export const I18nAmount = I18nAmountTemplate.bind({});
I18nAmount.args = {
...defaultArgs,
};
I18nAmount.storyName = 'Amount in diff locales';
Loading
Loading