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

3770 multi language improvements #4134

Merged
merged 16 commits into from
Jul 27, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions src/CONST.js

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

88 changes: 88 additions & 0 deletions src/components/LocalePicker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import React from 'react';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import styles from '../styles/styles';
import Picker from './Picker';
import Text from './Text';
import compose from '../libs/compose';
import {setLocale} from '../libs/actions/App';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
import ONYXKEYS from '../ONYXKEYS';
import CONST from '../CONST';
import Permissions from '../libs/Permissions';
import {translate} from '../libs/translate';

const propTypes = {
/** Indicates which locale the user currently has selected */
preferredLocale: PropTypes.string,

/** Indicates size of a picker component and whether to render the label or not */
size: PropTypes.oneOf(['normal', 'small']),

/** Beta features list */
betas: PropTypes.arrayOf(PropTypes.string),

...withLocalizePropTypes,
};

const defaultProps = {
preferredLocale: CONST.DEFAULT_LOCALE,
size: 'normal',
betas: [],
};

const localesToLanguages = {
default: {
value: 'en',
label: translate('en', 'preferencesPage.languages.english'),
},
es: {
value: 'es',
label: translate('es', 'preferencesPage.languages.spanish'),
},
};

const LocalePicker = ({
// eslint-disable-next-line no-shadow
preferredLocale, translate, betas, size,
}) => {
if (!Permissions.canUseInternationalization(betas)) {
return null;
}

return (
<>
{size === 'normal' && (
<Text style={[styles.formLabel]} numberOfLines={1}>
{translate('preferencesPage.language')}
</Text>
)}
<Picker
onChange={(locale) => {
if (locale !== preferredLocale) {
setLocale(locale);
}
}}
items={Object.values(localesToLanguages)}
size={size}
value={preferredLocale}
/>
</>
);
};

LocalePicker.defaultProps = defaultProps;
LocalePicker.propTypes = propTypes;
LocalePicker.displayName = 'LocalePicker';

export default compose(
withLocalize,
withOnyx({
preferredLocale: {
key: ONYXKEYS.PREFERRED_LOCALE,
},
betas: {
key: ONYXKEYS.BETAS,
},
}),
)(LocalePicker);
22 changes: 21 additions & 1 deletion src/components/Picker/PickerPropTypes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import Icon from '../Icon';
import styles from '../../styles/styles';
import {DownArrow} from '../Icon/Expensicons';

const propTypes = {
Expand Down Expand Up @@ -36,13 +37,32 @@ const propTypes = {

/** An icon to display with the picker */
icon: PropTypes.func,

/** Size of a picker component */
size: PropTypes.oneOf(['normal', 'small']),
};
const defaultProps = {
useDisabledStyles: false,
disabled: false,
placeholder: {},
value: null,
icon: () => <Icon src={DownArrow} />,
icon: size => (
<>
{size === 'small'
? (
<Icon
width={styles.pickerSmall.icon.width}
height={styles.pickerSmall.icon.height}
src={DownArrow}
/>
)
: (
<Icon
src={DownArrow}
/>
)}
</>
),
};

export {
Expand Down
36 changes: 23 additions & 13 deletions src/components/Picker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,29 @@ const Picker = ({
value,
icon,
disabled,
}) => (
<RNPickerSelect
onValueChange={onChange}
items={items}
style={useDisabledStyles ? pickerDisabledStyles : styles.picker}
useNativeAndroidPickerStyle={false}
placeholder={placeholder}
value={value}
Icon={icon}
disabled={disabled}
fixAndroidTouchableBug
/>
);
size,
}) => {
let pickerStyles;
if (size === 'small') {
pickerStyles = styles.pickerSmall;
} else {
pickerStyles = useDisabledStyles ? pickerDisabledStyles : styles.picker;
}

return (
<RNPickerSelect
onValueChange={onChange}
items={items}
style={pickerStyles}
useNativeAndroidPickerStyle={false}
placeholder={placeholder}
value={value}
Icon={() => icon(size)}
disabled={disabled}
fixAndroidTouchableBug
/>
);
};

Picker.propTypes = pickerPropTypes.propTypes;
Picker.defaultProps = pickerPropTypes.defaultProps;
Expand Down
9 changes: 9 additions & 0 deletions src/libs/Permissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,19 @@ function canUseDefaultRooms(betas) {
return _.contains(betas, CONST.BETAS.DEFAULT_ROOMS) || canUseAllBetas(betas);
}

/**
* @param {Array<String>} betas
* @returns {Boolean}
*/
function canUseInternationalization(betas) {
return _.contains(betas, CONST.BETAS.INTERNATIONALIZATION) || canUseAllBetas(betas);
}

export default {
canUseChronos,
canUseIOU,
canUsePayWithExpensify,
canUseFreePlan,
canUseDefaultRooms,
canUseInternationalization,
};
10 changes: 10 additions & 0 deletions src/libs/actions/SignInRedirect.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ Onyx.connect({
},
});

let currentPreferredLocale;
Onyx.connect({
key: ONYXKEYS.PREFERRED_LOCALE,
callback: val => currentPreferredLocale = val,
});

