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

Added Localize HOC #2208

Merged
merged 4 commits into from
Apr 7, 2021
Merged
Show file tree
Hide file tree
Changes from 3 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
86 changes: 86 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/preset-flow": "^7.12.13",
"@formatjs/intl-getcanonicallocales": "^1.5.8",
"@formatjs/intl-locale": "^2.4.21",
"@formatjs/intl-numberformat": "^6.2.5",
"@formatjs/intl-pluralrules": "^4.0.13",
"@react-native-community/async-storage": "^1.11.0",
"@react-native-community/cli": "4.13.1",
"@react-native-community/clipboard": "^1.5.1",
Expand Down
63 changes: 63 additions & 0 deletions src/components/withLocalize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import getComponentDisplayName from '../libs/getComponentDisplayName';
import compose from '../libs/compose';
import ONYXKEYS from '../ONYXKEYS';
import {translate} from '../libs/translate';
import DateUtils from '../libs/DateUtils';
import {toLocalPhone, fromLocalPhone} from '../libs/LocalePhoneNumber';
import numberFormat from '../libs/numberFormat';

const withLocalizePropTypes = {
parasharrajat marked this conversation as resolved.
Show resolved Hide resolved
// Translations functions using current User's preferred locale
translations: PropTypes.shape({
translate: PropTypes.func.isRequired,
numberFormat: PropTypes.func.isRequired,
timestampToRelative: PropTypes.func.isRequired,
timestampToDateTime: PropTypes.func.isRequired,
toLocalPhone: PropTypes.func.isRequired,
fromLocalPhone: PropTypes.func.isRequired,
}),
};

function withLocalizeHOC(WrappedComponent) {
const withLocalize = (props) => {
const translations = {
parasharrajat marked this conversation as resolved.
Show resolved Hide resolved
translate: (phrase, variables) => translate(props.preferredLocale, phrase, variables),
numberFormat: (number, options) => numberFormat(props.preferredLocale, number, options),
timestampToRelative: timestamp => DateUtils.timestampToRelative(props.preferredLocale, timestamp),
timestampToDateTime: (timestamp, includeTimezone) => DateUtils.timestampToDateTime(
props.preferredLocale,
timestamp,
includeTimezone,
),
toLocalPhone: number => toLocalPhone(props.preferredLocale, number),
fromLocalPhone: number => fromLocalPhone(props.preferredLocale, number),
};
return (
<WrappedComponent
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
translations={translations}
/>
);
};
withLocalize.displayName = `withLocalize(${getComponentDisplayName(WrappedComponent)})`;
withLocalize.defaultProps = {
preferredLocale: 'en',
};
return withLocalize;
}
export default compose(
withOnyx({
preferredLocale: {
key: ONYXKEYS.PREFERRED_LOCALE,
},
}),
withLocalizeHOC,
);

export {
withLocalizePropTypes,
};
5 changes: 5 additions & 0 deletions src/libs/numberFormat/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function numberFormat(locale, number, options) {
return new Intl.NumberFormat(locale, options).format(number);
}

export default numberFormat;
14 changes: 14 additions & 0 deletions src/libs/numberFormat/index.native.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// we only need polyfills for Mobile.
parasharrajat marked this conversation as resolved.
Show resolved Hide resolved
import '@formatjs/intl-getcanonicallocales/polyfill';
import '@formatjs/intl-locale/polyfill';
import '@formatjs/intl-pluralrules/polyfill';
import '@formatjs/intl-numberformat/polyfill';

// Load en Locale data
import '@formatjs/intl-numberformat/locale-data/en';
parasharrajat marked this conversation as resolved.
Show resolved Hide resolved

function numberFormat(locale, number, options) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Also, is there a way to not have to define this twice? And if there is, do we think is worth it?

Copy link
Member Author

Choose a reason for hiding this comment

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

We just need to import those files for mobile(native) platforms. I think it can be done via webpack. But for locale #2208 (review)

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand but the numberFormat is defined duplicate in 2 places.
(also, that link is supposed to send me where exactly? It takes me here again)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah. So I am saying that we can load the imports via webpack and remove two files.

And for locale probably

A proper way would be when the user switches a locale, load the file remotely.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah. So I am saying that we can load the imports via webpack and remove two files.

I am not sure I know how this works, can you explain?

Copy link
Contributor

Choose a reason for hiding this comment

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

You can import the src/libs/numberFormat/index.js which already defines the function and use it here, no?

Copy link
Member Author

Choose a reason for hiding this comment

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

index.js will be replaced with index.native.js so we need a new file. then we import from that file. Or better would be to create a file called lib/polyfills/index.native.js and import the packages there. this will allow adding all the polyfills at a single location and we import this file in app.js.

Copy link
Contributor

Choose a reason for hiding this comment

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

index.js will be replaced with index.native.js

Huh? Why?

What I am saying is:

  • The method is in index.js
  • index.native.js would import it and use it

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok. let me test it first to be sure. My assumption is that we replace index.js files with index.native.js on mobile platforms.

Copy link
Member Author

@parasharrajat parasharrajat Apr 7, 2021

Choose a reason for hiding this comment

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

@iwiznia. I tested it. My assumptions are correct. index files are replaced with platform-specific index files(such as index.android.js on android). So I can make a common base.js file. or let's just leave it like this as this is just two lines of code. We had to create two files.

  1. Index.js
  2. index.android.js
    To keep it dry, we can create one more base.js, But I think that will be totally overuse of DRY for just two lines. Anyways each platform only gets one file in the bundle.

return new Intl.NumberFormat(locale, options).format(number);
}

export default numberFormat;