Skip to content

Commit

Permalink
Merge pull request Expensify#29180 from software-mansion-labs/ts-migr…
Browse files Browse the repository at this point in the history
…ation/useLocalize

[TS migration] Migrate useLocalize
  • Loading branch information
mountiny authored Nov 13, 2023
2 parents b867619 + 493fef5 commit bebff5c
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 171 deletions.
2 changes: 1 addition & 1 deletion src/TIMEZONES.js → src/TIMEZONES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,4 +418,4 @@ export default [
'Pacific/Tongatapu',
'Pacific/Wake',
'Pacific/Wallis',
];
] as const;
134 changes: 0 additions & 134 deletions src/components/LocaleContextProvider.js

This file was deleted.

133 changes: 133 additions & 0 deletions src/components/LocaleContextProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import React, {createContext, useMemo} from 'react';
import {OnyxEntry, withOnyx} from 'react-native-onyx';
import {ValueOf} from 'type-fest';
import compose from '@libs/compose';
import DateUtils from '@libs/DateUtils';
import * as LocaleDigitUtils from '@libs/LocaleDigitUtils';
import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
import * as Localize from '@libs/Localize';
import * as NumberFormatUtils from '@libs/NumberFormatUtils';
import CONST from '@src/CONST';
import {TranslationPaths} from '@src/languages/types';
import ONYXKEYS from '@src/ONYXKEYS';
import withCurrentUserPersonalDetails, {WithCurrentUserPersonalDetailsProps} from './withCurrentUserPersonalDetails';

type Locale = ValueOf<typeof CONST.LOCALES>;

type LocaleContextProviderOnyxProps = {
/** The user's preferred locale e.g. 'en', 'es-ES' */
preferredLocale: OnyxEntry<Locale>;
};

type LocaleContextProviderProps = LocaleContextProviderOnyxProps &
WithCurrentUserPersonalDetailsProps & {
/** Actual content wrapped by this component */
children: React.ReactNode;
};

type LocaleContextProps = {
/** Returns translated string for given locale and phrase */
translate: <TKey extends TranslationPaths>(phraseKey: TKey, ...phraseParameters: Localize.PhraseParameters<Localize.Phrase<TKey>>) => string;

/** Formats number formatted according to locale and options */
numberFormat: (number: number, options: Intl.NumberFormatOptions) => string;

/** Converts a datetime into a localized string representation that's relative to current moment in time */
datetimeToRelative: (datetime: string) => string;

/** Formats a datetime to local date and time string */
datetimeToCalendarTime: (datetime: string, includeTimezone: boolean, isLowercase: boolean) => string;

/** Updates date-fns internal locale */
updateLocale: () => void;

/** Returns a locally converted phone number for numbers from the same region
* and an internationally converted phone number with the country code for numbers from other regions */
formatPhoneNumber: (phoneNumber: string) => string;

/** Gets the locale digit corresponding to a standard digit */
toLocaleDigit: (digit: string) => string;

/** Gets the standard digit corresponding to a locale digit */
fromLocaleDigit: (digit: string) => string;

/** The user's preferred locale e.g. 'en', 'es-ES' */
preferredLocale: Locale;
};

const LocaleContext = createContext<LocaleContextProps>({
translate: () => '',
numberFormat: () => '',
datetimeToRelative: () => '',
datetimeToCalendarTime: () => '',
updateLocale: () => '',
formatPhoneNumber: () => '',
toLocaleDigit: () => '',
fromLocaleDigit: () => '',
preferredLocale: CONST.LOCALES.DEFAULT,
});

