Chore: Migrate i18n to Typescript (#3988)
* Chore: Migrate i18n to Typescript and fix the Left and Right actions in RoomItem * remove fix to roomItem * update storyshot * Chore: Migrate i18n to Typescript and fix the Left and Right actions in RoomItem * remove fix to roomItem * update storyshot * fix removed itens * fix changes requested * interface for i18n, added resolveJsonModule to tsconfig.json * tweak at error alert * fix storyshot * refactor comments * create function isTranslated * fix accessibilityLabel Co-authored-by: Diego Mello <diegolmello@gmail.com>
This commit is contained in:
parent
397cd3d9b8
commit
25c37c1a60
|
@ -91,7 +91,7 @@ const Content = React.memo(
|
|||
<View style={styles.textContainer}>
|
||||
<View style={styles.textAlertContainer}>
|
||||
<Text style={[styles.title, { color: color || themes[theme].titleText }]} numberOfLines={1}>
|
||||
{translateTitle ? I18n.t(title) : title}
|
||||
{translateTitle && title ? I18n.t(title) : title}
|
||||
</Text>
|
||||
{alert ? (
|
||||
<CustomIcon style={[styles.alertIcon, { color: themes[theme].dangerColor }]} size={ICON_SIZE} name='info' />
|
||||
|
|
|
@ -20,7 +20,10 @@ const BaseButton = ({ accessibilityLabel, icon, color, ...props }: Partial<IBase
|
|||
const { theme } = useTheme();
|
||||
return (
|
||||
<BorderlessButton {...props} style={styles.actionButton}>
|
||||
<View accessible accessibilityLabel={i18n.t(accessibilityLabel)} accessibilityRole='button'>
|
||||
<View
|
||||
accessible
|
||||
accessibilityLabel={accessibilityLabel ? i18n.t(accessibilityLabel) : accessibilityLabel}
|
||||
accessibilityRole='button'>
|
||||
<CustomIcon name={icon} size={24} color={color || themes[theme].auxiliaryTintColor} />
|
||||
</View>
|
||||
</BorderlessButton>
|
||||
|
|
|
@ -680,7 +680,7 @@ class MessageBox extends Component<IMessageBoxProps, IMessageBoxState> {
|
|||
if (result.success) {
|
||||
return true;
|
||||
}
|
||||
Alert.alert(I18n.t('Error_uploading'), I18n.t(result.error));
|
||||
Alert.alert(I18n.t('Error_uploading'), result.error && I18n.isTranslated(result.error) ? I18n.t(result.error) : result.error);
|
||||
return false;
|
||||
};
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ interface IPasscodeBase {
|
|||
type: string;
|
||||
previousPasscode?: string;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
subtitle?: string | null;
|
||||
showBiometry?: boolean;
|
||||
onEndProcess: Function;
|
||||
onError?: Function;
|
||||
|
|
|
@ -14,7 +14,7 @@ interface IPasscodeChoose {
|
|||
const PasscodeChoose = ({ finishProcess, force = false }: IPasscodeChoose) => {
|
||||
const chooseRef = useRef<IBase>(null);
|
||||
const confirmRef = useRef<IBase>(null);
|
||||
const [subtitle, setSubtitle] = useState(null);
|
||||
const [subtitle, setSubtitle] = useState<string | null>(null);
|
||||
const [status, setStatus] = useState(TYPE.CHOOSE);
|
||||
const [previousPasscode, setPreviouPasscode] = useState('');
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import { themes } from '../../lib/constants';
|
|||
export { default as MarkdownPreview } from './Preview';
|
||||
|
||||
interface IMarkdownProps {
|
||||
msg?: string;
|
||||
msg?: string | null;
|
||||
theme: TSupportedThemes;
|
||||
md?: MarkdownAST;
|
||||
mentions?: IUserMention[];
|
||||
|
|
|
@ -2,7 +2,7 @@ import { TMessageModel } from '../../definitions/IMessage';
|
|||
import I18n from '../../i18n';
|
||||
import { DISCUSSION } from './constants';
|
||||
|
||||
export const formatMessageCount = (count?: number, type?: string): string => {
|
||||
export const formatMessageCount = (count?: number, type?: string): string | null => {
|
||||
const discussion = type === DISCUSSION;
|
||||
let text = discussion ? I18n.t('No_messages_yet') : null;
|
||||
if (!count) {
|
||||
|
|
|
@ -6,10 +6,19 @@ import 'moment/min/locales';
|
|||
|
||||
import { toMomentLocale } from '../utils/moment';
|
||||
import { isRTL } from './isRTL';
|
||||
import englishJson from './locales/en.json';
|
||||
|
||||
type TTranslatedKeys = keyof typeof englishJson;
|
||||
|
||||
export { isRTL };
|
||||
|
||||
export const LANGUAGES = [
|
||||
interface ILanguage {
|
||||
label: string;
|
||||
value: string;
|
||||
file: () => any;
|
||||
}
|
||||
|
||||
export const LANGUAGES: ILanguage[] = [
|
||||
{
|
||||
label: 'English',
|
||||
value: 'en',
|
||||
|
@ -82,12 +91,16 @@ export const LANGUAGES = [
|
|||
}
|
||||
];
|
||||
|
||||
interface ITranslations {
|
||||
[language: string]: () => typeof englishJson;
|
||||
}
|
||||
|
||||
const translations = LANGUAGES.reduce((ret, item) => {
|
||||
ret[item.value] = item.file;
|
||||
return ret;
|
||||
}, {});
|
||||
}, {} as ITranslations);
|
||||
|
||||
export const setLanguage = l => {
|
||||
export const setLanguage = (l: string) => {
|
||||
if (!l) {
|
||||
return;
|
||||
}
|
||||
|
@ -104,6 +117,8 @@ export const setLanguage = l => {
|
|||
i18n.translations = { ...i18n.translations, [locale]: translations[locale]?.() };
|
||||
I18nManager.forceRTL(isRTL(locale));
|
||||
I18nManager.swapLeftAndRightInRTL(isRTL(locale));
|
||||
// TODO: Review this logic
|
||||
// @ts-ignore
|
||||
i18n.isRTL = I18nManager.isRTL;
|
||||
moment.locale(toMomentLocale(locale));
|
||||
};
|
||||
|
@ -113,7 +128,16 @@ const defaultLanguage = { languageTag: 'en', isRTL: false };
|
|||
const availableLanguages = Object.keys(translations);
|
||||
const { languageTag } = RNLocalize.findBestAvailableLanguage(availableLanguages) || defaultLanguage;
|
||||
|
||||
// @ts-ignore
|
||||
i18n.isTranslated = (text?: string) => text in englishJson;
|
||||
|
||||
setLanguage(languageTag);
|
||||
i18n.fallbacks = true;
|
||||
|
||||
export default i18n;
|
||||
type Ti18n = {
|
||||
isRTL: boolean;
|
||||
t(scope: TTranslatedKeys, options?: any): string;
|
||||
isTranslated: (text?: string) => boolean;
|
||||
} & typeof i18n;
|
||||
|
||||
export default i18n as Ti18n;
|
|
@ -1,4 +1,4 @@
|
|||
// https://github.com/zoontek/react-native-localize/blob/master/src/constants.ts#L5
|
||||
const USES_RTL_LAYOUT = ['ar', 'ckb', 'fa', 'he', 'ks', 'lrc', 'mzn', 'ps', 'ug', 'ur', 'yi'];
|
||||
|
||||
export const isRTL = locale => USES_RTL_LAYOUT.includes(locale);
|
||||
export const isRTL = (locale?: string) => (locale ? USES_RTL_LAYOUT.includes(locale) : false);
|
|
@ -16,7 +16,7 @@ import protectedFunction from '../../lib/methods/helpers/protectedFunction';
|
|||
import SafeAreaView from '../../containers/SafeAreaView';
|
||||
import log, { events, logEvent } from '../../utils/log';
|
||||
import sharedStyles from '../Styles';
|
||||
import { OPTIONS } from './options';
|
||||
import { IOptionsField, OPTIONS } from './options';
|
||||
import { ChatsStackParamList } from '../../stacks/types';
|
||||
import { IRoomNotifications } from '../../definitions';
|
||||
|
||||
|
@ -131,10 +131,10 @@ class NotificationPreferencesView extends React.Component<INotificationPreferenc
|
|||
renderPickerOption = (key: string) => {
|
||||
const { room } = this.state;
|
||||
const { theme } = this.props;
|
||||
const text = room[key] ? OPTIONS[key].find((option: any) => option.value === room[key]) : OPTIONS[key][0];
|
||||
const text = room[key] ? OPTIONS[key].find(option => option.value === room[key]) : (OPTIONS[key][0] as IOptionsField);
|
||||
return (
|
||||
<Text style={[styles.pickerText, { color: themes[theme].actionTintColor }]}>
|
||||
{I18n.t(text?.label, { defaultValue: text?.label, second: text?.second })}
|
||||
{text?.label ? I18n.t(text?.label, { defaultValue: text?.label, second: text?.second }) : text?.label}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -25,7 +25,7 @@ const Channel = ({ room }: { room: ISubscription }) => {
|
|||
/>
|
||||
<Item
|
||||
label={I18n.t('Broadcast_Channel')}
|
||||
content={room.broadcast && I18n.t('Broadcast_channel_Description')}
|
||||
content={room.broadcast ? I18n.t('Broadcast_channel_Description') : ''}
|
||||
testID='room-info-view-broadcast'
|
||||
/>
|
||||
</>
|
||||
|
|
|
@ -72,7 +72,11 @@ class UserNotificationPreferencesView extends React.Component<
|
|||
renderPickerOption = (key: TKey) => {
|
||||
const { theme } = this.props;
|
||||
const text = this.findDefaultOption(key);
|
||||
return <Text style={[styles.pickerText, { color: themes[theme].actionTintColor }]}>{I18n.t(text?.label)}</Text>;
|
||||
return (
|
||||
<Text style={[styles.pickerText, { color: themes[theme].actionTintColor }]}>
|
||||
{text?.label ? I18n.t(text?.label) : text?.label}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
|
||||
pickerSelection = (title: string, key: TKey) => {
|
||||
|
@ -82,7 +86,9 @@ class UserNotificationPreferencesView extends React.Component<
|
|||
|
||||
const defaultOption = this.findDefaultOption(key);
|
||||
if (OPTIONS[key][0]?.value !== 'default') {
|
||||
const defaultValue = { label: `${I18n.t('Default')} (${I18n.t(defaultOption?.label)})` } as {
|
||||
const defaultValue = {
|
||||
label: `${I18n.t('Default')} (${defaultOption?.label ? I18n.t(defaultOption?.label) : defaultOption?.label})`
|
||||
} as {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
|
|
@ -148,6 +148,7 @@
|
|||
"@testing-library/react-native": "^9.0.0",
|
||||
"@types/bytebuffer": "^5.0.43",
|
||||
"@types/ejson": "^2.1.3",
|
||||
"@types/i18n-js": "^3.8.2",
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/lodash": "^4.14.171",
|
||||
"@types/react": "^17.0.14",
|
||||
|
|
|
@ -67,7 +67,8 @@
|
|||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true /* Skip type checking of declaration files. */,
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"exclude": ["node_modules", "e2e/docker", "__mocks__"]
|
||||
}
|
||||
|
|
|
@ -4514,6 +4514,11 @@
|
|||
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880"
|
||||
integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA==
|
||||
|
||||
"@types/i18n-js@^3.8.2":
|
||||
version "3.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/i18n-js/-/i18n-js-3.8.2.tgz#957a3fa268124d09e3b3b34695f0184118f4bc4f"
|
||||
integrity sha512-F+AuFCjllE1A0W/YUxJB13q2t7cWITMqXOTXQ/InfXxxT8nXrrqL7s/8Pv6XThGjFPemukElwk6QlMOKCEg7eQ==
|
||||
|
||||
"@types/is-function@^1.0.0":
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.0.tgz#1b0b819b1636c7baf0d6785d030d12edf70c3e83"
|
||||
|
|
Loading…
Reference in New Issue