/**
* Clears the Onyx store and redirects to the sign in page.
* Normally this method would live in Session.js, but that would cause a circular dependency with Network.js.
Expand All @@ -37,12 +43,16 @@ function redirectToSignIn(errorMessage) {
}

const activeClients = currentActiveClients;
const preferredLocale = currentPreferredLocale;

// We must set the authToken to null so we can navigate to "signin" it's not possible to navigate to the route as
// it only exists when the authToken is null.
Onyx.set(ONYXKEYS.SESSION, {authToken: null})
.then(() => {
Onyx.clear().then(() => {
if (preferredLocale) {
Onyx.set(ONYXKEYS.PREFERRED_LOCALE, preferredLocale);
}
if (errorMessage) {
Onyx.set(ONYXKEYS.SESSION, {error: errorMessage});
}
Expand Down
35 changes: 3 additions & 32 deletions src/pages/settings/PreferencesPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';

import HeaderWithCloseButton from '../../components/HeaderWithCloseButton';
import LocalePicker from '../../components/LocalePicker';
import Navigation from '../../libs/Navigation/Navigation';
import ROUTES from '../../ROUTES';
import ONYXKEYS from '../../ONYXKEYS';
Expand All @@ -17,7 +18,6 @@ import Switch from '../../components/Switch';
import Picker from '../../components/Picker';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
import compose from '../../libs/compose';
import {setLocale} from '../../libs/actions/App';

const propTypes = {
/** The chat priority mode */
Expand All @@ -29,20 +29,16 @@ const propTypes = {
expensifyNewsStatus: PropTypes.bool,
}),

/** Indicates which locale the user currently has selected */
preferredLocale: PropTypes.string,

...withLocalizePropTypes,
};

const defaultProps = {
priorityMode: CONST.PRIORITY_MODE.DEFAULT,
user: {},
preferredLocale: CONST.DEFAULT_LOCALE,
};

const PreferencesPage = ({
priorityMode, user, translate, preferredLocale,
priorityMode, user, translate,
}) => {
const priorityModes = {
default: {
Expand All @@ -57,17 +53,6 @@ const PreferencesPage = ({
},
};

const localesToLanguages = {
default: {
value: 'en',
label: translate('preferencesPage.languages.english'),
},
es: {
value: 'es',
label: translate('preferencesPage.languages.spanish'),
},
};

return (
<ScreenWrapper>
<HeaderWithCloseButton
Expand Down Expand Up @@ -109,19 +94,8 @@ const PreferencesPage = ({
<Text style={[styles.textLabel, styles.colorMuted, styles.mb6]}>
{priorityModes[priorityMode].description}
</Text>
<Text style={[styles.formLabel]} numberOfLines={1}>
{translate('preferencesPage.language')}
</Text>
<View style={[styles.mb2]}>
<Picker
onChange={(locale) => {
if (locale !== preferredLocale) {
setLocale(locale);
}
}}
items={Object.values(localesToLanguages)}
value={preferredLocale}
/>
<LocalePicker />
</View>
</View>
</View>
Expand All @@ -142,8 +116,5 @@ export default compose(
user: {
key: ONYXKEYS.USER,
},
preferredLocale: {
key: ONYXKEYS.NVP_PREFERRED_LOCALE,
},
}),
)(PreferencesPage);
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,17 @@ import withLocalize, {
withLocalizePropTypes,
} from '../../../../components/withLocalize';
import LogoWordmark from '../../../../../assets/images/expensify-wordmark.svg';
import LocalePicker from '../../../../components/LocalePicker';

const TermsWithLicenses = ({translate}) => (
<View>
<View style={[styles.mt1, styles.alignItemsCenter, styles.mb3]}>
<LogoWordmark height={30} width={80} />
</View>
<View
style={[
styles.dFlex,
styles.flexRow,
styles.flexWrap,
styles.textAlignCenter,
styles.alignItemsCenter,
styles.justifyContentCenter,
]}
>
<Text style={[styles.textAlignCenter, styles.loginTermsText]}>
Expand Down Expand Up @@ -61,6 +58,12 @@ const TermsWithLicenses = ({translate}) => (
</TextLink>
<Text style={[styles.textAlignCenter, styles.loginTermsText]}>.</Text>
</View>
<View style={[
styles.mt4, styles.alignItemsCenter, styles.mb2, styles.flexRow, styles.justifyContentBetween]}
>
<LogoWordmark height={30} width={80} />
<LocalePicker size="small" />
</View>
</View>
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,16 @@ import withLocalize, {
withLocalizePropTypes,
} from '../../../../components/withLocalize';
import LogoWordmark from '../../../../../assets/images/expensify-wordmark.svg';
import LocalePicker from '../../../../components/LocalePicker';

const TermsWithLicenses = ({translate}) => (
<View>
<View style={[styles.mt1, styles.alignItemsCenter, styles.mb3]}>
<LogoWordmark height={30} width={80} />
</View>
<View
style={[
styles.dFlex,
styles.flexColumn,
styles.flexWrap,
styles.textAlignCenter,
styles.alignItemsCenter,
styles.justifyContentCenter,
]}
>
Expand Down Expand Up @@ -67,6 +64,12 @@ const TermsWithLicenses = ({translate}) => (
<Text style={[styles.textAlignCenter, styles.loginTermsText]}>.</Text>
</View>
</View>
<View style={[
styles.mt4, styles.alignItemsCenter, styles.mb2, styles.flexRow, styles.justifyContentBetween]}
>
<LogoWordmark height={30} width={80} />
<LocalePicker size="small" />
</View>
</View>
);

Expand Down
Loading