function LocaleContextProvider({preferredLocale, currentUserPersonalDetails = {}, children}: LocaleContextProviderProps) {
const locale = preferredLocale ?? CONST.LOCALES.DEFAULT;

const selectedTimezone = useMemo(() => currentUserPersonalDetails?.timezone?.selected, [currentUserPersonalDetails]);

const translate = useMemo<LocaleContextProps['translate']>(
() =>
(phraseKey, ...phraseParameters) =>
Localize.translate(locale, phraseKey, ...phraseParameters),
[locale],
);

const numberFormat = useMemo<LocaleContextProps['numberFormat']>(() => (number, options) => NumberFormatUtils.format(locale, number, options), [locale]);

const datetimeToRelative = useMemo<LocaleContextProps['datetimeToRelative']>(() => (datetime) => DateUtils.datetimeToRelative(locale, datetime), [locale]);

const datetimeToCalendarTime = useMemo<LocaleContextProps['datetimeToCalendarTime']>(
() =>
(datetime, includeTimezone, isLowercase = false) =>
DateUtils.datetimeToCalendarTime(locale, datetime, includeTimezone, selectedTimezone, isLowercase),
[locale, selectedTimezone],
);

const updateLocale = useMemo<LocaleContextProps['updateLocale']>(() => () => DateUtils.setLocale(locale), [locale]);

const formatPhoneNumber = useMemo<LocaleContextProps['formatPhoneNumber']>(() => (phoneNumber) => LocalePhoneNumber.formatPhoneNumber(phoneNumber), []);

const toLocaleDigit = useMemo<LocaleContextProps['toLocaleDigit']>(() => (digit) => LocaleDigitUtils.toLocaleDigit(locale, digit), [locale]);

const fromLocaleDigit = useMemo<LocaleContextProps['fromLocaleDigit']>(() => (localeDigit) => LocaleDigitUtils.fromLocaleDigit(locale, localeDigit), [locale]);

const contextValue = useMemo<LocaleContextProps>(
() => ({
translate,
numberFormat,
datetimeToRelative,
datetimeToCalendarTime,
updateLocale,
formatPhoneNumber,
toLocaleDigit,
fromLocaleDigit,
preferredLocale: locale,
}),
[translate, numberFormat, datetimeToRelative, datetimeToCalendarTime, updateLocale, formatPhoneNumber, toLocaleDigit, fromLocaleDigit, locale],
);

return <LocaleContext.Provider value={contextValue}>{children}</LocaleContext.Provider>;
}

const Provider = compose(
withOnyx<LocaleContextProviderProps, LocaleContextProviderOnyxProps>({
preferredLocale: {
key: ONYXKEYS.NVP_PREFERRED_LOCALE,
selector: (preferredLocale) => preferredLocale,
},
}),
withCurrentUserPersonalDetails,
)(LocaleContextProvider);

Provider.displayName = 'withOnyx(LocaleContextProvider)';

export {Provider as LocaleContextProvider, LocaleContext};

export type {LocaleContextProps};
5 changes: 3 additions & 2 deletions src/components/withCurrentUserPersonalDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type HOCProps = {
currentUserPersonalDetails: CurrentUserPersonalDetails;
};

type ComponentProps = OnyxProps & HOCProps;
type WithCurrentUserPersonalDetailsProps = OnyxProps & HOCProps;

// TODO: remove when all components that use it will be migrated to TS
const withCurrentUserPersonalDetailsPropTypes = {
Expand All @@ -29,7 +29,7 @@ const withCurrentUserPersonalDetailsDefaultProps: HOCProps = {
currentUserPersonalDetails: {},
};

export default function <TProps extends ComponentProps, TRef>(
export default function <TProps extends WithCurrentUserPersonalDetailsProps, TRef>(
WrappedComponent: ComponentType<TProps & RefAttributes<TRef>>,
): ComponentType<Omit<Omit<TProps, keyof HOCProps> & RefAttributes<TRef>, keyof OnyxProps>> {
function WithCurrentUserPersonalDetails(props: Omit<TProps, keyof HOCProps>, ref: ForwardedRef<TRef>) {
Expand Down Expand Up @@ -62,3 +62,4 @@ export default function <TProps extends ComponentProps, TRef>(
}

export {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps};
export type {WithCurrentUserPersonalDetailsProps};
6 changes: 0 additions & 6 deletions src/hooks/useLocalize.js

This file was deleted.

6 changes: 6 additions & 0 deletions src/hooks/useLocalize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {useContext} from 'react';
import {LocaleContext, LocaleContextProps} from '@components/LocaleContextProvider';

export default function useLocalize(): LocaleContextProps {
return useContext(LocaleContext);
}
2 changes: 1 addition & 1 deletion src/languages/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,10 +243,10 @@ type TranslationFlatObject = {

export type {
TranslationBase,
TranslationPaths,
EnglishTranslation,
TranslationFlatObject,
AddressLineParams,
TranslationPaths,
CharacterLimitParams,
MaxParticipantsReachedParams,
ZipCodeExampleFormatParams,
Expand Down
Loading

0 comments on commit bebff5c

Please sign in to comment.