This commit is contained in:
Diego Mello 2018-06-01 14:38:13 -03:00 committed by Guilherme Gazzo
parent ed8ce28708
commit 466a57e6b1
53 changed files with 679 additions and 445 deletions

View File

@ -172,6 +172,7 @@ repositories {
} }
dependencies { dependencies {
compile project(':react-native-i18n')
compile project(':react-native-fabric') compile project(':react-native-fabric')
compile project(':react-native-audio') compile project(':react-native-audio')
compile project(":reactnativekeyboardinput") compile project(":reactnativekeyboardinput")

View File

@ -20,6 +20,7 @@ import com.wix.reactnativekeyboardinput.KeyboardInputPackage;
import com.rnim.rn.audio.ReactNativeAudioPackage; import com.rnim.rn.audio.ReactNativeAudioPackage;
import com.smixx.fabric.FabricPackage; import com.smixx.fabric.FabricPackage;
import com.dylanvann.fastimage.FastImageViewPackage; import com.dylanvann.fastimage.FastImageViewPackage;
import com.AlexanderZaytsev.RNI18n.RNI18nPackage;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -51,7 +52,8 @@ public class MainApplication extends Application implements ReactApplication {
new KeyboardInputPackage(MainApplication.this), new KeyboardInputPackage(MainApplication.this),
new RocketChatNativePackage(), new RocketChatNativePackage(),
new FabricPackage(), new FabricPackage(),
new FastImageViewPackage() new FastImageViewPackage(),
new RNI18nPackage()
); );
} }
}; };

View File

@ -1,4 +1,6 @@
rootProject.name = 'RocketChatRN' rootProject.name = 'RocketChatRN'
include ':react-native-i18n'
project(':react-native-i18n').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-i18n/android')
include ':react-native-fast-image' include ':react-native-fast-image'
project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android') project(':react-native-fast-image').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-fast-image/android')
include ':react-native-fabric' include ':react-native-fabric'

View File

@ -1,69 +0,0 @@
import { StyleSheet, View, Text } from 'react-native';
import PropTypes from 'prop-types';
import React from 'react';
import { connect } from 'react-redux';
const styles = StyleSheet.create({
bannerContainer: {
backgroundColor: '#ddd'
},
bannerText: {
textAlign: 'center',
margin: 5
}
});
@connect(state => ({
connecting: state.meteor.connecting,
authenticating: state.login.isFetching,
offline: !state.meteor.connected,
logged: !!state.login.token
}))
export default class Banner extends React.PureComponent {
static propTypes = {
connecting: PropTypes.bool,
authenticating: PropTypes.bool,
offline: PropTypes.bool
}
render() {
const {
connecting, authenticating, offline, logged
} = this.props;
if (offline) {
return (
<View style={[styles.bannerContainer, { backgroundColor: 'red' }]}>
<Text style={[styles.bannerText, { color: '#a00' }]}>offline...</Text>
</View>
);
}
if (connecting) {
return (
<View style={[styles.bannerContainer, { backgroundColor: '#0d0' }]}>
<Text style={[styles.bannerText, { color: '#fff' }]}>Connecting...</Text>
</View>
);
}
if (authenticating) {
return (
<View style={[styles.bannerContainer, { backgroundColor: 'orange' }]}>
<Text style={[styles.bannerText, { color: '#a00' }]}>Authenticating...</Text>
</View>
);
}
if (logged) {
return this.props.children;
}
return (
<View style={[styles.bannerContainer, { backgroundColor: 'orange' }]}>
<Text style={[styles.bannerText, { color: '#a00' }]}>Not logged...</Text>
</View>
);
}
}

View File

@ -18,6 +18,7 @@ import {
} from '../actions/messages'; } from '../actions/messages';
import { showToast } from '../utils/info'; import { showToast } from '../utils/info';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import I18n from '../i18n';
@connect( @connect(
state => ({ state => ({
@ -86,50 +87,50 @@ export default class MessageActions extends React.Component {
if (nextProps.showActions !== this.props.showActions && nextProps.showActions) { if (nextProps.showActions !== this.props.showActions && nextProps.showActions) {
const { actionMessage } = nextProps; const { actionMessage } = nextProps;
// Cancel // Cancel
this.options = ['Cancel']; this.options = [I18n.t('Cancel')];
this.CANCEL_INDEX = 0; this.CANCEL_INDEX = 0;
// Reply // Reply
if (!this.isRoomReadOnly()) { if (!this.isRoomReadOnly()) {
this.options.push('Reply'); this.options.push(I18n.t('Reply'));
this.REPLY_INDEX = this.options.length - 1; this.REPLY_INDEX = this.options.length - 1;
} }
// Edit // Edit
if (this.allowEdit(nextProps)) { if (this.allowEdit(nextProps)) {
this.options.push('Edit'); this.options.push(I18n.t('Edit'));
this.EDIT_INDEX = this.options.length - 1; this.EDIT_INDEX = this.options.length - 1;
} }
// Permalink // Permalink
this.options.push('Copy Permalink'); this.options.push(I18n.t('Copy_Permalink'));
this.PERMALINK_INDEX = this.options.length - 1; this.PERMALINK_INDEX = this.options.length - 1;
// Copy // Copy
this.options.push('Copy Message'); this.options.push(I18n.t('Copy_Message'));
this.COPY_INDEX = this.options.length - 1; this.COPY_INDEX = this.options.length - 1;
// Share // Share
this.options.push('Share Message'); this.options.push(I18n.t('Share_Message'));
this.SHARE_INDEX = this.options.length - 1; this.SHARE_INDEX = this.options.length - 1;
// Quote // Quote
if (!this.isRoomReadOnly()) { if (!this.isRoomReadOnly()) {
this.options.push('Quote'); this.options.push(I18n.t('Quote'));
this.QUOTE_INDEX = this.options.length - 1; this.QUOTE_INDEX = this.options.length - 1;
} }
// Star // Star
if (this.props.Message_AllowStarring) { if (this.props.Message_AllowStarring) {
this.options.push(actionMessage.starred ? 'Unstar' : 'Star'); this.options.push(I18n.t(actionMessage.starred ? 'Unstar' : 'Star'));
this.STAR_INDEX = this.options.length - 1; this.STAR_INDEX = this.options.length - 1;
} }
// Pin // Pin
if (this.props.Message_AllowPinning) { if (this.props.Message_AllowPinning) {
this.options.push(actionMessage.pinned ? 'Unpin' : 'Pin'); this.options.push(I18n.t(actionMessage.pinned ? 'Unpin' : 'Pin'));
this.PIN_INDEX = this.options.length - 1; this.PIN_INDEX = this.options.length - 1;
} }
// Reaction // Reaction
if (!this.isRoomReadOnly() || this.canReactWhenReadOnly()) { if (!this.isRoomReadOnly() || this.canReactWhenReadOnly()) {
this.options.push('Add Reaction'); this.options.push(I18n.t('Add_Reaction'));
this.REACTION_INDEX = this.options.length - 1; this.REACTION_INDEX = this.options.length - 1;
} }
// Delete // Delete
if (this.allowDelete(nextProps)) { if (this.allowDelete(nextProps)) {
this.options.push('Delete'); this.options.push(I18n.t('Delete'));
this.DELETE_INDEX = this.options.length - 1; this.DELETE_INDEX = this.options.length - 1;
} }
setTimeout(() => { setTimeout(() => {
@ -141,7 +142,7 @@ export default class MessageActions extends React.Component {
if (this.state.copyPermalink) { if (this.state.copyPermalink) {
this.setState({ copyPermalink: false }); this.setState({ copyPermalink: false });
await Clipboard.setString(nextProps.permalink); await Clipboard.setString(nextProps.permalink);
showToast('Permalink copied to clipboard!'); showToast(I18n.t('Permalink_copied_to_clipboard'));
this.props.permalinkClear(); this.props.permalinkClear();
// quote // quote
} else if (this.state.quote) { } else if (this.state.quote) {
@ -234,15 +235,15 @@ export default class MessageActions extends React.Component {
handleDelete() { handleDelete() {
Alert.alert( Alert.alert(
'Are you sure?', I18n.t('Are_you_sure_question_mark'),
'You will not be able to recover this message!', I18n.t('You_will_not_be_able_to_recover_this_message'),
[ [
{ {
text: 'Cancel', text: I18n.t('Cancel'),
style: 'cancel' style: 'cancel'
}, },
{ {
text: 'Yes, delete it!', text: I18n.t('Yes_action_it', { action: 'delete' }),
style: 'destructive', style: 'destructive',
onPress: () => this.props.deleteRequest(this.props.actionMessage) onPress: () => this.props.deleteRequest(this.props.actionMessage)
} }
@ -258,7 +259,7 @@ export default class MessageActions extends React.Component {
handleCopy = async() => { handleCopy = async() => {
await Clipboard.setString(this.props.actionMessage.msg); await Clipboard.setString(this.props.actionMessage.msg);
showToast('Copied to clipboard!'); showToast(I18n.t('Copied_to_clipboard'));
} }
handleShare = async() => { handleShare = async() => {
@ -336,7 +337,7 @@ export default class MessageActions extends React.Component {
return ( return (
<ActionSheet <ActionSheet
ref={o => this.ActionSheet = o} ref={o => this.ActionSheet = o}
title='Messages actions' title={I18n.t('Message_actions')}
testID='message-actions' testID='message-actions'
options={this.options} options={this.options}
cancelButtonIndex={this.CANCEL_INDEX} cancelButtonIndex={this.CANCEL_INDEX}

View File

@ -4,6 +4,7 @@ import { View, SafeAreaView, Platform, PermissionsAndroid, Text } from 'react-na
import { AudioRecorder, AudioUtils } from 'react-native-audio'; import { AudioRecorder, AudioUtils } from 'react-native-audio';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
import styles from './styles'; import styles from './styles';
import I18n from '../../i18n';
export const _formatTime = function(seconds) { export const _formatTime = function(seconds) {
let minutes = Math.floor(seconds / 60); let minutes = Math.floor(seconds / 60);
@ -24,8 +25,8 @@ export default class extends React.PureComponent {
} }
const rationale = { const rationale = {
title: 'Microphone Permission', title: I18n.t('Microphone_Permission'),
message: 'Rocket Chat needs access to your microphone so you can send audio message.' message: I18n.t('Microphone_Permission_Message')
}; };
const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, rationale); const result = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, rationale);
@ -118,7 +119,7 @@ export default class extends React.PureComponent {
style={[styles.actionButtons, { color: 'red' }]} style={[styles.actionButtons, { color: 'red' }]}
name='clear' name='clear'
key='clear' key='clear'
accessibilityLabel='Cancel recording' accessibilityLabel={I18n.t('Cancel_recording')}
accessibilityTraits='button' accessibilityTraits='button'
onPress={this.cancelAudioMessage} onPress={this.cancelAudioMessage}
/> />
@ -127,7 +128,7 @@ export default class extends React.PureComponent {
style={[styles.actionButtons, { color: 'green' }]} style={[styles.actionButtons, { color: 'green' }]}
name='check' name='check'
key='check' key='check'
accessibilityLabel='Finish recording' accessibilityLabel={I18n.t('Finish_recording')}
accessibilityTraits='button' accessibilityTraits='button'
onPress={this.finishAudioMessage} onPress={this.finishAudioMessage}
/> />

View File

@ -19,6 +19,7 @@ import { emojis } from '../../emojis';
import Recording from './Recording'; import Recording from './Recording';
import './EmojiKeyboard'; import './EmojiKeyboard';
import log from '../../utils/log'; import log from '../../utils/log';
import I18n from '../../i18n';
const MENTIONS_TRACKING_TYPE_USERS = '@'; const MENTIONS_TRACKING_TYPE_USERS = '@';
const MENTIONS_TRACKING_TYPE_EMOJIS = ':'; const MENTIONS_TRACKING_TYPE_EMOJIS = ':';
@ -107,7 +108,7 @@ export default class MessageBox extends React.PureComponent {
return (<Icon return (<Icon
style={styles.actionButtons} style={styles.actionButtons}
name='close' name='close'
accessibilityLabel='Cancel editing' accessibilityLabel={I18n.t('Cancel_editing')}
accessibilityTraits='button' accessibilityTraits='button'
onPress={() => this.editCancel()} onPress={() => this.editCancel()}
testID='messagebox-cancel-editing' testID='messagebox-cancel-editing'
@ -116,14 +117,14 @@ export default class MessageBox extends React.PureComponent {
return !this.state.showEmojiKeyboard ? (<Icon return !this.state.showEmojiKeyboard ? (<Icon
style={styles.actionButtons} style={styles.actionButtons}
onPress={() => this.openEmoji()} onPress={() => this.openEmoji()}
accessibilityLabel='Open emoji selector' accessibilityLabel={I18n.t('Open_emoji_selector')}
accessibilityTraits='button' accessibilityTraits='button'
name='mood' name='mood'
testID='messagebox-open-emoji' testID='messagebox-open-emoji'
/>) : (<Icon />) : (<Icon
onPress={() => this.closeEmoji()} onPress={() => this.closeEmoji()}
style={styles.actionButtons} style={styles.actionButtons}
accessibilityLabel='Close emoji selector' accessibilityLabel={I18n.t('Close_emoji_selector')}
accessibilityTraits='button' accessibilityTraits='button'
name='keyboard' name='keyboard'
testID='messagebox-close-emoji' testID='messagebox-close-emoji'
@ -137,7 +138,7 @@ export default class MessageBox extends React.PureComponent {
style={[styles.actionButtons, { color: '#1D74F5' }]} style={[styles.actionButtons, { color: '#1D74F5' }]}
name='send' name='send'
key='sendIcon' key='sendIcon'
accessibilityLabel='Send message' accessibilityLabel={I18n.t('Send message')}
accessibilityTraits='button' accessibilityTraits='button'
onPress={() => this.submit(this.state.text)} onPress={() => this.submit(this.state.text)}
testID='messagebox-send-message' testID='messagebox-send-message'
@ -148,7 +149,7 @@ export default class MessageBox extends React.PureComponent {
style={[styles.actionButtons, { color: '#1D74F5', paddingHorizontal: 10 }]} style={[styles.actionButtons, { color: '#1D74F5', paddingHorizontal: 10 }]}
name='mic' name='mic'
key='micIcon' key='micIcon'
accessibilityLabel='Send audio message' accessibilityLabel={I18n.t('Send audio message')}
accessibilityTraits='button' accessibilityTraits='button'
onPress={() => this.recordAudioMessage()} onPress={() => this.recordAudioMessage()}
testID='messagebox-send-audio' testID='messagebox-send-audio'
@ -157,7 +158,7 @@ export default class MessageBox extends React.PureComponent {
style={[styles.actionButtons, { color: '#2F343D', fontSize: 16 }]} style={[styles.actionButtons, { color: '#2F343D', fontSize: 16 }]}
name='plus' name='plus'
key='fileIcon' key='fileIcon'
accessibilityLabel='Message actions' accessibilityLabel={I18n.t('Message actions')}
accessibilityTraits='button' accessibilityTraits='button'
onPress={() => this.addFile()} onPress={() => this.addFile()}
testID='messagebox-actions' testID='messagebox-actions'
@ -169,18 +170,13 @@ export default class MessageBox extends React.PureComponent {
const options = { const options = {
maxHeight: 1960, maxHeight: 1960,
maxWidth: 1960, maxWidth: 1960,
quality: 0.8, quality: 0.8
customButtons: [{
name: 'import', title: 'Import File From'
}]
}; };
ImagePicker.showImagePicker(options, (response) => { ImagePicker.showImagePicker(options, (response) => {
if (response.didCancel) { if (response.didCancel) {
console.warn('User cancelled image picker'); console.warn('User cancelled image picker');
} else if (response.error) { } else if (response.error) {
log('ImagePicker Error', response.error); log('ImagePicker Error', response.error);
} else if (response.customButton) {
console.warn('User tapped custom button: ', response.customButton);
} else { } else {
const fileInfo = { const fileInfo = {
name: response.fileName, name: response.fileName,
@ -250,10 +246,10 @@ export default class MessageBox extends React.PureComponent {
_getFixedMentions(keyword) { _getFixedMentions(keyword) {
if ('all'.indexOf(keyword) !== -1) { if ('all'.indexOf(keyword) !== -1) {
this.users = [{ _id: -1, username: 'all', desc: 'all' }, ...this.users]; this.users = [{ _id: -1, username: 'all' }, ...this.users];
} }
if ('here'.indexOf(keyword) !== -1) { if ('here'.indexOf(keyword) !== -1) {
this.users = [{ _id: -2, username: 'here', desc: 'active users' }, ...this.users]; this.users = [{ _id: -2, username: 'here' }, ...this.users];
} }
} }
@ -419,7 +415,7 @@ export default class MessageBox extends React.PureComponent {
onPress={() => this._onPressMention(item)} onPress={() => this._onPressMention(item)}
> >
<Text style={styles.fixedMentionAvatar}>{item.username}</Text> <Text style={styles.fixedMentionAvatar}>{item.username}</Text>
<Text>Notify {item.desc} in this room</Text> <Text>{item.username === 'here' ? I18n.t('Notify_active_in_this_room') : I18n.t('Notify_all_in_this_room')}</Text>
</TouchableOpacity> </TouchableOpacity>
) )
renderMentionEmoji = (item) => { renderMentionEmoji = (item) => {
@ -507,7 +503,7 @@ export default class MessageBox extends React.PureComponent {
returnKeyType='default' returnKeyType='default'
keyboardType='twitter' keyboardType='twitter'
blurOnSubmit={false} blurOnSubmit={false}
placeholder='New Message' placeholder={I18n.t('New_Message')}
onChangeText={text => this.onChangeText(text)} onChangeText={text => this.onChangeText(text)}
value={this.state.text} value={this.state.text}
underlineColorAndroid='transparent' underlineColorAndroid='transparent'

View File

@ -7,6 +7,7 @@ import { errorActionsHide } from '../actions/messages';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import database from '../lib/realm'; import database from '../lib/realm';
import protectedFunction from '../lib/methods/helpers/protectedFunction'; import protectedFunction from '../lib/methods/helpers/protectedFunction';
import I18n from '../i18n';
@connect( @connect(
state => ({ state => ({
@ -27,7 +28,7 @@ export default class MessageErrorActions extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.handleActionPress = this.handleActionPress.bind(this); this.handleActionPress = this.handleActionPress.bind(this);
this.options = ['Cancel', 'Delete', 'Resend']; this.options = [I18n.t('Cancel'), I18n.t('Delete'), I18n.t('Resend')];
this.CANCEL_INDEX = 0; this.CANCEL_INDEX = 0;
this.DELETE_INDEX = 1; this.DELETE_INDEX = 1;
this.RESEND_INDEX = 2; this.RESEND_INDEX = 2;
@ -66,7 +67,7 @@ export default class MessageErrorActions extends React.Component {
return ( return (
<ActionSheet <ActionSheet
ref={o => this.ActionSheet = o} ref={o => this.ActionSheet = o}
title='Messages actions' title={I18n.t('Message_actions')}
options={this.options} options={this.options}
cancelButtonIndex={this.CANCEL_INDEX} cancelButtonIndex={this.CANCEL_INDEX}
destructiveButtonIndex={this.DELETE_INDEX} destructiveButtonIndex={this.DELETE_INDEX}

View File

@ -7,6 +7,7 @@ import { DrawerActions } from 'react-navigation';
import database from '../lib/realm'; import database from '../lib/realm';
import { setServer } from '../actions/server'; import { setServer } from '../actions/server';
import { logout } from '../actions/login'; import { logout } from '../actions/login';
import I18n from '../i18n';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
scrollView: { scrollView: {
@ -115,9 +116,7 @@ export default class Sidebar extends Component {
testID='sidebar-logout' testID='sidebar-logout'
> >
<View style={styles.serverItem}> <View style={styles.serverItem}>
<Text> <Text>{I18n.t('Logout')}</Text>
Logout
</Text>
</View> </View>
</TouchableHighlight> </TouchableHighlight>
<TouchableHighlight <TouchableHighlight
@ -128,9 +127,7 @@ export default class Sidebar extends Component {
testID='sidebar-add-server' testID='sidebar-add-server'
> >
<View style={styles.serverItem}> <View style={styles.serverItem}>
<Text> <Text>{I18n.t('Add_Server')}</Text>
Add Server
</Text>
</View> </View>
</TouchableHighlight> </TouchableHighlight>
</View> </View>

View File

@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { View, StyleSheet, Text, Keyboard, LayoutAnimation } from 'react-native'; import { View, StyleSheet, Text, Keyboard, LayoutAnimation } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import I18n from '../i18n';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
typing: { typing: {
@ -31,7 +32,7 @@ export default class Typing extends React.Component {
} }
get usersTyping() { get usersTyping() {
const users = this.props.usersTyping.filter(_username => this.props.username !== _username); const users = this.props.usersTyping.filter(_username => this.props.username !== _username);
return users.length ? `${ users.join(' ,') } ${ users.length > 1 ? 'are' : 'is' } typing` : ''; return users.length ? `${ users.join(' ,') } ${ users.length > 1 ? I18n.t('are_typing') : I18n.t('is_typing') }` : '';
} }
render() { render() {
const { usersTyping } = this; const { usersTyping } = this;

View File

@ -5,6 +5,7 @@ import Modal from 'react-native-modal';
import Icon from 'react-native-vector-icons/MaterialIcons'; import Icon from 'react-native-vector-icons/MaterialIcons';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import Emoji from './Emoji'; import Emoji from './Emoji';
import I18n from '../../i18n';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
titleContainer: { titleContainer: {
@ -68,11 +69,11 @@ export default class ReactionsModal extends React.PureComponent {
renderItem = (item) => { renderItem = (item) => {
const count = item.usernames.length; const count = item.usernames.length;
let usernames = item.usernames.slice(0, 3) let usernames = item.usernames.slice(0, 3)
.map(username => (username.value === this.props.user.username ? 'you' : username.value)).join(', '); .map(username => (username.value === this.props.user.username ? I18n.t('you') : username.value)).join(', ');
if (count > 3) { if (count > 3) {
usernames = `${ usernames } and more ${ count - 3 }`; usernames = `${ usernames } ${ I18n.t('and_more') } ${ count - 3 }`;
} else { } else {
usernames = usernames.replace(/,(?=[^,]*$)/, ' and'); usernames = usernames.replace(/,(?=[^,]*$)/, ` ${ I18n.t('and') }`);
} }
return ( return (
<View style={styles.itemContainer}> <View style={styles.itemContainer}>
@ -86,7 +87,7 @@ export default class ReactionsModal extends React.PureComponent {
</View> </View>
<View style={styles.peopleItemContainer}> <View style={styles.peopleItemContainer}>
<Text style={styles.reactCount}> <Text style={styles.reactCount}>
{count === 1 ? '1 person' : `${ count } people`} reacted {count === 1 ? I18n.t('1_person_reacted') : I18n.t('N_people_reacted', { n: count })}
</Text> </Text>
<Text style={styles.peopleReacted}>{ usernames }</Text> <Text style={styles.peopleReacted}>{ usernames }</Text>
</View> </View>
@ -113,7 +114,7 @@ export default class ReactionsModal extends React.PureComponent {
size={20} size={20}
onPress={onClose} onPress={onClose}
/> />
<Text style={styles.title}>Reactions</Text> <Text style={styles.title}>{I18n.t('Reactions')}</Text>
</View> </View>
</TouchableWithoutFeedback> </TouchableWithoutFeedback>
<View style={styles.listContainer}> <View style={styles.listContainer}>

View File

@ -21,6 +21,7 @@ import styles from './styles';
import { actionsShow, errorActionsShow, toggleReactionPicker, replyBroadcast } from '../../actions/messages'; import { actionsShow, errorActionsShow, toggleReactionPicker, replyBroadcast } from '../../actions/messages';
import messagesStatus from '../../constants/messagesStatus'; import messagesStatus from '../../constants/messagesStatus';
import Touch from '../../utils/touch'; import Touch from '../../utils/touch';
import I18n from '../../i18n';
const SYSTEM_MESSAGES = [ const SYSTEM_MESSAGES = [
'r', 'r',
@ -44,35 +45,35 @@ const getInfoMessage = ({
t, role, msg, u t, role, msg, u
}) => { }) => {
if (t === 'rm') { if (t === 'rm') {
return 'Message removed'; return I18n.t('Message_removed');
} else if (t === 'uj') { } else if (t === 'uj') {
return 'Has joined the channel.'; return I18n.t('Has_joined_the_channel');
} else if (t === 'r') { } else if (t === 'r') {
return `Room name changed to: ${ msg } by ${ u.username }`; return I18n.t('Room_name_changed', { name: msg, userBy: u.username });
} else if (t === 'message_pinned') { } else if (t === 'message_pinned') {
return 'Message pinned'; return I18n.t('Message_pinned');
} else if (t === 'ul') { } else if (t === 'ul') {
return 'Has left the channel.'; return I18n.t('Has_left_the_channel');
} else if (t === 'ru') { } else if (t === 'ru') {
return `User ${ msg } removed by ${ u.username }`; return I18n.t('User_removed_by', { userRemoved: msg, userBy: u.username });
} else if (t === 'au') { } else if (t === 'au') {
return `User ${ msg } added by ${ u.username }`; return I18n.t('User_added_by', { userAdded: msg, userBy: u.username });
} else if (t === 'user-muted') { } else if (t === 'user-muted') {
return `User ${ msg } muted by ${ u.username }`; return I18n.t('User_muted_by', { userMuted: msg, userBy: u.username });
} else if (t === 'user-unmuted') { } else if (t === 'user-unmuted') {
return `User ${ msg } unmuted by ${ u.username }`; return I18n.t('User_unmuted_by', { userUnmuted: msg, userBy: u.username });
} else if (t === 'subscription-role-added') { } else if (t === 'subscription-role-added') {
return `${ msg } was set ${ role } by ${ u.username }`; return `${ msg } was set ${ role } by ${ u.username }`;
} else if (t === 'subscription-role-removed') { } else if (t === 'subscription-role-removed') {
return `${ msg } is no longer ${ role } by ${ u.username }`; return `${ msg } is no longer ${ role } by ${ u.username }`;
} else if (t === 'room_changed_description') { } else if (t === 'room_changed_description') {
return `Room description changed to: ${ msg } by ${ u.username }`; return I18n.t('Room_changed_description', { description: msg, userBy: u.username });
} else if (t === 'room_changed_announcement') { } else if (t === 'room_changed_announcement') {
return `Room announcement changed to: ${ msg } by ${ u.username }`; return I18n.t('Room_changed_announcement', { announcement: msg, userBy: u.username });
} else if (t === 'room_changed_topic') { } else if (t === 'room_changed_topic') {
return `Room topic changed to: ${ msg } by ${ u.username }`; return I18n.t('Room_changed_topic', { topic: msg, userBy: u.username });
} else if (t === 'room_changed_privacy') { } else if (t === 'room_changed_privacy') {
return `Room type changed to: ${ msg } by ${ u.username }`; return I18n.t('Room_changed_privacy', { type: msg, userBy: u.username });
} }
return ''; return '';
}; };
@ -334,7 +335,7 @@ export default class Message extends React.Component {
} = this.props; } = this.props;
const username = item.alias || item.u.username; const username = item.alias || item.u.username;
const isEditing = message._id === item._id && editing; const isEditing = message._id === item._id && editing;
const accessibilityLabel = `Message from ${ username } at ${ moment(item.ts).format(this.timeFormat) }, ${ this.props.item.msg }`; const accessibilityLabel = I18n.t('Message_accessibility', { user: username, time: moment(item.ts).format(this.timeFormat), message: this.props.item.msg });
return ( return (
<Touch <Touch

View File

@ -17,6 +17,9 @@ import RoomFilesView from '../../views/RoomFilesView';
import RoomMembersView from '../../views/RoomMembersView'; import RoomMembersView from '../../views/RoomMembersView';
import RoomInfoView from '../../views/RoomInfoView'; import RoomInfoView from '../../views/RoomInfoView';
import RoomInfoEditView from '../../views/RoomInfoEditView'; import RoomInfoEditView from '../../views/RoomInfoEditView';
import I18n from '../../i18n';
const headerTintColor = '#292E35';
const AuthRoutes = createStackNavigator( const AuthRoutes = createStackNavigator(
{ {
@ -29,92 +32,92 @@ const AuthRoutes = createStackNavigator(
CreateChannel: { CreateChannel: {
screen: CreateChannelView, screen: CreateChannelView,
navigationOptions: { navigationOptions: {
title: 'Create Channel', title: I18n.t('Create_Channel'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
SelectedUsers: { SelectedUsers: {
screen: SelectedUsersView, screen: SelectedUsersView,
navigationOptions: { navigationOptions: {
title: 'Select Users', title: I18n.t('Select_Users'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
AddServer: { AddServer: {
screen: NewServerView, screen: NewServerView,
navigationOptions: { navigationOptions: {
title: 'New server', title: I18n.t('New_Server'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
RoomActions: { RoomActions: {
screen: RoomActionsView, screen: RoomActionsView,
navigationOptions: { navigationOptions: {
title: 'Actions', title: I18n.t('Actions'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
StarredMessages: { StarredMessages: {
screen: StarredMessagesView, screen: StarredMessagesView,
navigationOptions: { navigationOptions: {
title: 'Starred Messages', title: I18n.t('Starred_Messages'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
PinnedMessages: { PinnedMessages: {
screen: PinnedMessagesView, screen: PinnedMessagesView,
navigationOptions: { navigationOptions: {
title: 'Pinned Messages', title: I18n.t('Pinned_Messages'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
MentionedMessages: { MentionedMessages: {
screen: MentionedMessagesView, screen: MentionedMessagesView,
navigationOptions: { navigationOptions: {
title: 'Mentioned Messages', title: I18n.t('Mentioned_Messages'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
SnippetedMessages: { SnippetedMessages: {
screen: SnippetedMessagesView, screen: SnippetedMessagesView,
navigationOptions: { navigationOptions: {
title: 'Snippet Messages', title: I18n.t('Snippet_Messages'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
SearchMessages: { SearchMessages: {
screen: SearchMessagesView, screen: SearchMessagesView,
navigationOptions: { navigationOptions: {
title: 'Search Messages', title: I18n.t('Search_Messages'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
RoomFiles: { RoomFiles: {
screen: RoomFilesView, screen: RoomFilesView,
navigationOptions: { navigationOptions: {
title: 'Room Files', title: I18n.t('Room_Files'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
RoomMembers: { RoomMembers: {
screen: RoomMembersView, screen: RoomMembersView,
navigationOptions: { navigationOptions: {
title: 'Room Members', title: I18n.t('Room_Members'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
RoomInfo: { RoomInfo: {
screen: RoomInfoView, screen: RoomInfoView,
navigationOptions: { navigationOptions: {
title: 'Room Info', title: I18n.t('Room_Info'),
headerTintColor: '#292E35' headerTintColor
} }
}, },
RoomInfoEdit: { RoomInfoEdit: {
screen: RoomInfoEditView, screen: RoomInfoEditView,
navigationOptions: { navigationOptions: {
title: 'Room Info Edit', title: I18n.t('Room_Info_Edit'),
headerTintColor: '#292E35' headerTintColor
} }
} }
}, },

View File

@ -13,6 +13,7 @@ import TermsServiceView from '../../views/TermsServiceView';
import PrivacyPolicyView from '../../views/PrivacyPolicyView'; import PrivacyPolicyView from '../../views/PrivacyPolicyView';
import ForgotPasswordView from '../../views/ForgotPasswordView'; import ForgotPasswordView from '../../views/ForgotPasswordView';
import database from '../../lib/realm'; import database from '../../lib/realm';
import I18n from '../../i18n';
const hasServers = () => { const hasServers = () => {
const db = database.databases.serversDB.objects('servers'); const db = database.databases.serversDB.objects('servers');
@ -24,12 +25,12 @@ const ServerStack = createStackNavigator({
screen: ListServerView, screen: ListServerView,
navigationOptions({ navigation }) { navigationOptions({ navigation }) {
return { return {
title: 'Servers', title: I18n.t('Servers'),
headerRight: ( headerRight: (
<TouchableOpacity <TouchableOpacity
onPress={() => navigation.navigate({ key: 'AddServer', routeName: 'AddServer' })} onPress={() => navigation.navigate({ key: 'AddServer', routeName: 'AddServer' })}
style={{ width: 50, alignItems: 'center' }} style={{ width: 50, alignItems: 'center' }}
accessibilityLabel='Add server' accessibilityLabel={I18n.t('Add_Server')}
accessibilityTraits='button' accessibilityTraits='button'
> >
<Icon name='plus' size={16} /> <Icon name='plus' size={16} />
@ -65,7 +66,7 @@ const LoginStack = createStackNavigator({
ForgotPassword: { ForgotPassword: {
screen: ForgotPasswordView, screen: ForgotPasswordView,
navigationOptions: { navigationOptions: {
title: 'Forgot my password', title: I18n.t('Forgot_my_password'),
headerTintColor: '#292E35' headerTintColor: '#292E35'
} }
} }
@ -83,14 +84,14 @@ const RegisterStack = createStackNavigator({
TermsService: { TermsService: {
screen: TermsServiceView, screen: TermsServiceView,
navigationOptions: { navigationOptions: {
title: 'Terms of service', title: I18n.t('Terms_of_Service'),
headerTintColor: '#292E35' headerTintColor: '#292E35'
} }
}, },
PrivacyPolicy: { PrivacyPolicy: {
screen: PrivacyPolicyView, screen: PrivacyPolicyView,
navigationOptions: { navigationOptions: {
title: 'Privacy policy', title: I18n.t('Privacy_Policy'),
headerTintColor: '#292E35' headerTintColor: '#292E35'
} }
} }

10
app/i18n/index.js Normal file
View File

@ -0,0 +1,10 @@
import I18n from 'react-native-i18n';
import en from './locales/en';
I18n.fallbacks = true;
I18n.translations = {
en
};
export default I18n;

216
app/i18n/locales/en.js Normal file
View File

@ -0,0 +1,216 @@
export default {
'1_online_member': '1 online member',
'1_person_reacted': '1 person reacted',
Actions: 'Actions',
Add_Reaction: 'Add Reaction',
Add_Server: 'Add Server',
Add_user: 'Add user',
Alert: 'Alert',
alert: 'alert',
alerts: 'alerts',
All_users_in_the_channel_can_write_new_messages: 'All users in the channel can write new messages',
All: 'All',
Allow_Reactions: 'Allow Reactions',
and_more: 'and more',
and: 'and',
announcement: 'announcement',
Announcement: 'Announcement',
ARCHIVE: 'ARCHIVE',
archive: 'archive',
are_typing: 'are typing',
Are_you_sure_question_mark: 'Are you sure?',
Are_you_sure_you_want_to_leave_the_room: 'Are you sure you want to leave the room {{room}}?',
Authenticating: 'Authenticating',
Away: 'Away',
Block_user: 'Block user',
Broadcast_channel_Description: 'Only authorized users can write new messages, but the other users will be able to reply',
Broadcast_Channel: 'Broadcast Channel',
Busy: 'Busy',
By_proceeding_you_are_agreeing: 'By proceeding you are agreeing to our',
Cancel_editing: 'Cancel editing',
Cancel_recording: 'Cancel recording',
Cancel: 'Cancel',
Channel_Name: 'Channel Name',
Close_emoji_selector: 'Close emoji selector',
Code: 'Code',
Colaborative: 'Colaborative',
Connect: 'Connect',
Connected_to: 'Connected to',
Connecting: 'Connecting',
Copied_to_clipboard: 'Copied to clipboard!',
Copy_Message: 'Copy Message',
Copy_Permalink: 'Copy Permalink',
Create_account: 'Create account',
Create_Channel: 'Create Channel',
Create: 'Create',
Delete_Room_Warning: 'Deleting a room will delete all messages posted within the room. This cannot be undone.',
delete: 'delete',
Delete: 'Delete',
DELETE: 'DELETE',
description: 'description',
Description: 'Description',
Disable_notifications: 'Disable notifications',
Do_you_really_want_to_key_this_room_question_mark: 'Do you really want to {{key}} this room?',
edit: 'edit',
Edit: 'Edit',
Email_or_password_field_is_empty: 'Email or password field is empty',
Email: 'Email',
Enable_notifications: 'Enable notifications',
Everyone_can_access_this_channel: 'Everyone can access this channel',
Files: 'Files',
Finish_recording: 'Finish recording',
Forgot_my_password: 'Forgot my password',
Forgot_password_If_this_email_is_registered: 'If this email is registered, we\'ll send instructions on how to reset your password. If you do not receive an email shortly, please come back and try again.',
Forgot_password: 'Forgot password',
Has_joined_the_channel: 'Has joined the channel',
Has_left_the_channel: 'Has left the channel',
I_have_an_account: 'I have an account',
Invisible: 'Invisible',
is_a_valid_RocketChat_instance: 'is a valid Rocket.Chat instance',
is_not_a_valid_RocketChat_instance: 'is not a valid Rocket.Chat instance',
is_typing: 'is typing',
Just_invited_people_can_access_this_channel: 'Just invited people can access this channel',
last_message: 'last message',
Leave_channel: 'Leave channel',
leave: 'leave',
Loading_messages_ellipsis: 'Loading messages...',
Login: 'Login',
Logout: 'Logout',
Members: 'Members',
Mentioned_Messages: 'Mentioned Messages',
mentioned: 'mentioned',
Mentions: 'Mentions',
Message_accessibility: 'Message from {{user}} at {{time}}: {{message}}',
Message_actions: 'Message actions',
Message_pinned: 'Message pinned',
Message_removed: 'Message removed',
Microphone_Permission_Message: 'Rocket Chat needs access to your microphone so you can send audio message.',
Microphone_Permission: 'Microphone Permission',
Mute: 'Mute',
muted: 'muted',
My_servers: 'My servers',
N_online_members: '{{n}} online members',
N_person_reacted: '{{n}} people reacted',
Name: 'Name',
New_in_RocketChat_question_mark: 'New in Rocket.Chat?',
New_Message: 'New Message',
New_Server: 'New Server',
No_files: 'No files',
No_mentioned_messages: 'No mentioned messages',
No_pinned_messages: 'No pinned messages',
No_snippeted_messages: 'No snippeted messages',
No_starred_messages: 'No starred messages',
No_announcement_provided: 'No announcement provided.',
No_description_provided: 'No description provided.',
No_topic_provided: 'No topic provided.',
No_Message: 'No Message',
No_Reactions: 'No Reactions',
Not_logged: 'Not logged',
Nothing_to_save: 'Nothing to save!',
Notify_active_in_this_room: 'Notify active users in this room',
Notify_all_in_this_room: 'Notify all in this room',
Offline: 'Offline',
Online: 'Online',
Only_authorized_users_can_write_new_messages: 'Only authorized users can write new messages',
Open_emoji_selector: 'Open emoji selector',
Or_continue_using_social_accounts: 'Or continue using social accounts',
Password: 'Password',
Permalink_copied_to_clipboard: 'Permalink copied to clipboard!',
Pin: 'Pin',
Pinned_Messages: 'Pinned Messages',
pinned: 'pinned',
Pinned: 'Pinned',
Privacy_Policy: ' Privacy Policy',
Private_Channel: 'Private Channel',
Private: 'Private',
Public_Channel: 'Public Channel',
Public: 'Public',
Quote: 'Quote',
Reactions_are_disabled: 'Reactions are disabled',
Reactions_are_enabled: 'Reactions are enabled',
Reactions: 'Reactions',
Read_Only_Channel: 'Read Only Channel',
Read_Only: 'Read Only',
Register: 'Register',
Repeat_Password: 'Repeat Password',
Reply: 'Reply',
Resend: 'Resend',
Reset_password: 'Reset password',
RESET: 'RESET',
Roles: 'Roles',
Room_actions: 'Room actions',
Room_changed_announcement: 'Room announcement changed to: {{announcement}} by {{userBy}}',
Room_changed_description: 'Room description changed to: {{description}} by {{userBy}}',
Room_changed_privacy: 'Room type changed to: {{type}} by {{userBy}}',
Room_changed_topic: 'Room topic changed to: {{topic}} by {{userBy}}',
Room_Files: 'Room Files',
Room_Info_Edit: 'Room Info Edit',
Room_Info: 'Room Info',
Room_Members: 'Room Members',
Room_name_changed: 'Room name changed to: {{name}} by {{userBy}}',
SAVE: 'SAVE',
Search_Messages: 'Search Messages',
Search: 'Search',
Select_Users: 'Select Users',
Send_audio_message: 'Send audio message',
Send_message: 'Send message',
Servers: 'Servers',
Settings_succesfully_changed: 'Settings succesfully changed!',
Share_Message: 'Share Message',
Share: 'Share',
Sign_in_your_server: 'Sign in your server',
Sign_Up: 'Sign Up',
Snippet_Messages: 'Snippet Messages',
snippeted: 'snippeted',
Snippets: 'Snippets',
Some_field_is_invalid_or_empty: 'Some field is invalid or empty',
Star_room: 'Star room',
Star: 'Star',
Starred_Messages: 'Starred Messages',
starred: 'starred',
Starred: 'Starred',
Start_of_conversation: 'Start of conversation',
Submit: 'Submit',
tap_to_change_status: 'tap to change status',
Tap_to_view_servers_list: 'Tap to view servers list',
Terms_of_Service: ' Terms of Service ',
There_was_an_error_while_saving_settings: 'There was an error while saving settings!',
This_room_is_blocked: 'This room is blocked',
This_room_is_read_only: 'This room is read only',
Timezone: 'Timezone',
topic: 'topic',
Topic: 'Topic',
Type_the_channel_name_here: 'Type the channel name here',
unarchive: 'unarchive',
UNARCHIVE: 'UNARCHIVE',
Unblock_user: 'Unblock user',
Unmute: 'Unmute',
unmuted: 'unmuted',
Unpin: 'Unpin',
unread_messages: 'unread messages',
Unstar: 'Unstar',
User_added_by: 'User {{userAdded}} added by {{userBy}}',
User_has_been_key: 'User has been {{key}}!',
User_is_no_longer_role_by_: '{{user}} is no longer {{role}} by {{userBy}}',
User_muted_by: 'User {{userMuted}} muted by {{userBy}}',
User_removed_by: 'User {{userRemoved}} removed by {{userBy}}',
User_unmuted_by: 'User {{userUnmuted}} unmuted by {{userBy}}',
User_was_set_role_by_: '{{user}} was set {{role}} by {{userBy}}',
Username_is_empty: 'Username is empty',
Username: 'Username',
Validating: 'Validating',
Video_call: 'Video call',
Voice_call: 'Voice call',
Welcome_title_pt_1: 'Prepare to take off with',
Welcome_title_pt_2: 'the ultimate chat platform',
Yes_action_it: 'Yes, {{action}} it!',
Yesterday: 'Yesterday',
You_are_in_preview_mode: 'You are in preview mode',
You_are_offline: 'You are offline',
You_can_search_using_RegExp_eg: 'You can search using RegExp. e.g. `/^text$/i`',
You_colon: 'You: ',
you_were_mentioned: 'you were mentioned',
You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!',
you: 'you',
Your_server: 'Your server'
};

View File

@ -2,7 +2,6 @@ import normalizeMessage from './normalizeMessage';
// TODO: delete and update // TODO: delete and update
export const merge = (subscription, room) => { export const merge = (subscription, room) => {
subscription.muted = [];
if (room) { if (room) {
if (room.rid) { if (room.rid) {
subscription.rid = room.rid; subscription.rid = room.rid;
@ -19,7 +18,9 @@ export const merge = (subscription, room) => {
subscription.broadcast = room.broadcast; subscription.broadcast = room.broadcast;
if (room.muted && room.muted.length) { if (room.muted && room.muted.length) {
subscription.muted = room.muted.filter(user => user).map(user => ({ value: user })); subscription.muted = room.muted.map(user => ({ value: user }));
} else {
subscription.muted = [];
} }
} }
if (subscription.roles && subscription.roles.length) { if (subscription.roles && subscription.roles.length) {

View File

@ -4,13 +4,13 @@ import PropTypes from 'prop-types';
import { View, Text, StyleSheet, ViewPropTypes } from 'react-native'; import { View, Text, StyleSheet, ViewPropTypes } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
// import SimpleMarkdown from 'simple-markdown';
import Avatar from '../containers/Avatar'; import Avatar from '../containers/Avatar';
import Status from '../containers/status'; import Status from '../containers/status';
import Touch from '../utils/touch/index'; //eslint-disable-line import Touch from '../utils/touch/index'; //eslint-disable-line
import Markdown from '../containers/message/Markdown'; import Markdown from '../containers/message/Markdown';
import RoomTypeIcon from '../containers/RoomTypeIcon'; import RoomTypeIcon from '../containers/RoomTypeIcon';
import I18n from '../i18n';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -98,36 +98,6 @@ const styles = StyleSheet.create({
marginTop: 3 marginTop: 3
} }
}); });
// const markdownStyle = { block: { marginBottom: 0, flexWrap: 'wrap', flexDirection: 'row' } };
// const parseInline = (parse, content, state) => {
// const isCurrentlyInline = state.inline || false;
// state.inline = true;
// const result = parse(content, state);
// state.inline = isCurrentlyInline;
// return result;
// };
// const parseCaptureInline = (capture, parse, state) => ({ content: parseInline(parse, capture[1], state) });
// const customRules = {
// strong: {
// order: -4,
// match: SimpleMarkdown.inlineRegex(/^\*\*([\s\S]+?)\*\*(?!\*)/),
// parse: parseCaptureInline,
// react: (node, output, state) => ({
// type: 'strong',
// key: state.key,
// props: {
// children: output(node.content, state)
// }
// })
// },
// text: {
// order: -3,
// match: SimpleMarkdown.inlineRegex(/^[\s\S]+?(?=[^0-9A-Za-z\s\u00c0-\uffff]|\n\n| {2,}\n|\w+:\S|$)/),
// parse: capture => ({ content: capture[0] }),
// react: node => node.content
// }
// };
const renderNumber = (unread, userMentions) => { const renderNumber = (unread, userMentions) => {
if (!unread || unread <= 0) { if (!unread || unread <= 0) {
@ -207,13 +177,13 @@ export default class RoomItem extends React.Component {
return ''; return '';
} }
if (!lastMessage) { if (!lastMessage) {
return 'No Message'; return I18n.t('No_Message');
} }
let prefix = ''; let prefix = '';
if (lastMessage.u.username === this.props.user.username) { if (lastMessage.u.username === this.props.user.username) {
prefix = 'You: '; prefix = I18n.t('You_colon');
} else if (type !== 'd') { } else if (type !== 'd') {
prefix = `${ lastMessage.u.username }: `; prefix = `${ lastMessage.u.username }: `;
} }
@ -234,7 +204,7 @@ export default class RoomItem extends React.Component {
} }
formatDate = date => moment(date).calendar(null, { formatDate = date => moment(date).calendar(null, {
lastDay: '[Yesterday]', lastDay: `[${ I18n.t('Yesterday') }]`,
sameDay: 'h:mm A', sameDay: 'h:mm A',
lastWeek: 'dddd', lastWeek: 'dddd',
sameElse: 'MMM D' sameElse: 'MMM D'
@ -249,17 +219,17 @@ export default class RoomItem extends React.Component {
let accessibilityLabel = name; let accessibilityLabel = name;
if (unread === 1) { if (unread === 1) {
accessibilityLabel += `, ${ unread } alert`; accessibilityLabel += `, ${ unread } ${ I18n.t('alert') }`;
} else if (unread > 1) { } else if (unread > 1) {
accessibilityLabel += `, ${ unread } alerts`; accessibilityLabel += `, ${ unread } ${ I18n.t('alerts') }`;
} }
if (userMentions > 0) { if (userMentions > 0) {
accessibilityLabel += ', you were mentioned'; accessibilityLabel += `, ${ I18n.t('you_were_mentioned') }`;
} }
if (date) { if (date) {
accessibilityLabel += `, last message ${ date }`; accessibilityLabel += `, ${ I18n.t('last_message') } ${ date }`;
} }
return ( return (

View File

@ -98,7 +98,7 @@ const handleReplyBroadcast = function* handleReplyBroadcast({ message }) {
} }
yield delay(100); yield delay(100);
const server = yield select(state => state.server.server); const server = yield select(state => state.server.server);
const msg = `[ ](${ server }/direct/${ username }?msg=${ message._id })`; const msg = `[ ](${ server }/direct/${ username }?msg=${ message._id }) `;
yield put(setInput({ msg })); yield put(setInput({ msg }));
} catch (e) { } catch (e) {
log('handleReplyBroadcast', e); log('handleReplyBroadcast', e);

View File

@ -11,6 +11,7 @@ import styles from './Styles';
import KeyboardView from '../presentation/KeyboardView'; import KeyboardView from '../presentation/KeyboardView';
import scrollPersistTaps from '../utils/scrollPersistTaps'; import scrollPersistTaps from '../utils/scrollPersistTaps';
import Button from '../containers/Button'; import Button from '../containers/Button';
import I18n from '../i18n';
@connect( @connect(
state => ({ state => ({
@ -22,9 +23,6 @@ import Button from '../containers/Button';
}) })
) )
export default class CreateChannelView extends LoggedView { export default class CreateChannelView extends LoggedView {
static navigationOptions = () => ({
title: 'Create a New Channel'
});
static propTypes = { static propTypes = {
create: PropTypes.func.isRequired, create: PropTypes.func.isRequired,
createChannel: PropTypes.object.isRequired, createChannel: PropTypes.object.isRequired,
@ -99,8 +97,8 @@ export default class CreateChannelView extends LoggedView {
return this.renderSwitch({ return this.renderSwitch({
id: 'type', id: 'type',
value: type, value: type,
label: type ? 'Private Channel' : 'Public Channel', label: type ? I18n.t('Private_Channel') : I18n.t('Public_Channel'),
description: type ? 'Just invited people can access this channel' : 'Everyone can access this channel', description: type ? I18n.t('Just_invited_people_can_access_this_channel') : I18n.t('Everyone_can_access_this_channel'),
onValueChange: value => this.setState({ type: value }) onValueChange: value => this.setState({ type: value })
}); });
} }
@ -110,8 +108,8 @@ export default class CreateChannelView extends LoggedView {
return this.renderSwitch({ return this.renderSwitch({
id: 'readonly', id: 'readonly',
value: readOnly, value: readOnly,
label: 'Read Only Channel', label: I18n.t('Read_Only_Channel'),
description: readOnly ? 'Only authorized users can write new messages' : 'All users in the channel can write new messages', description: readOnly ? I18n.t('Only_authorized_users_can_write_new_messages') : I18n.t('All_users_in_the_channel_can_write_new_messages'),
onValueChange: value => this.setState({ readOnly: value }), onValueChange: value => this.setState({ readOnly: value }),
disabled: broadcast disabled: broadcast
}); });
@ -122,8 +120,8 @@ export default class CreateChannelView extends LoggedView {
return this.renderSwitch({ return this.renderSwitch({
id: 'broadcast', id: 'broadcast',
value: broadcast, value: broadcast,
label: 'Broadcast Channel', label: I18n.t('Broadcast_Channel'),
description: 'Only authorized users can write new messages, but the other users will be able to reply', description: I18n.t('Broadcast_channel_Description'),
onValueChange: (value) => { onValueChange: (value) => {
this.setState({ this.setState({
broadcast: value, broadcast: value,
@ -142,10 +140,10 @@ export default class CreateChannelView extends LoggedView {
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
<SafeAreaView testID='create-channel-view'> <SafeAreaView testID='create-channel-view'>
<RCTextInput <RCTextInput
label='Channel Name' label={I18n.t('Channel_Name')}
value={this.state.channelName} value={this.state.channelName}
onChangeText={channelName => this.setState({ channelName })} onChangeText={channelName => this.setState({ channelName })}
placeholder='Type the channel name here' placeholder={I18n.t('Type_the_channel_name_here')}
returnKeyType='done' returnKeyType='done'
autoFocus autoFocus
testID='create-channel-name' testID='create-channel-name'
@ -156,7 +154,7 @@ export default class CreateChannelView extends LoggedView {
{this.renderBroadcast()} {this.renderBroadcast()}
<View style={styles.alignItemsFlexStart}> <View style={styles.alignItemsFlexStart}>
<Button <Button
title='Create' title={I18n.t('Create')}
type='primary' type='primary'
onPress={this.submit} onPress={this.submit}
disabled={this.state.channelName.length === 0 || this.props.createChannel.isFetching} disabled={this.state.channelName.length === 0 || this.props.createChannel.isFetching}

View File

@ -12,6 +12,7 @@ import Loading from '../containers/Loading';
import styles from './Styles'; import styles from './Styles';
import { showErrorAlert } from '../utils/info'; import { showErrorAlert } from '../utils/info';
import scrollPersistTaps from '../utils/scrollPersistTaps'; import scrollPersistTaps from '../utils/scrollPersistTaps';
import I18n from '../i18n';
@connect(state => ({ @connect(state => ({
login: state.login login: state.login
@ -45,12 +46,7 @@ export default class ForgotPasswordView extends LoggedView {
if (login.success) { if (login.success) {
this.props.navigation.goBack(); this.props.navigation.goBack();
setTimeout(() => { setTimeout(() => {
showErrorAlert( showErrorAlert(I18n.t('Forgot_password_If_this_email_is_registered'), I18n.t('Alert'));
'If this email is registered, ' +
'we\'ll send instructions on how to reset your password. ' +
'If you do not receive an email shortly, please come back and try again.',
'Alert'
);
}); });
} }
} }
@ -85,8 +81,8 @@ export default class ForgotPasswordView extends LoggedView {
<View style={styles.formContainer}> <View style={styles.formContainer}>
<TextInput <TextInput
inputStyle={this.state.invalidEmail ? { borderColor: 'red' } : {}} inputStyle={this.state.invalidEmail ? { borderColor: 'red' } : {}}
label='Email' label={I18n.t('Email')}
placeholder='Email' placeholder={I18n.t('Email')}
keyboardType='email-address' keyboardType='email-address'
returnKeyType='next' returnKeyType='next'
onChangeText={email => this.validate(email)} onChangeText={email => this.validate(email)}
@ -96,7 +92,7 @@ export default class ForgotPasswordView extends LoggedView {
<View style={styles.alignItemsFlexStart}> <View style={styles.alignItemsFlexStart}>
<Button <Button
title='Reset password' title={I18n.t('Reset_password')}
type='primary' type='primary'
onPress={this.resetPassword} onPress={this.resetPassword}
testID='forgot-password-view-submit' testID='forgot-password-view-submit'

View File

@ -12,6 +12,7 @@ import { setServer } from '../actions/server';
import database from '../lib/realm'; import database from '../lib/realm';
import Fade from '../animations/fade'; import Fade from '../animations/fade';
import Touch from '../utils/touch'; import Touch from '../utils/touch';
import I18n from '../i18n';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
view: { view: {
@ -141,7 +142,7 @@ class ListServerView extends LoggedView {
getState = () => { getState = () => {
const sections = [{ const sections = [{
title: 'My servers', title: I18n.t('My_servers'),
data: this.data data: this.data
}]; }];
// //

View File

@ -15,6 +15,7 @@ import scrollPersistTaps from '../utils/scrollPersistTaps';
import random from '../utils/random'; import random from '../utils/random';
import Button from '../containers/Button'; import Button from '../containers/Button';
import Loading from '../containers/Loading'; import Loading from '../containers/Loading';
import I18n from '../i18n';
const userAgentAndroid = 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1'; const userAgentAndroid = 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1';
const userAgent = Platform.OS === 'ios' ? 'UserAgent' : userAgentAndroid; const userAgent = Platform.OS === 'ios' ? 'UserAgent' : userAgentAndroid;
@ -205,7 +206,7 @@ export default class LoginSignupView extends LoggedView {
return ( return (
<View style={styles.servicesContainer}> <View style={styles.servicesContainer}>
<Text style={styles.servicesTitle}> <Text style={styles.servicesTitle}>
Or continue using Social accounts {I18n.t('Or_continue_using_social_accounts')}
</Text> </Text>
<View style={sharedStyles.loginOAuthButtons} key='services'> <View style={sharedStyles.loginOAuthButtons} key='services'>
{this.props.Accounts_OAuth_Facebook && this.props.services.facebook && {this.props.Accounts_OAuth_Facebook && this.props.services.facebook &&
@ -284,20 +285,20 @@ export default class LoginSignupView extends LoggedView {
style={sharedStyles.loginLogo} style={sharedStyles.loginLogo}
resizeMode='center' resizeMode='center'
/> />
<Text style={[sharedStyles.loginText, styles.header, { color: '#81848A' }]}>Prepare to take off with</Text> <Text style={[sharedStyles.loginText, styles.header, { color: '#81848A' }]}>{I18n.t('Welcome_title_pt_1')}</Text>
<Text style={[sharedStyles.loginText, styles.header]}>the ultimate chat platform</Text> <Text style={[sharedStyles.loginText, styles.header]}>{I18n.t('Welcome_title_pt_2')}</Text>
<Image <Image
style={styles.planetImage} style={styles.planetImage}
source={require('../static/images/planet.png')} source={require('../static/images/planet.png')}
/> />
<Button <Button
title='I have an account' title={I18n.t('I_have_an_account')}
type='primary' type='primary'
onPress={() => this.props.navigation.navigate({ key: 'Login', routeName: 'Login' })} onPress={() => this.props.navigation.navigate({ key: 'Login', routeName: 'Login' })}
testID='welcome-view-login' testID='welcome-view-login'
/> />
<Button <Button
title='Create account' title={I18n.t('Create_account')}
type='secondary' type='secondary'
onPress={() => this.props.navigation.navigate({ key: 'Register', routeName: 'Register' })} onPress={() => this.props.navigation.navigate({ key: 'Register', routeName: 'Register' })}
testID='welcome-view-register' testID='welcome-view-register'

View File

@ -15,6 +15,7 @@ import scrollPersistTaps from '../utils/scrollPersistTaps';
import { showToast } from '../utils/info'; import { showToast } from '../utils/info';
import { COLOR_BUTTON_PRIMARY } from '../constants/colors'; import { COLOR_BUTTON_PRIMARY } from '../constants/colors';
import LoggedView from './View'; import LoggedView from './View';
import I18n from '../i18n';
@connect(state => ({ @connect(state => ({
server: state.server.server, server: state.server.server,
@ -44,7 +45,7 @@ export default class LoginView extends LoggedView {
submit = async() => { submit = async() => {
const { username, password, code } = this.state; const { username, password, code } = this.state;
if (username.trim() === '' || password.trim() === '') { if (username.trim() === '' || password.trim() === '') {
showToast('Email or password field is empty'); showToast(I18n.t('Email_or_password_field_is_empty'));
return; return;
} }
Keyboard.dismiss(); Keyboard.dismiss();
@ -62,9 +63,9 @@ export default class LoginView extends LoggedView {
return ( return (
<TextInput <TextInput
inputRef={ref => this.codeInput = ref} inputRef={ref => this.codeInput = ref}
label='Code' label={I18n.t('Code')}
onChangeText={code => this.setState({ code })} onChangeText={code => this.setState({ code })}
placeholder='Code' placeholder={I18n.t('Code')}
keyboardType='numeric' keyboardType='numeric'
returnKeyType='done' returnKeyType='done'
autoCapitalize='none' autoCapitalize='none'
@ -87,8 +88,8 @@ export default class LoginView extends LoggedView {
<CloseModalButton navigation={this.props.navigation} /> <CloseModalButton navigation={this.props.navigation} />
<Text style={[styles.loginText, styles.loginTitle]}>Login</Text> <Text style={[styles.loginText, styles.loginTitle]}>Login</Text>
<TextInput <TextInput
label='Username' label={I18n.t('Username')}
placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || 'Username'} placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || I18n.t('Username')}
keyboardType='email-address' keyboardType='email-address'
returnKeyType='next' returnKeyType='next'
iconLeft='at' iconLeft='at'
@ -99,8 +100,8 @@ export default class LoginView extends LoggedView {
<TextInput <TextInput
inputRef={(e) => { this.password = e; }} inputRef={(e) => { this.password = e; }}
label='Password' label={I18n.t('Password')}
placeholder={this.props.Accounts_PasswordPlaceholder || 'Password'} placeholder={this.props.Accounts_PasswordPlaceholder || I18n.t('Password')}
returnKeyType='done' returnKeyType='done'
iconLeft='key-variant' iconLeft='key-variant'
secureTextEntry secureTextEntry
@ -113,7 +114,7 @@ export default class LoginView extends LoggedView {
<View style={styles.alignItemsFlexStart}> <View style={styles.alignItemsFlexStart}>
<Button <Button
title='Login' title={I18n.t('Login')}
type='primary' type='primary'
onPress={this.submit} onPress={this.submit}
testID='login-view-submit' testID='login-view-submit'
@ -122,15 +123,15 @@ export default class LoginView extends LoggedView {
style={[styles.loginText, { marginTop: 10 }]} style={[styles.loginText, { marginTop: 10 }]}
testID='login-view-register' testID='login-view-register'
onPress={() => this.props.navigation.navigate('Register')} onPress={() => this.props.navigation.navigate('Register')}
>New in Rocket.Chat? &nbsp; >{I18n.t('New_in_RocketChat_question_mark')} &nbsp;
<Text style={{ color: COLOR_BUTTON_PRIMARY }}>Sign Up <Text style={{ color: COLOR_BUTTON_PRIMARY }}>{I18n.t('Sign_Up')}
</Text> </Text>
</Text> </Text>
<Text <Text
style={[styles.loginText, { marginTop: 20, fontSize: 13 }]} style={[styles.loginText, { marginTop: 20, fontSize: 13 }]}
onPress={() => this.props.navigation.navigate('ForgotPassword')} onPress={() => this.props.navigation.navigate('ForgotPassword')}
testID='login-view-forgot-password' testID='login-view-forgot-password'
>Forgot password >{I18n.t('Forgot_password')}
</Text> </Text>
</View> </View>

View File

@ -8,6 +8,7 @@ import { openMentionedMessages, closeMentionedMessages } from '../../actions/men
import styles from './styles'; import styles from './styles';
import Message from '../../containers/message'; import Message from '../../containers/message';
import RCActivityIndicator from '../../containers/ActivityIndicator'; import RCActivityIndicator from '../../containers/ActivityIndicator';
import I18n from '../../i18n';
@connect( @connect(
state => ({ state => ({
@ -74,7 +75,7 @@ export default class MentionedMessagesView extends LoggedView {
renderEmpty = () => ( renderEmpty = () => (
<View style={styles.listEmptyContainer} testID='mentioned-messages-view'> <View style={styles.listEmptyContainer} testID='mentioned-messages-view'>
<Text>No mentioned messages</Text> <Text>{I18n.t('No_mentioned_messages')}</Text>
</View> </View>
) )

View File

@ -11,6 +11,7 @@ import Button from '../containers/Button';
import TextInput from '../containers/TextInput'; import TextInput from '../containers/TextInput';
import Loading from '../containers/Loading'; import Loading from '../containers/Loading';
import LoggedView from './View'; import LoggedView from './View';
import I18n from '../i18n';
@connect(state => ({ @connect(state => ({
validInstance: !state.server.failure && !state.server.connecting, validInstance: !state.server.failure && !state.server.connecting,
@ -81,7 +82,7 @@ export default class NewServerView extends LoggedView {
if (this.props.validating) { if (this.props.validating) {
return ( return (
<Text style={[styles.validateText, styles.validatingText]}> <Text style={[styles.validateText, styles.validatingText]}>
Validating {this.state.text || 'open'} ... {I18n.t('Validating')} {this.state.text || 'open'} ...
</Text> </Text>
); );
} }
@ -89,13 +90,13 @@ export default class NewServerView extends LoggedView {
if (this.props.validInstance) { if (this.props.validInstance) {
return ( return (
<Text style={[styles.validateText, styles.validText]}> <Text style={[styles.validateText, styles.validText]}>
{this.state.url} is a valid Rocket.Chat instance {this.state.url} {I18n.t('is_a_valid_RocketChat_instance')}
</Text> </Text>
); );
} }
return ( return (
<Text style={[styles.validateText, styles.invalidText]}> <Text style={[styles.validateText, styles.invalidText]}>
{this.state.url} is not a valid Rocket.Chat instance {this.state.url} {I18n.t('is_not_a_valid_RocketChat_instance')}
</Text> </Text>
); );
} }
@ -109,11 +110,11 @@ export default class NewServerView extends LoggedView {
> >
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
<SafeAreaView testID='new-server-view'> <SafeAreaView testID='new-server-view'>
<Text style={[styles.loginText, styles.loginTitle]}>Sign in your server</Text> <Text style={[styles.loginText, styles.loginTitle]}>{I18n.t('Sign_in_your_server')}</Text>
<TextInput <TextInput
inputRef={e => this.input = e} inputRef={e => this.input = e}
containerStyle={{ marginBottom: 5 }} containerStyle={{ marginBottom: 5 }}
label='Your server' label={I18n.t('Your_server')}
placeholder={this.state.defaultServer} placeholder={this.state.defaultServer}
returnKeyType='done' returnKeyType='done'
onChangeText={this.onChangeText} onChangeText={this.onChangeText}
@ -123,7 +124,7 @@ export default class NewServerView extends LoggedView {
{this.renderValidation()} {this.renderValidation()}
<View style={[styles.alignItemsFlexStart, { marginTop: 20 }]}> <View style={[styles.alignItemsFlexStart, { marginTop: 20 }]}>
<Button <Button
title='Connect' title={I18n.t('Connect')}
type='primary' type='primary'
onPress={this.submit} onPress={this.submit}
disabled={!validInstance} disabled={!validInstance}

View File

@ -10,10 +10,11 @@ import styles from './styles';
import Message from '../../containers/message'; import Message from '../../containers/message';
import { togglePinRequest } from '../../actions/messages'; import { togglePinRequest } from '../../actions/messages';
import RCActivityIndicator from '../../containers/ActivityIndicator'; import RCActivityIndicator from '../../containers/ActivityIndicator';
import I18n from '../../i18n';
const PIN_INDEX = 0; const PIN_INDEX = 0;
const CANCEL_INDEX = 1; const CANCEL_INDEX = 1;
const options = ['Unpin', 'Cancel']; const options = [I18n.t('Unpin'), I18n.t('Cancel')];
@connect( @connect(
state => ({ state => ({
@ -98,7 +99,7 @@ export default class PinnedMessagesView extends LoggedView {
renderEmpty = () => ( renderEmpty = () => (
<View style={styles.listEmptyContainer} testID='pinned-messages-view'> <View style={styles.listEmptyContainer} testID='pinned-messages-view'>
<Text>No pinned messages</Text> <Text>{I18n.t('No_pinned_messages')}</Text>
</View> </View>
) )
@ -138,7 +139,7 @@ export default class PinnedMessagesView extends LoggedView {
<ActionSheet <ActionSheet
key='pinned-messages-view-action-sheet' key='pinned-messages-view-action-sheet'
ref={o => this.actionSheet = o} ref={o => this.actionSheet = o}
title='Actions' title={I18n.t('Actions')}
options={options} options={options}
cancelButtonIndex={CANCEL_INDEX} cancelButtonIndex={CANCEL_INDEX}
onPress={this.handleActionPress} onPress={this.handleActionPress}

View File

@ -3,15 +3,11 @@ import PropTypes from 'prop-types';
import { WebView } from 'react-native'; import { WebView } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
class PrivacyPolicyView extends React.Component { class PrivacyPolicyView extends React.PureComponent {
static propTypes = { static propTypes = {
privacyPolicy: PropTypes.string privacyPolicy: PropTypes.string
} }
static navigationOptions = () => ({
title: 'Terms of service'
});
render() { render() {
return ( return (
<WebView source={{ html: this.props.privacyPolicy }} /> <WebView source={{ html: this.props.privacyPolicy }} />

View File

@ -13,6 +13,7 @@ import { showToast } from '../utils/info';
import CloseModalButton from '../containers/CloseModalButton'; import CloseModalButton from '../containers/CloseModalButton';
import scrollPersistTaps from '../utils/scrollPersistTaps'; import scrollPersistTaps from '../utils/scrollPersistTaps';
import LoggedView from './View'; import LoggedView from './View';
import I18n from '../i18n';
@connect(state => ({ @connect(state => ({
server: state.server.server, server: state.server.server,
@ -65,7 +66,7 @@ export default class RegisterView extends LoggedView {
name, email, password, code name, email, password, code
} = this.state; } = this.state;
if (!this.valid()) { if (!this.valid()) {
showToast('Some field is invalid or empty'); showToast(I18n.t('Some_field_is_invalid_or_empty'));
return; return;
} }
@ -78,7 +79,7 @@ export default class RegisterView extends LoggedView {
usernameSubmit = () => { usernameSubmit = () => {
const { username } = this.state; const { username } = this.state;
if (!username) { if (!username) {
showToast('Username is empty'); showToast(I18n.t('Username_is_empty'));
return; return;
} }
@ -102,8 +103,8 @@ export default class RegisterView extends LoggedView {
<View> <View>
<TextInput <TextInput
inputRef={(e) => { this.name = e; }} inputRef={(e) => { this.name = e; }}
label={this.props.Accounts_NamePlaceholder || 'Name'} label={this.props.Accounts_NamePlaceholder || I18n.t('Name')}
placeholder={this.props.Accounts_NamePlaceholder || 'Name'} placeholder={this.props.Accounts_NamePlaceholder || I18n.t('Name')}
returnKeyType='next' returnKeyType='next'
iconLeft='account' iconLeft='account'
onChangeText={name => this.setState({ name })} onChangeText={name => this.setState({ name })}
@ -112,8 +113,8 @@ export default class RegisterView extends LoggedView {
/> />
<TextInput <TextInput
inputRef={(e) => { this.email = e; }} inputRef={(e) => { this.email = e; }}
label={this.props.Accounts_EmailOrUsernamePlaceholder || 'Email'} label={this.props.Accounts_EmailOrUsernamePlaceholder || I18n.t('Email')}
placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || 'Email'} placeholder={this.props.Accounts_EmailOrUsernamePlaceholder || I18n.t('Email')}
returnKeyType='next' returnKeyType='next'
keyboardType='email-address' keyboardType='email-address'
iconLeft='email' iconLeft='email'
@ -124,8 +125,8 @@ export default class RegisterView extends LoggedView {
/> />
<TextInput <TextInput
inputRef={(e) => { this.password = e; }} inputRef={(e) => { this.password = e; }}
label={this.props.Accounts_PasswordPlaceholder || 'Password'} label={this.props.Accounts_PasswordPlaceholder || I18n.t('Password')}
placeholder={this.props.Accounts_PasswordPlaceholder || 'Password'} placeholder={this.props.Accounts_PasswordPlaceholder || I18n.t('Password')}
returnKeyType='next' returnKeyType='next'
iconLeft='key-variant' iconLeft='key-variant'
secureTextEntry secureTextEntry
@ -140,8 +141,8 @@ export default class RegisterView extends LoggedView {
this.state.confirmPassword && this.state.confirmPassword &&
this.state.confirmPassword !== this.state.password ? { borderColor: 'red' } : {} this.state.confirmPassword !== this.state.password ? { borderColor: 'red' } : {}
} }
label={this.props.Accounts_RepeatPasswordPlaceholder || 'Repeat Password'} label={this.props.Accounts_RepeatPasswordPlaceholder || I18n.t('Repeat_Password')}
placeholder={this.props.Accounts_RepeatPasswordPlaceholder || 'Repeat Password'} placeholder={this.props.Accounts_RepeatPasswordPlaceholder || I18n.t('Repeat_Password')}
returnKeyType='done' returnKeyType='done'
iconLeft='key-variant' iconLeft='key-variant'
secureTextEntry secureTextEntry
@ -152,13 +153,13 @@ export default class RegisterView extends LoggedView {
<View style={styles.alignItemsFlexStart}> <View style={styles.alignItemsFlexStart}>
<Text style={styles.loginTermsText}> <Text style={styles.loginTermsText}>
By proceeding you are agreeing to our {I18n.t('By_proceeding_you_are_agreeing')}
<Text style={styles.link} onPress={this.termsService}> Terms of Service </Text> <Text style={styles.link} onPress={this.termsService}>{I18n.t('Terms_of_Service')}</Text>
and {I18n.t('and')}
<Text style={styles.link} onPress={this.privacyPolicy}> Privacy Policy</Text> <Text style={styles.link} onPress={this.privacyPolicy}>{I18n.t('Privacy_Policy')}</Text>
</Text> </Text>
<Button <Button
title='Register' title={I18n.t('Register')}
type='primary' type='primary'
onPress={this.submit} onPress={this.submit}
testID='register-view-submit' testID='register-view-submit'
@ -176,8 +177,8 @@ export default class RegisterView extends LoggedView {
<View> <View>
<TextInput <TextInput
inputRef={(e) => { this.username = e; }} inputRef={(e) => { this.username = e; }}
label={this.props.Accounts_UsernamePlaceholder || 'Username'} label={this.props.Accounts_UsernamePlaceholder || I18n.t('Username')}
placeholder={this.props.Accounts_UsernamePlaceholder || 'Username'} placeholder={this.props.Accounts_UsernamePlaceholder || I18n.t('Username')}
returnKeyType='done' returnKeyType='done'
iconLeft='at' iconLeft='at'
onChangeText={username => this.setState({ username })} onChangeText={username => this.setState({ username })}
@ -187,7 +188,7 @@ export default class RegisterView extends LoggedView {
<View style={styles.alignItemsFlexStart}> <View style={styles.alignItemsFlexStart}>
<Button <Button
title='Register' title={I18n.t('Register')}
type='primary' type='primary'
onPress={this.usernameSubmit} onPress={this.usernameSubmit}
testID='register-view-submit-username' testID='register-view-submit-username'
@ -203,7 +204,7 @@ export default class RegisterView extends LoggedView {
<ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}> <ScrollView {...scrollPersistTaps} contentContainerStyle={styles.containerScrollView}>
<SafeAreaView testID='register-view'> <SafeAreaView testID='register-view'>
<CloseModalButton navigation={this.props.navigation} /> <CloseModalButton navigation={this.props.navigation} />
<Text style={[styles.loginText, styles.loginTitle]}>Sign Up</Text> <Text style={[styles.loginText, styles.loginTitle]}>{I18n.t('Sign_Up')}</Text>
{this._renderRegister()} {this._renderRegister()}
{this._renderUsername()} {this._renderUsername()}
{this.props.login.failure && {this.props.login.failure &&

View File

@ -17,6 +17,7 @@ import { leaveRoom } from '../../actions/room';
import { setLoading } from '../../actions/selectedUsers'; import { setLoading } from '../../actions/selectedUsers';
import log from '../../utils/log'; import log from '../../utils/log';
import RoomTypeIcon from '../../containers/RoomTypeIcon'; import RoomTypeIcon from '../../containers/RoomTypeIcon';
import I18n from '../../i18n';
const renderSeparator = () => <View style={styles.separator} />; const renderSeparator = () => <View style={styles.separator} />;
const getRoomTitle = room => (room.t === 'd' ? <Text>{room.fname}</Text> : <Text><RoomTypeIcon type={room.t} />&nbsp;{room.name}</Text>); const getRoomTitle = room => (room.t === 'd' ? <Text>{room.fname}</Text> : <Text><RoomTypeIcon type={room.t} />&nbsp;{room.name}</Text>);
@ -158,13 +159,13 @@ export default class RoomActionsView extends LoggedView {
data: [ data: [
{ {
icon: 'ios-call-outline', icon: 'ios-call-outline',
name: 'Voice call', name: I18n.t('Voice_call'),
disabled: true, disabled: true,
testID: 'room-actions-voice' testID: 'room-actions-voice'
}, },
{ {
icon: 'ios-videocam-outline', icon: 'ios-videocam-outline',
name: 'Video call', name: I18n.t('Video_call'),
disabled: true, disabled: true,
testID: 'room-actions-video' testID: 'room-actions-video'
} }
@ -174,55 +175,55 @@ export default class RoomActionsView extends LoggedView {
data: [ data: [
{ {
icon: 'ios-attach', icon: 'ios-attach',
name: 'Files', name: I18n.t('Files'),
route: 'RoomFiles', route: 'RoomFiles',
params: { rid }, params: { rid },
testID: 'room-actions-files' testID: 'room-actions-files'
}, },
{ {
icon: 'ios-at-outline', icon: 'ios-at-outline',
name: 'Mentions', name: I18n.t('Mentions'),
route: 'MentionedMessages', route: 'MentionedMessages',
params: { rid }, params: { rid },
testID: 'room-actions-mentioned' testID: 'room-actions-mentioned'
}, },
{ {
icon: 'ios-star-outline', icon: 'ios-star-outline',
name: 'Starred', name: I18n.t('Starred'),
route: 'StarredMessages', route: 'StarredMessages',
params: { rid }, params: { rid },
testID: 'room-actions-starred' testID: 'room-actions-starred'
}, },
{ {
icon: 'ios-search', icon: 'ios-search',
name: 'Search', name: I18n.t('Search'),
route: 'SearchMessages', route: 'SearchMessages',
params: { rid }, params: { rid },
testID: 'room-actions-search' testID: 'room-actions-search'
}, },
{ {
icon: 'ios-share-outline', icon: 'ios-share-outline',
name: 'Share', name: I18n.t('Share'),
disabled: true, disabled: true,
testID: 'room-actions-share' testID: 'room-actions-share'
}, },
{ {
icon: 'ios-pin', icon: 'ios-pin',
name: 'Pinned', name: I18n.t('Pinned'),
route: 'PinnedMessages', route: 'PinnedMessages',
params: { rid }, params: { rid },
testID: 'room-actions-pinned' testID: 'room-actions-pinned'
}, },
{ {
icon: 'ios-code', icon: 'ios-code',
name: 'Snippets', name: I18n.t('Snippets'),
route: 'SnippetedMessages', route: 'SnippetedMessages',
params: { rid }, params: { rid },
testID: 'room-actions-snippeted' testID: 'room-actions-snippeted'
}, },
{ {
icon: `ios-notifications${ notifications ? '' : '-off' }-outline`, icon: `ios-notifications${ notifications ? '' : '-off' }-outline`,
name: `${ notifications ? 'Enable' : 'Disable' } notifications`, name: I18n.t(`${ notifications ? 'Enable' : 'Disable' }_notifications`),
event: () => this.toggleNotifications(), event: () => this.toggleNotifications(),
testID: 'room-actions-notifications' testID: 'room-actions-notifications'
} }
@ -235,7 +236,7 @@ export default class RoomActionsView extends LoggedView {
data: [ data: [
{ {
icon: 'block', icon: 'block',
name: `${ blocker ? 'Unblock' : 'Block' } user`, name: I18n.t(`${ blocker ? 'Unblock' : 'Block' }_user`),
type: 'danger', type: 'danger',
event: () => this.toggleBlockUser(), event: () => this.toggleBlockUser(),
testID: 'room-actions-block-user' testID: 'room-actions-block-user'
@ -249,8 +250,10 @@ export default class RoomActionsView extends LoggedView {
if (this.canViewMembers) { if (this.canViewMembers) {
actions.push({ actions.push({
icon: 'ios-people', icon: 'ios-people',
name: 'Members', name: I18n.t('Members'),
description: (onlineMembers.length === 1 ? `${ onlineMembers.length } member` : `${ onlineMembers.length } members`), description: (onlineMembers.length === 1 ?
I18n.t('1_online_member') :
I18n.t('N_online_members', { n: onlineMembers.length })),
route: 'RoomMembers', route: 'RoomMembers',
params: { rid, members: onlineMembers }, params: { rid, members: onlineMembers },
testID: 'room-actions-members' testID: 'room-actions-members'
@ -260,7 +263,7 @@ export default class RoomActionsView extends LoggedView {
if (this.canAddUser) { if (this.canAddUser) {
actions.push({ actions.push({
icon: 'ios-person-add', icon: 'ios-person-add',
name: 'Add user', name: I18n.t('Add_user'),
route: 'SelectedUsers', route: 'SelectedUsers',
params: { params: {
nextAction: async() => { nextAction: async() => {
@ -283,7 +286,7 @@ export default class RoomActionsView extends LoggedView {
data: [ data: [
{ {
icon: 'block', icon: 'block',
name: 'Leave channel', name: I18n.t('Leave_channel'),
type: 'danger', type: 'danger',
event: () => this.leaveChannel(), event: () => this.leaveChannel(),
testID: 'room-actions-leave-channel' testID: 'room-actions-leave-channel'
@ -308,15 +311,15 @@ export default class RoomActionsView extends LoggedView {
leaveChannel = () => { leaveChannel = () => {
const { room } = this.state; const { room } = this.state;
Alert.alert( Alert.alert(
'Are you sure?', I18n.t('Are_you_sure_question_mark'),
`Are you sure you want to leave the room ${ getRoomTitle(room) }?`, I18n.t('Are_you_sure_you_want_to_leave_the_room', { room: room.t === 'd' ? room.fname : room.name }),
[ [
{ {
text: 'Cancel', text: I18n.t('Cancel'),
style: 'cancel' style: 'cancel'
}, },
{ {
text: 'Yes, leave it!', text: I18n.t('Yes_action_it', { action: I18n.t('leave') }),
style: 'destructive', style: 'destructive',
onPress: () => this.props.leaveRoom(room.rid) onPress: () => this.props.leaveRoom(room.rid)
} }

View File

@ -8,6 +8,7 @@ import { openRoomFiles, closeRoomFiles } from '../../actions/roomFiles';
import styles from './styles'; import styles from './styles';
import Message from '../../containers/message'; import Message from '../../containers/message';
import RCActivityIndicator from '../../containers/ActivityIndicator'; import RCActivityIndicator from '../../containers/ActivityIndicator';
import I18n from '../../i18n';
@connect( @connect(
state => ({ state => ({
@ -74,7 +75,7 @@ export default class RoomFilesView extends LoggedView {
renderEmpty = () => ( renderEmpty = () => (
<View style={styles.listEmptyContainer} testID='room-files-view'> <View style={styles.listEmptyContainer} testID='room-files-view'>
<Text>No files</Text> <Text>{I18n.t('No_files')}</Text>
</View> </View>
) )

View File

@ -17,6 +17,7 @@ import Loading from '../../containers/Loading';
import SwitchContainer from './SwitchContainer'; import SwitchContainer from './SwitchContainer';
import random from '../../utils/random'; import random from '../../utils/random';
import log from '../../utils/log'; import log from '../../utils/log';
import I18n from '../../i18n';
const PERMISSION_SET_READONLY = 'set-readonly'; const PERMISSION_SET_READONLY = 'set-readonly';
const PERMISSION_SET_REACT_WHEN_READONLY = 'set-react-when-readonly'; const PERMISSION_SET_REACT_WHEN_READONLY = 'set-react-when-readonly';
@ -133,7 +134,7 @@ export default class RoomInfoEditView extends LoggedView {
let error = false; let error = false;
if (!this.formIsChanged()) { if (!this.formIsChanged()) {
showErrorAlert('Nothing to save!'); showErrorAlert(I18n.t('Nothing_to_save'));
return; return;
} }
@ -189,24 +190,24 @@ export default class RoomInfoEditView extends LoggedView {
await this.setState({ saving: false }); await this.setState({ saving: false });
setTimeout(() => { setTimeout(() => {
if (error) { if (error) {
showErrorAlert('There was an error while saving settings!'); showErrorAlert(I18n.t('There_was_an_error_while_saving_settings'));
} else { } else {
showToast('Settings succesfully changed!'); showToast(I18n.t('Settings_succesfully_changed'));
} }
}, 100); }, 100);
} }
delete = () => { delete = () => {
Alert.alert( Alert.alert(
'Are you sure?', I18n.t('Are_you_sure_question_mark'),
'Deleting a room will delete all messages posted within the room. This cannot be undone.', I18n.t('Delete_Room_Warning'),
[ [
{ {
text: 'Cancel', text: I18n.t('Cancel'),
style: 'cancel' style: 'cancel'
}, },
{ {
text: 'Yes, delete it!', text: I18n.t('Yes_action_it', { action: I18n.t('delete') }),
style: 'destructive', style: 'destructive',
onPress: () => this.props.eraseRoom(this.state.room.rid) onPress: () => this.props.eraseRoom(this.state.room.rid)
} }
@ -217,17 +218,17 @@ export default class RoomInfoEditView extends LoggedView {
toggleArchive = () => { toggleArchive = () => {
const { archived } = this.state.room; const { archived } = this.state.room;
const action = `${ archived ? 'un' : '' }archive`; const action = I18n.t(`${ archived ? 'un' : '' }archive`);
Alert.alert( Alert.alert(
'Are you sure?', I18n.t('Are_you_sure_question_mark'),
`Do you really want to ${ action } this room?`, I18n.t('Do_you_really_want_to_key_this_room_question_mark', { key: action }),
[ [
{ {
text: 'Cancel', text: I18n.t('Cancel'),
style: 'cancel' style: 'cancel'
}, },
{ {
text: `Yes, ${ action } it!`, text: I18n.t('Yes_action_it', { action }),
style: 'destructive', style: 'destructive',
onPress: () => { onPress: () => {
try { try {
@ -268,7 +269,7 @@ export default class RoomInfoEditView extends LoggedView {
<View style={sharedStyles.formContainer}> <View style={sharedStyles.formContainer}>
<RCTextInput <RCTextInput
inputRef={(e) => { this.name = e; }} inputRef={(e) => { this.name = e; }}
label='Name' label={I18n.t('Name')}
value={name} value={name}
onChangeText={value => this.setState({ name: value })} onChangeText={value => this.setState({ name: value })}
onSubmitEditing={() => { this.description.focus(); }} onSubmitEditing={() => { this.description.focus(); }}
@ -277,7 +278,7 @@ export default class RoomInfoEditView extends LoggedView {
/> />
<RCTextInput <RCTextInput
inputRef={(e) => { this.description = e; }} inputRef={(e) => { this.description = e; }}
label='Description' label={I18n.t('Description')}
value={description} value={description}
onChangeText={value => this.setState({ description: value })} onChangeText={value => this.setState({ description: value })}
onSubmitEditing={() => { this.topic.focus(); }} onSubmitEditing={() => { this.topic.focus(); }}
@ -285,7 +286,7 @@ export default class RoomInfoEditView extends LoggedView {
/> />
<RCTextInput <RCTextInput
inputRef={(e) => { this.topic = e; }} inputRef={(e) => { this.topic = e; }}
label='Topic' label={I18n.t('Topic')}
value={topic} value={topic}
onChangeText={value => this.setState({ topic: value })} onChangeText={value => this.setState({ topic: value })}
onSubmitEditing={() => { this.announcement.focus(); }} onSubmitEditing={() => { this.announcement.focus(); }}
@ -293,7 +294,7 @@ export default class RoomInfoEditView extends LoggedView {
/> />
<RCTextInput <RCTextInput
inputRef={(e) => { this.announcement = e; }} inputRef={(e) => { this.announcement = e; }}
label='Announcement' label={I18n.t('Announcement')}
value={announcement} value={announcement}
onChangeText={value => this.setState({ announcement: value })} onChangeText={value => this.setState({ announcement: value })}
onSubmitEditing={() => { this.joinCode.focus(); }} onSubmitEditing={() => { this.joinCode.focus(); }}
@ -301,7 +302,7 @@ export default class RoomInfoEditView extends LoggedView {
/> />
<RCTextInput <RCTextInput
inputRef={(e) => { this.joinCode = e; }} inputRef={(e) => { this.joinCode = e; }}
label='Password' label={I18n.t('Password')}
value={joinCode} value={joinCode}
onChangeText={value => this.setState({ joinCode: value })} onChangeText={value => this.setState({ joinCode: value })}
onSubmitEditing={this.submit} onSubmitEditing={this.submit}
@ -310,19 +311,19 @@ export default class RoomInfoEditView extends LoggedView {
/> />
<SwitchContainer <SwitchContainer
value={t} value={t}
leftLabelPrimary='Public' leftLabelPrimary={I18n.t('Public')}
leftLabelSecondary='Everyone can access this channel' leftLabelSecondary={I18n.t('Everyone_can_access_this_channel')}
rightLabelPrimary='Private' rightLabelPrimary={I18n.t('Private')}
rightLabelSecondary='Just invited people can access this channel' rightLabelSecondary={I18n.t('Just_invited_people_can_access_this_channel')}
onValueChange={value => this.setState({ t: value })} onValueChange={value => this.setState({ t: value })}
testID='room-info-edit-view-t' testID='room-info-edit-view-t'
/> />
<SwitchContainer <SwitchContainer
value={ro} value={ro}
leftLabelPrimary='Colaborative' leftLabelPrimary={I18n.t('Colaborative')}
leftLabelSecondary='All users in the channel can write new messages' leftLabelSecondary={I18n.t('All_users_in_the_channel_can_write_new_messages')}
rightLabelPrimary='Read Only' rightLabelPrimary={I18n.t('Read_Only')}
rightLabelSecondary='Only authorized users can write new messages' rightLabelSecondary={I18n.t('Only_authorized_users_can_write_new_messages')}
onValueChange={value => this.setState({ ro: value })} onValueChange={value => this.setState({ ro: value })}
disabled={!this.permissions[PERMISSION_SET_READONLY] || room.broadcast} disabled={!this.permissions[PERMISSION_SET_READONLY] || room.broadcast}
testID='room-info-edit-view-ro' testID='room-info-edit-view-ro'
@ -330,10 +331,10 @@ export default class RoomInfoEditView extends LoggedView {
{ro && !room.broadcast && {ro && !room.broadcast &&
<SwitchContainer <SwitchContainer
value={reactWhenReadOnly} value={reactWhenReadOnly}
leftLabelPrimary='No Reactions' leftLabelPrimary={I18n.t('No_Reactions')}
leftLabelSecondary='Reactions are disabled' leftLabelSecondary={I18n.t('Reactions_are_disabled')}
rightLabelPrimary='Allow Reactions' rightLabelPrimary={I18n.t('Allow_Reactions')}
rightLabelSecondary='Reactions are enabled' rightLabelSecondary={I18n.t('Reactions_are_enabled')}
onValueChange={value => this.setState({ reactWhenReadOnly: value })} onValueChange={value => this.setState({ reactWhenReadOnly: value })}
disabled={!this.permissions[PERMISSION_SET_REACT_WHEN_READONLY]} disabled={!this.permissions[PERMISSION_SET_REACT_WHEN_READONLY]}
testID='room-info-edit-view-react-when-ro' testID='room-info-edit-view-react-when-ro'
@ -341,7 +342,7 @@ export default class RoomInfoEditView extends LoggedView {
} }
{room.broadcast && {room.broadcast &&
[ [
<Text style={styles.broadcast}>Broadcast channel</Text>, <Text style={styles.broadcast}>{I18n.t('Broadcast_Channel')}</Text>,
<View style={styles.divider} /> <View style={styles.divider} />
] ]
} }
@ -351,7 +352,7 @@ export default class RoomInfoEditView extends LoggedView {
disabled={!this.formIsChanged()} disabled={!this.formIsChanged()}
testID='room-info-edit-view-submit' testID='room-info-edit-view-submit'
> >
<Text style={sharedStyles.button} accessibilityTraits='button'>SAVE</Text> <Text style={sharedStyles.button} accessibilityTraits='button'>{I18n.t('SAVE')}</Text>
</TouchableOpacity> </TouchableOpacity>
<View style={{ flexDirection: 'row' }}> <View style={{ flexDirection: 'row' }}>
<TouchableOpacity <TouchableOpacity
@ -359,7 +360,7 @@ export default class RoomInfoEditView extends LoggedView {
onPress={this.reset} onPress={this.reset}
testID='room-info-edit-view-reset' testID='room-info-edit-view-reset'
> >
<Text style={sharedStyles.button_inverted} accessibilityTraits='button'>RESET</Text> <Text style={sharedStyles.button_inverted} accessibilityTraits='button'>{I18n.t('RESET')}</Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity <TouchableOpacity
style={[ style={[
@ -373,7 +374,7 @@ export default class RoomInfoEditView extends LoggedView {
testID='room-info-edit-view-archive' testID='room-info-edit-view-archive'
> >
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'> <Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>
{ room.archived ? 'UNARCHIVE' : 'ARCHIVE' } { room.archived ? I18n.t('UNARCHIVE') : I18n.t('ARCHIVE') }
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
@ -389,7 +390,7 @@ export default class RoomInfoEditView extends LoggedView {
disabled={!this.hasDeletePermission()} disabled={!this.hasDeletePermission()}
testID='room-info-edit-view-delete' testID='room-info-edit-view-delete'
> >
<Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>DELETE</Text> <Text style={[sharedStyles.button_inverted, styles.colorDanger]} accessibilityTraits='button'>{I18n.t('DELETE')}</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
<Loading visible={this.state.saving} /> <Loading visible={this.state.saving} />

View File

@ -16,6 +16,7 @@ import Touch from '../../utils/touch';
import log from '../../utils/log'; import log from '../../utils/log';
import RoomTypeIcon from '../../containers/RoomTypeIcon'; import RoomTypeIcon from '../../containers/RoomTypeIcon';
import I18n from '../../i18n';
const PERMISSION_EDIT_ROOM = 'edit-room'; const PERMISSION_EDIT_ROOM = 'edit-room';
@ -56,7 +57,7 @@ export default class RoomInfoView extends LoggedView {
onPress={() => navigation.navigate({ key: 'RoomInfoEdit', routeName: 'RoomInfoEdit', params: { rid: navigation.state.params.rid } })} onPress={() => navigation.navigate({ key: 'RoomInfoEdit', routeName: 'RoomInfoEdit', params: { rid: navigation.state.params.rid } })}
underlayColor='#ffffff' underlayColor='#ffffff'
activeOpacity={0.5} activeOpacity={0.5}
accessibilityLabel='edit' accessibilityLabel={I18n.t('edit')}
accessibilityTraits='button' accessibilityTraits='button'
testID='room-info-view-edit-button' testID='room-info-view-edit-button'
> >
@ -132,14 +133,14 @@ export default class RoomInfoView extends LoggedView {
const [room] = this.rooms; const [room] = this.rooms;
this.setState({ room }); this.setState({ room });
} }
// TODO: translate
renderItem = (key, room) => ( renderItem = (key, room) => (
<View style={styles.item}> <View style={styles.item}>
<Text style={styles.itemLabel}>{camelize(key)}</Text> <Text style={styles.itemLabel}>{I18n.t(camelize(key))}</Text>
<Text <Text
style={[styles.itemContent, !room[key] && styles.itemContent__empty]} style={[styles.itemContent, !room[key] && styles.itemContent__empty]}
testID={`room-info-view-${ key }`} testID={`room-info-view-${ key }`}
>{ room[key] ? room[key] : `No ${ key } provided.` } >{ room[key] ? room[key] : I18n.t(`No_${ key }_provided`) }
</Text> </Text>
</View> </View>
); );
@ -147,7 +148,7 @@ export default class RoomInfoView extends LoggedView {
renderRoles = () => ( renderRoles = () => (
this.state.roles.length > 0 && this.state.roles.length > 0 &&
<View style={styles.item}> <View style={styles.item}>
<Text style={styles.itemLabel}>Roles</Text> <Text style={styles.itemLabel}>{I18n.t('Roles')}</Text>
<View style={styles.rolesContainer}> <View style={styles.rolesContainer}>
{this.state.roles.map(role => ( {this.state.roles.map(role => (
<View style={styles.roleBadge} key={role}> <View style={styles.roleBadge} key={role}>
@ -168,7 +169,7 @@ export default class RoomInfoView extends LoggedView {
// TODO: translate // TODO: translate
return ( return (
<View style={styles.item}> <View style={styles.item}>
<Text style={styles.itemLabel}>Timezone</Text> <Text style={styles.itemLabel}>{I18n.t('Timezone')}</Text>
<Text style={styles.itemContent}>{moment().utcOffset(utcOffset).format(this.props.Message_TimeFormat)} (UTC { utcOffset })</Text> <Text style={styles.itemContent}>{moment().utcOffset(utcOffset).format(this.props.Message_TimeFormat)} (UTC { utcOffset })</Text>
</View> </View>
); );
@ -189,11 +190,11 @@ export default class RoomInfoView extends LoggedView {
renderBroadcast = () => ( renderBroadcast = () => (
<View style={styles.item}> <View style={styles.item}>
<Text style={styles.itemLabel}>Broadcast Channel</Text> <Text style={styles.itemLabel}>{I18n.t('Broadcast_Channel')}</Text>
<Text <Text
style={styles.itemContent} style={styles.itemContent}
testID='room-info-view-broadcast' testID='room-info-view-broadcast'
>Only authorized users can write new messages, but the other users will be able to reply >{I18n.t('Broadcast_channel_Description')}
</Text> </Text>
</View> </View>
) )

View File

@ -14,6 +14,7 @@ import { goRoom } from '../../containers/routes/NavigationService';
import database from '../../lib/realm'; import database from '../../lib/realm';
import { showToast } from '../../utils/info'; import { showToast } from '../../utils/info';
import log from '../../utils/log'; import log from '../../utils/log';
import I18n from '../../i18n';
@connect(state => ({ @connect(state => ({
user: state.login.user, user: state.login.user,
@ -26,7 +27,7 @@ export default class MentionedMessagesView extends LoggedView {
static navigationOptions = ({ navigation }) => { static navigationOptions = ({ navigation }) => {
const params = navigation.state.params || {}; const params = navigation.state.params || {};
const label = params.allUsers ? 'All' : 'Online'; const label = params.allUsers ? I18n.t('All') : I18n.t('Online');
if (params.allUsers === undefined) { if (params.allUsers === undefined) {
return; return;
} }
@ -123,14 +124,14 @@ export default class MentionedMessagesView extends LoggedView {
if (!this.permissions['mute-user']) { if (!this.permissions['mute-user']) {
return; return;
} }
this.actionSheetOptions = ['Cancel']; this.actionSheetOptions = [I18n.t('Cancel')];
const { muted } = this.state.room; const { muted } = this.state.room;
const userIsMuted = !!muted.find(m => m.value === user.username); const userIsMuted = !!muted.find(m => m.value === user.username);
user.muted = userIsMuted; user.muted = userIsMuted;
if (userIsMuted) { if (userIsMuted) {
this.actionSheetOptions.push('Unmute'); this.actionSheetOptions.push(I18n.t('Unmute'));
} else { } else {
this.actionSheetOptions.push('Mute'); this.actionSheetOptions.push(I18n.t('Mute'));
} }
this.setState({ userLongPressed: user }); this.setState({ userLongPressed: user });
Vibration.vibrate(50); Vibration.vibrate(50);
@ -141,7 +142,7 @@ export default class MentionedMessagesView extends LoggedView {
const { rid, userLongPressed } = this.state; const { rid, userLongPressed } = this.state;
try { try {
await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted); await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted);
showToast(`User has been ${ userLongPressed.muted ? 'unmuted' : 'muted' }!`); showToast(I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') }));
} catch (e) { } catch (e) {
log('handleMute', e); log('handleMute', e);
} }
@ -164,7 +165,7 @@ export default class MentionedMessagesView extends LoggedView {
style={styles.searchBox} style={styles.searchBox}
onChangeText={text => this.onSearchChangeText(text)} onChangeText={text => this.onSearchChangeText(text)}
returnKeyType='search' returnKeyType='search'
placeholder='Search' placeholder={I18n.t('Search')}
clearButtonMode='while-editing' clearButtonMode='while-editing'
blurOnSubmit blurOnSubmit
autoCorrect={false} autoCorrect={false}
@ -209,7 +210,7 @@ export default class MentionedMessagesView extends LoggedView {
<ActionSheet <ActionSheet
key='room-members-actionsheet' key='room-members-actionsheet'
ref={o => this.ActionSheet = o} ref={o => this.ActionSheet = o}
title='Actions' title={I18n.t('Actions')}
options={this.actionSheetOptions} options={this.actionSheetOptions}
cancelButtonIndex={this.CANCEL_INDEX} cancelButtonIndex={this.CANCEL_INDEX}
onPress={this.handleActionPress} onPress={this.handleActionPress}

View File

@ -11,28 +11,28 @@ import Avatar from '../../../containers/Avatar';
import { STATUS_COLORS } from '../../../constants/colors'; import { STATUS_COLORS } from '../../../constants/colors';
import styles from './styles'; import styles from './styles';
import { closeRoom } from '../../../actions/room'; import { closeRoom } from '../../../actions/room';
import log from '../../../utils/log'; import log from '../../../utils/log';
import RoomTypeIcon from '../../../containers/RoomTypeIcon'; import RoomTypeIcon from '../../../containers/RoomTypeIcon';
import I18n from '../../../i18n';
const title = (offline, connecting, authenticating, logged) => { const title = (offline, connecting, authenticating, logged) => {
if (offline) { if (offline) {
return 'You are offline...'; return `${ I18n.t('You_are_offline') }...`;
} }
if (connecting) { if (connecting) {
return 'Connecting...'; return `${ I18n.t('Connecting') }...`;
} }
if (authenticating) { if (authenticating) {
return 'Authenticating...'; return `${ I18n.t('Authenticating') }...`;
} }
if (logged) { if (logged) {
return null; return null;
} }
return 'Not logged...'; return `${ I18n.t('Not_logged') }...`;
}; };
@connect(state => ({ @connect(state => ({
@ -87,7 +87,7 @@ export default class RoomHeaderView extends React.PureComponent {
getUserStatusLabel() { getUserStatusLabel() {
const status = this.getUserStatus(); const status = this.getUserStatus();
return status.charAt(0).toUpperCase() + status.slice(1); return I18n.t(status.charAt(0).toUpperCase() + status.slice(1));
} }
updateState = () => { updateState = () => {
@ -104,7 +104,7 @@ export default class RoomHeaderView extends React.PureComponent {
requestAnimationFrame(() => this.props.close()); requestAnimationFrame(() => this.props.close());
}} }}
tintColor='#292E35' tintColor='#292E35'
title='Back' title={I18n.t('Back')}
titleStyle={{ display: 'none' }} titleStyle={{ display: 'none' }}
/>); />);
@ -124,7 +124,7 @@ export default class RoomHeaderView extends React.PureComponent {
let t = ''; let t = '';
if (!title(offline, connecting, authenticating, logged) && loading) { if (!title(offline, connecting, authenticating, logged) && loading) {
t = 'Loading messages...'; t = I18n.t('Loading_messages_ellipsis');
} else if (this.isDirect()) { } else if (this.isDirect()) {
t = this.getUserStatusLabel(); t = this.getUserStatusLabel();
} else { } else {
@ -177,7 +177,7 @@ export default class RoomHeaderView extends React.PureComponent {
log('toggleFavorite', e); log('toggleFavorite', e);
} }
}} }}
accessibilityLabel='Star room' accessibilityLabel={I18n.t('Star_room')}
accessibilityTraits='button' accessibilityTraits='button'
testID='room-view-header-star' testID='room-view-header-star'
> >
@ -191,7 +191,7 @@ export default class RoomHeaderView extends React.PureComponent {
<TouchableOpacity <TouchableOpacity
style={styles.headerButton} style={styles.headerButton}
onPress={() => this.props.navigation.navigate({ key: 'RoomActions', routeName: 'RoomActions', params: { rid: this.state.room.rid } })} onPress={() => this.props.navigation.navigate({ key: 'RoomActions', routeName: 'RoomActions', params: { rid: this.state.room.rid } })}
accessibilityLabel='Room actions' accessibilityLabel={I18n.t('Room_actions')}
accessibilityTraits='button' accessibilityTraits='button'
testID='room-view-header-actions' testID='room-view-header-actions'
> >

View File

@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { View, StyleSheet, Text, LayoutAnimation } from 'react-native'; import { View, StyleSheet, Text, LayoutAnimation } from 'react-native';
import I18n from '../../i18n';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
firstUnread: { firstUnread: {
@ -30,7 +31,7 @@ export default class UnreadSeparator extends React.PureComponent {
return ( return (
<View style={styles.firstUnread}> <View style={styles.firstUnread}>
<View style={styles.firstUnreadLine} /> <View style={styles.firstUnreadLine} />
<Text style={styles.firstUnreadBadge}>unread messages</Text> <Text style={styles.firstUnreadBadge}>{I18n.t('unread_messages')}</Text>
</View> </View>
); );
} }

View File

@ -1,22 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Text, View } from 'react-native';
import { connect } from 'react-redux';
import styles from './styles';
@connect(state => ({
loading: state.messages.isFetching
}), null)
export default class Banner extends React.PureComponent {
static propTypes = {
loading: PropTypes.bool
};
render() {
return (this.props.loading ? (
<View style={styles.bannerContainer}>
<Text style={styles.bannerText}>Loading new messages...</Text>
</View>
) : null);
}
}

View File

@ -2,12 +2,12 @@ import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { Text, View, Button } from 'react-native'; import { Text, View, Button } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'; // import { bindActionCreators } from 'redux';
import equal from 'deep-equal'; import equal from 'deep-equal';
import LoggedView from '../View'; import LoggedView from '../View';
import { List } from './ListView'; import { List } from './ListView';
import * as actions from '../../actions'; // import * as actions from '../../actions';
import { openRoom, setLastOpen } from '../../actions/room'; import { openRoom, setLastOpen } from '../../actions/room';
import { editCancel, toggleReactionPicker, actionsShow } from '../../actions/messages'; import { editCancel, toggleReactionPicker, actionsShow } from '../../actions/messages';
import database from '../../lib/realm'; import database from '../../lib/realm';
@ -21,17 +21,18 @@ import RoomsHeader from './Header';
import ReactionPicker from './ReactionPicker'; import ReactionPicker from './ReactionPicker';
import styles from './styles'; import styles from './styles';
import log from '../../utils/log'; import log from '../../utils/log';
import I18n from '../../i18n';
@connect( @connect(
state => ({ state => ({
Site_Url: state.settings.Site_Url || state.server ? state.server.server : '', // Site_Url: state.settings.Site_Url || state.server ? state.server.server : '',
Message_TimeFormat: state.settings.Message_TimeFormat, // Message_TimeFormat: state.settings.Message_TimeFormat,
loading: state.messages.isFetching, loading: state.messages.isFetching,
user: state.login.user, user: state.login.user,
actionMessage: state.messages.actionMessage actionMessage: state.messages.actionMessage
}), }),
dispatch => ({ dispatch => ({
actions: bindActionCreators(actions, dispatch), // actions: bindActionCreators(actions, dispatch),
openRoom: room => dispatch(openRoom(room)), openRoom: room => dispatch(openRoom(room)),
editCancel: () => dispatch(editCancel()), editCancel: () => dispatch(editCancel()),
setLastOpen: date => dispatch(setLastOpen(date)), setLastOpen: date => dispatch(setLastOpen(date)),
@ -48,8 +49,8 @@ export default class RoomView extends LoggedView {
editCancel: PropTypes.func, editCancel: PropTypes.func,
rid: PropTypes.string, rid: PropTypes.string,
name: PropTypes.string, name: PropTypes.string,
Site_Url: PropTypes.string, // Site_Url: PropTypes.string,
Message_TimeFormat: PropTypes.string, // Message_TimeFormat: PropTypes.string,
loading: PropTypes.bool, loading: PropTypes.bool,
actionMessage: PropTypes.object, actionMessage: PropTypes.object,
toggleReactionPicker: PropTypes.func.isRequired, toggleReactionPicker: PropTypes.func.isRequired,
@ -191,7 +192,7 @@ export default class RoomView extends LoggedView {
if (!this.state.joined) { if (!this.state.joined) {
return ( return (
<View> <View>
<Text>You are in preview mode.</Text> <Text>{I18n.t('You_are_in_preview_mode')}</Text>
<Button title='Join' onPress={this.joinRoom} /> <Button title='Join' onPress={this.joinRoom} />
</View> </View>
); );
@ -199,14 +200,14 @@ export default class RoomView extends LoggedView {
if (this.state.room.archived || this.isReadOnly()) { if (this.state.room.archived || this.isReadOnly()) {
return ( return (
<View style={styles.readOnly}> <View style={styles.readOnly}>
<Text>This room is read only</Text> <Text>{I18n.t('This_room_is_read_only')}</Text>
</View> </View>
); );
} }
if (this.isBlocked()) { if (this.isBlocked()) {
return ( return (
<View style={styles.blockedOrBlocker}> <View style={styles.blockedOrBlocker}>
<Text>This room is blocked</Text> <Text>{I18n.t('This_room_is_blocked')}</Text>
</View> </View>
); );
} }
@ -215,9 +216,9 @@ export default class RoomView extends LoggedView {
renderHeader = () => { renderHeader = () => {
if (this.state.end) { if (this.state.end) {
return <Text style={styles.loadingMore}>Start of conversation</Text>; return <Text style={styles.loadingMore}>{I18n.t('Start_of_conversation')}</Text>;
} }
return <Text style={styles.loadingMore}>Loading more messages...</Text>; return <Text style={styles.loadingMore}>{I18n.t('Loading_messages_ellipsis')}</Text>;
} }
render() { render() {
return ( return (

View File

@ -14,25 +14,26 @@ import { STATUS_COLORS } from '../../../constants/colors';
import { setSearch } from '../../../actions/rooms'; import { setSearch } from '../../../actions/rooms';
import styles from './styles'; import styles from './styles';
import log from '../../../utils/log'; import log from '../../../utils/log';
import I18n from '../../../i18n';
const title = (offline, connecting, authenticating, logged) => { const title = (offline, connecting, authenticating, logged) => {
if (offline) { if (offline) {
return 'offline...'; return `${ I18n.t('Offline') }...`;
} }
if (connecting) { if (connecting) {
return 'Connecting...'; return `${ I18n.t('Connecting') }...`;
} }
if (authenticating) { if (authenticating) {
return 'Authenticating...'; return `${ I18n.t('Authenticating') }...`;
} }
if (logged) { if (logged) {
return null; return null;
} }
return 'Not logged...'; return `${ I18n.t('Not_logged') }...`;
}; };
@connect(state => ({ @connect(state => ({
@ -96,7 +97,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
getUserStatusLabel() { getUserStatusLabel() {
const status = this.getUserStatus(); const status = this.getUserStatus();
return status.charAt(0).toUpperCase() + status.slice(1); return I18n.t(status.charAt(0).toUpperCase() + status.slice(1));
} }
showModal() { showModal() {
@ -124,7 +125,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
<View <View
style={styles.left} style={styles.left}
accessible accessible
accessibilityLabel={`Connected to ${ this.props.baseUrl }. Tap to view servers list.`} accessibilityLabel={`${ I18n.t('Connected_to') } ${ this.props.baseUrl }. ${ I18n.t('Tap_to_view_servers_list') }.`}
accessibilityTraits='button' accessibilityTraits='button'
testID='rooms-list-view-sidebar' testID='rooms-list-view-sidebar'
> >
@ -156,7 +157,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
const t = title(offline, connecting, authenticating, logged); const t = title(offline, connecting, authenticating, logged);
const accessibilityLabel = `${ user.username }, ${ this.getUserStatusLabel() }, tap to change status`; const accessibilityLabel = `${ user.username }, ${ this.getUserStatusLabel() }, ${ I18n.t('tap_to_change_status') }`;
return ( return (
<TouchableOpacity <TouchableOpacity
style={styles.titleContainer} style={styles.titleContainer}
@ -190,7 +191,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
<TouchableOpacity <TouchableOpacity
style={styles.headerButton} style={styles.headerButton}
onPress={() => this.onPressSearchButton()} onPress={() => this.onPressSearchButton()}
accessibilityLabel='Search' accessibilityLabel={I18n.t('Search')}
accessibilityTraits='button' accessibilityTraits='button'
> >
<Icon <Icon
@ -204,7 +205,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
<TouchableOpacity <TouchableOpacity
style={styles.headerButton} style={styles.headerButton}
onPress={() => this.createChannel()} onPress={() => this.createChannel()}
accessibilityLabel='Create channel' accessibilityLabel={I18n.t('Create_Channel')}
accessibilityTraits='button' accessibilityTraits='button'
testID='rooms-list-view-create-channel' testID='rooms-list-view-create-channel'
> >
@ -223,6 +224,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
renderModalButton = (status, text) => { renderModalButton = (status, text) => {
const statusStyle = [styles.status, { marginRight: 10, backgroundColor: STATUS_COLORS[status] }]; const statusStyle = [styles.status, { marginRight: 10, backgroundColor: STATUS_COLORS[status] }];
const textStyle = { flex: 1, fontWeight: this.props.user.status === status ? 'bold' : 'normal' }; const textStyle = { flex: 1, fontWeight: this.props.user.status === status ? 'bold' : 'normal' };
const label = text || status;
return ( return (
<TouchableOpacity <TouchableOpacity
style={styles.modalButton} style={styles.modalButton}
@ -231,7 +233,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
> >
<View style={statusStyle} /> <View style={statusStyle} />
<Text style={textStyle}> <Text style={textStyle}>
{text || status.charAt(0).toUpperCase() + status.slice(1)} {I18n.t(label.charAt(0).toUpperCase() + label.slice(1))}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
); );
@ -252,7 +254,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
style={styles.inputSearch} style={styles.inputSearch}
onChangeText={text => this.onSearchChangeText(text)} onChangeText={text => this.onSearchChangeText(text)}
returnKeyType='search' returnKeyType='search'
placeholder='Search' placeholder={I18n.t('Search')}
clearButtonMode='while-editing' clearButtonMode='while-editing'
blurOnSubmit blurOnSubmit
autoCorrect={false} autoCorrect={false}
@ -281,7 +283,7 @@ export default class RoomsListHeaderView extends React.PureComponent {
{this.renderModalButton('online')} {this.renderModalButton('online')}
{this.renderModalButton('busy')} {this.renderModalButton('busy')}
{this.renderModalButton('away')} {this.renderModalButton('away')}
{this.renderModalButton('offline', 'Invisible')} {this.renderModalButton('offline', 'invisible')}
</View> </View>
</Modal> </Modal>
</View> </View>

View File

@ -14,6 +14,7 @@ import styles from './styles';
import debounce from '../../utils/debounce'; import debounce from '../../utils/debounce';
import LoggedView from '../View'; import LoggedView from '../View';
import log from '../../utils/log'; import log from '../../utils/log';
import I18n from '../../i18n';
@connect(state => ({ @connect(state => ({
user: state.login.user, user: state.login.user,
@ -166,7 +167,7 @@ export default class RoomsListView extends LoggedView {
style={styles.searchBox} style={styles.searchBox}
onChangeText={text => this.onSearchChangeText(text)} onChangeText={text => this.onSearchChangeText(text)}
returnKeyType='search' returnKeyType='search'
placeholder='Search' placeholder={I18n.t('Search')}
clearButtonMode='while-editing' clearButtonMode='while-editing'
blurOnSubmit blurOnSubmit
autoCorrect={false} autoCorrect={false}
@ -213,7 +214,7 @@ export default class RoomsListView extends LoggedView {
renderCreateButtons = () => ( renderCreateButtons = () => (
<ActionButton buttonColor='rgba(231,76,60,1)'> <ActionButton buttonColor='rgba(231,76,60,1)'>
<ActionButton.Item buttonColor='#9b59b6' title='Create Channel' onPress={() => { this.createChannel(); }} > <ActionButton.Item buttonColor='#9b59b6' title={I18n.t('Create_Channel')} onPress={() => { this.createChannel(); }} >
<Icon name='md-chatbubbles' style={styles.actionButtonIcon} /> <Icon name='md-chatbubbles' style={styles.actionButtonIcon} />
</ActionButton.Item> </ActionButton.Item>
</ActionButton> </ActionButton>

View File

@ -14,6 +14,7 @@ import buildMessage from '../../lib/methods/helpers/buildMessage';
import Message from '../../containers/message'; import Message from '../../containers/message';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
import log from '../../utils/log'; import log from '../../utils/log';
import I18n from '../../i18n';
@connect(state => ({ @connect(state => ({
user: state.login.user, user: state.login.user,
@ -114,12 +115,12 @@ export default class SearchMessagesView extends LoggedView {
<View style={styles.searchContainer}> <View style={styles.searchContainer}>
<RCTextInput <RCTextInput
inputRef={(e) => { this.name = e; }} inputRef={(e) => { this.name = e; }}
label='Search' label={I18n.t('Search')}
onChangeText={this.onChangeSearch} onChangeText={this.onChangeSearch}
placeholder='Search Messages' placeholder={I18n.t('Search_Messages')}
testID='search-message-view-input' testID='search-message-view-input'
/> />
<Markdown msg='You can search using RegExp. e.g. `/^text$/i`' /> <Markdown msg={I18n.t('You_can_search_using_RegExp_eg')} />
<View style={styles.divider} /> <View style={styles.divider} />
</View> </View>
<FlatList <FlatList

View File

@ -12,6 +12,7 @@ import Avatar from '../containers/Avatar';
import Loading from '../containers/Loading'; import Loading from '../containers/Loading';
import debounce from '../utils/debounce'; import debounce from '../utils/debounce';
import LoggedView from './View'; import LoggedView from './View';
import I18n from '../i18n';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
@ -101,7 +102,7 @@ export default class SelectedUsersView extends LoggedView {
justifyContent: 'center' justifyContent: 'center'
}} }}
onPress={() => params.nextAction()} onPress={() => params.nextAction()}
accessibilityLabel='Submit' accessibilityLabel={I18n.t('Submit')}
accessibilityTraits='button' accessibilityTraits='button'
testID='selected-users-view-submit' testID='selected-users-view-submit'
> >
@ -227,7 +228,7 @@ export default class SelectedUsersView extends LoggedView {
style={styles.searchBox} style={styles.searchBox}
onChangeText={text => this.onSearchChangeText(text)} onChangeText={text => this.onSearchChangeText(text)}
returnKeyType='search' returnKeyType='search'
placeholder='Search' placeholder={I18n.t('Search')}
clearButtonMode='while-editing' clearButtonMode='while-editing'
blurOnSubmit blurOnSubmit
testID='select-users-view-search' testID='select-users-view-search'

View File

@ -8,6 +8,7 @@ import { openSnippetedMessages, closeSnippetedMessages } from '../../actions/sni
import styles from './styles'; import styles from './styles';
import Message from '../../containers/message'; import Message from '../../containers/message';
import RCActivityIndicator from '../../containers/ActivityIndicator'; import RCActivityIndicator from '../../containers/ActivityIndicator';
import I18n from '../../i18n';
@connect( @connect(
state => ({ state => ({
@ -74,7 +75,7 @@ export default class SnippetedMessagesView extends LoggedView {
renderEmpty = () => ( renderEmpty = () => (
<View style={styles.listEmptyContainer} testID='snippeted-messages-view'> <View style={styles.listEmptyContainer} testID='snippeted-messages-view'>
<Text>No snippeted messages</Text> <Text>{I18n.t('No_snippeted_messages')}</Text>
</View> </View>
) )

View File

@ -10,10 +10,11 @@ import styles from './styles';
import Message from '../../containers/message'; import Message from '../../containers/message';
import { toggleStarRequest } from '../../actions/messages'; import { toggleStarRequest } from '../../actions/messages';
import RCActivityIndicator from '../../containers/ActivityIndicator'; import RCActivityIndicator from '../../containers/ActivityIndicator';
import I18n from '../../i18n';
const STAR_INDEX = 0; const STAR_INDEX = 0;
const CANCEL_INDEX = 1; const CANCEL_INDEX = 1;
const options = ['Unstar', 'Cancel']; const options = [I18n.t('Unstar'), I18n.t('Cancel')];
@connect( @connect(
state => ({ state => ({
@ -98,7 +99,7 @@ export default class StarredMessagesView extends LoggedView {
renderEmpty = () => ( renderEmpty = () => (
<View style={styles.listEmptyContainer} testID='starred-messages-view'> <View style={styles.listEmptyContainer} testID='starred-messages-view'>
<Text>No starred messages</Text> <Text>{I18n.t('No_starred_messages')}</Text>
</View> </View>
) )
@ -138,7 +139,7 @@ export default class StarredMessagesView extends LoggedView {
<ActionSheet <ActionSheet
key='starred-messages-view-action-sheet' key='starred-messages-view-action-sheet'
ref={o => this.actionSheet = o} ref={o => this.actionSheet = o}
title='Actions' title={I18n.t('Actions')}
options={options} options={options}
cancelButtonIndex={CANCEL_INDEX} cancelButtonIndex={CANCEL_INDEX}
onPress={this.handleActionPress} onPress={this.handleActionPress}

View File

@ -3,15 +3,11 @@ import PropTypes from 'prop-types';
import { WebView } from 'react-native'; import { WebView } from 'react-native';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
class TermsServiceView extends React.Component { class TermsServiceView extends React.PureComponent {
static propTypes = { static propTypes = {
termsService: PropTypes.string termsService: PropTypes.string
} }
static navigationOptions = () => ({
title: 'Terms of service'
});
render() { render() {
return ( return (
<WebView source={{ html: this.props.termsService }} /> <WebView source={{ html: this.props.termsService }} />

View File

@ -178,16 +178,16 @@ describe('Room screen', () => {
describe('Message', async() => { describe('Message', async() => {
it('should show message actions', async() => { it('should show message actions', async() => {
await element(by.text(`${ data.random }message`)).longPress(); await element(by.text(`${ data.random }message`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Cancel')).tap(); await element(by.text('Cancel')).tap();
await waitFor(element(by.text('Cancel'))).toBeNotVisible().withTimeout(2000); await waitFor(element(by.text('Cancel'))).toBeNotVisible().withTimeout(2000);
}); });
it('should copy permalink', async() => { it('should copy permalink', async() => {
await element(by.text(`${ data.random }message`)).longPress(); await element(by.text(`${ data.random }message`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Copy Permalink')).tap(); await element(by.text('Copy Permalink')).tap();
await expect(element(by.text('Permalink copied to clipboard!'))).toBeVisible(); await expect(element(by.text('Permalink copied to clipboard!'))).toBeVisible();
await waitFor(element(by.text('Permalink copied to clipboard!'))).toBeNotVisible().withTimeout(5000); await waitFor(element(by.text('Permalink copied to clipboard!'))).toBeNotVisible().withTimeout(5000);
@ -197,8 +197,8 @@ describe('Room screen', () => {
it('should copy message', async() => { it('should copy message', async() => {
await element(by.text(`${ data.random }message`)).longPress(); await element(by.text(`${ data.random }message`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Copy Message')).tap(); await element(by.text('Copy Message')).tap();
await expect(element(by.text('Copied to clipboard!'))).toBeVisible(); await expect(element(by.text('Copied to clipboard!'))).toBeVisible();
await waitFor(element(by.text('Copied to clipboard!'))).toBeNotVisible().withTimeout(5000); await waitFor(element(by.text('Copied to clipboard!'))).toBeNotVisible().withTimeout(5000);
@ -207,10 +207,10 @@ describe('Room screen', () => {
it('should star message', async() => { it('should star message', async() => {
await element(by.text(`${ data.random }message`)).longPress(); await element(by.text(`${ data.random }message`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Star')).tap(); await element(by.text('Star')).tap();
await waitFor(element(by.text('Messages actions'))).toBeNotVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeNotVisible().withTimeout(5000);
await element(by.text(`${ data.random }message`)).longPress(); await element(by.text(`${ data.random }message`)).longPress();
await waitFor(element(by.text('Unstar'))).toBeVisible().withTimeout(2000); await waitFor(element(by.text('Unstar'))).toBeVisible().withTimeout(2000);
await expect(element(by.text('Unstar'))).toBeVisible(); await expect(element(by.text('Unstar'))).toBeVisible();
@ -220,8 +220,8 @@ describe('Room screen', () => {
it('should react to message', async() => { it('should react to message', async() => {
await element(by.text(`${ data.random }message`)).longPress(); await element(by.text(`${ data.random }message`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Add Reaction')).tap(); await element(by.text('Add Reaction')).tap();
await waitFor(element(by.id('reaction-picker'))).toBeVisible().withTimeout(2000); await waitFor(element(by.id('reaction-picker'))).toBeVisible().withTimeout(2000);
await expect(element(by.id('reaction-picker'))).toBeVisible(); await expect(element(by.id('reaction-picker'))).toBeVisible();
@ -254,8 +254,8 @@ describe('Room screen', () => {
it('should reply message', async() => { it('should reply message', async() => {
await mockMessage('reply'); await mockMessage('reply');
await element(by.text(`${ data.random }reply`)).longPress(); await element(by.text(`${ data.random }reply`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Reply')).tap(); await element(by.text('Reply')).tap();
await element(by.id('messagebox-input')).typeText('replied'); await element(by.id('messagebox-input')).typeText('replied');
await element(by.id('messagebox-send-message')).tap(); await element(by.id('messagebox-send-message')).tap();
@ -265,8 +265,8 @@ describe('Room screen', () => {
it('should edit message', async() => { it('should edit message', async() => {
await mockMessage('edit'); await mockMessage('edit');
await element(by.text(`${ data.random }edit`)).longPress(); await element(by.text(`${ data.random }edit`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Edit')).tap(); await element(by.text('Edit')).tap();
await element(by.id('messagebox-input')).typeText('ed'); await element(by.id('messagebox-input')).typeText('ed');
await element(by.id('messagebox-send-message')).tap(); await element(by.id('messagebox-send-message')).tap();
@ -277,8 +277,8 @@ describe('Room screen', () => {
it('should quote message', async() => { it('should quote message', async() => {
await mockMessage('quote'); await mockMessage('quote');
await element(by.text(`${ data.random }quote`)).longPress(); await element(by.text(`${ data.random }quote`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Quote')).tap(); await element(by.text('Quote')).tap();
await element(by.id('messagebox-input')).typeText(`${ data.random }quoted`); await element(by.id('messagebox-input')).typeText(`${ data.random }quoted`);
await element(by.id('messagebox-send-message')).tap(); await element(by.id('messagebox-send-message')).tap();
@ -287,10 +287,10 @@ describe('Room screen', () => {
it('should pin message', async() => { it('should pin message', async() => {
await element(by.text(`${ data.random }edited`)).longPress(); await element(by.text(`${ data.random }edited`)).longPress();
await waitFor(element(by.text('Messages actions'))).toBeVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeVisible().withTimeout(5000);
await expect(element(by.text('Messages actions'))).toBeVisible(); await expect(element(by.text('Message actions'))).toBeVisible();
await element(by.text('Pin')).tap(); await element(by.text('Pin')).tap();
await waitFor(element(by.text('Messages actions'))).toBeNotVisible().withTimeout(5000); await waitFor(element(by.text('Message actions'))).toBeNotVisible().withTimeout(5000);
await waitFor(element(by.text(`${ data.random }edited`)).atIndex(1)).toBeVisible().withTimeout(60000); await waitFor(element(by.text(`${ data.random }edited`)).atIndex(1)).toBeVisible().withTimeout(60000);
await element(by.text(`${ data.random }edited`)).atIndex(0).longPress(); await element(by.text(`${ data.random }edited`)).atIndex(0).longPress();
await waitFor(element(by.text('Unpin'))).toBeVisible().withTimeout(2000); await waitFor(element(by.text('Unpin'))).toBeVisible().withTimeout(2000);

View File

@ -5,6 +5,7 @@
}; };
objectVersion = 46; objectVersion = 46;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; }; 00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; }; 00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
@ -12,6 +13,7 @@
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; }; 00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; }; 00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
00E356F31AD99517003FC87E /* RocketChatRNTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* RocketChatRNTests.m */; }; 00E356F31AD99517003FC87E /* RocketChatRNTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* RocketChatRNTests.m */; };
09CB5909C1E64707832358CE /* libRNI18n-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C01CD6D4653143EEB5100C3A /* libRNI18n-tvOS.a */; };
0C6E2DE448364EA896869ADF /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B37C79D9BD0742CE936B6982 /* libc++.tbd */; }; 0C6E2DE448364EA896869ADF /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B37C79D9BD0742CE936B6982 /* libc++.tbd */; };
0DC38A29B0E54AF4AF96CB95 /* MaterialCommunityIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2EADB1731B5E47D093292B59 /* MaterialCommunityIcons.ttf */; }; 0DC38A29B0E54AF4AF96CB95 /* MaterialCommunityIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 2EADB1731B5E47D093292B59 /* MaterialCommunityIcons.ttf */; };
0F026E58B8A6427D9A204D89 /* libSplashScreen.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B2607FA180F14E6584301101 /* libSplashScreen.a */; }; 0F026E58B8A6427D9A204D89 /* libSplashScreen.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B2607FA180F14E6584301101 /* libSplashScreen.a */; };
@ -65,12 +67,13 @@
B8C682AD1FD8511E003A12C8 /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1B0746E708284151B8AD1198 /* Ionicons.ttf */; }; B8C682AD1FD8511E003A12C8 /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1B0746E708284151B8AD1198 /* Ionicons.ttf */; };
B8C682AE1FD8511F003A12C8 /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1B0746E708284151B8AD1198 /* Ionicons.ttf */; }; B8C682AE1FD8511F003A12C8 /* Ionicons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1B0746E708284151B8AD1198 /* Ionicons.ttf */; };
B8E79AF41F3CD167005B464F /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB61A68108700A75B9A /* Info.plist */; }; B8E79AF41F3CD167005B464F /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB61A68108700A75B9A /* Info.plist */; };
BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD2E2837F110483CA29EE0D4 /* libFastImage.a */; };
BED2B77AA660460E8BC9F8E0 /* libRNFetchBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6533FB90166345D29F1B91C0 /* libRNFetchBlob.a */; }; BED2B77AA660460E8BC9F8E0 /* libRNFetchBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 6533FB90166345D29F1B91C0 /* libRNFetchBlob.a */; };
C758F0BD5C3244E2BA073E61 /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B696712EE2345A59F007A88 /* libRNImagePicker.a */; }; C758F0BD5C3244E2BA073E61 /* libRNImagePicker.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B696712EE2345A59F007A88 /* libRNImagePicker.a */; };
CBD0E0A35B174C4DBFED3B31 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E528DE3A405E43B4A37ABA68 /* Zocial.ttf */; }; CBD0E0A35B174C4DBFED3B31 /* Zocial.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E528DE3A405E43B4A37ABA68 /* Zocial.ttf */; };
D6408D9E4A864FF6BA986857 /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8A2DD67ADD954AD9873F45FC /* SimpleLineIcons.ttf */; }; D6408D9E4A864FF6BA986857 /* SimpleLineIcons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 8A2DD67ADD954AD9873F45FC /* SimpleLineIcons.ttf */; };
EF736EF520A64AE8820E684A /* libRealmReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF26CC845883492D8AC8869B /* libRealmReact.a */; }; EF736EF520A64AE8820E684A /* libRealmReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF26CC845883492D8AC8869B /* libRealmReact.a */; };
BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FD2E2837F110483CA29EE0D4 /* libFastImage.a */; }; F5BF54DC78E1411B8343933B /* libRNI18n.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 921481B47B50490CA761932E /* libRNI18n.a */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -326,6 +329,27 @@
remoteGlobalIDString = 39DF4FE71E00394E00F5B4B2; remoteGlobalIDString = 39DF4FE71E00394E00F5B4B2;
remoteInfo = RCTCustomInputController; remoteInfo = RCTCustomInputController;
}; };
7A770EC120BECDC7001AD51A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 1845C223DA364898A8400573 /* FastImage.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = A287971D1DE0C0A60081BDFA;
remoteInfo = FastImage;
};
7A770EC520BECDC7001AD51A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RNI18n;
};
7A770EC720BECDC7001AD51A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 6476C4051EEAA69700B10F51;
remoteInfo = "RNI18n-tvOS";
};
7A7F5C981FCC982500024129 /* PBXContainerItemProxy */ = { 7A7F5C981FCC982500024129 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = AD0379F2BCE84C968538CDAF /* RCTVideo.xcodeproj */; containerPortal = AD0379F2BCE84C968538CDAF /* RCTVideo.xcodeproj */;
@ -490,10 +514,12 @@
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RocketChatRN/Info.plist; sourceTree = "<group>"; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = RocketChatRN/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = RocketChatRN/main.m; sourceTree = "<group>"; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = RocketChatRN/main.m; sourceTree = "<group>"; };
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; }; 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
1845C223DA364898A8400573 /* FastImage.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = FastImage.xcodeproj; path = "../node_modules/react-native-fast-image/ios/FastImage.xcodeproj"; sourceTree = "<group>"; };
1B0746E708284151B8AD1198 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = file; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = "<group>"; }; 1B0746E708284151B8AD1198 /* Ionicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = file; name = Ionicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Ionicons.ttf"; sourceTree = "<group>"; };
1D3BB00B9ABF44EA9BD71318 /* libSafariViewManager.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libSafariViewManager.a; sourceTree = "<group>"; }; 1D3BB00B9ABF44EA9BD71318 /* libSafariViewManager.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libSafariViewManager.a; sourceTree = "<group>"; };
20CE3E407E0D4D9E8C9885F2 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTVideo.a; sourceTree = "<group>"; }; 20CE3E407E0D4D9E8C9885F2 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRCTVideo.a; sourceTree = "<group>"; };
22A8B76C8EBA443BB97CE82D /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = "<group>"; }; 22A8B76C8EBA443BB97CE82D /* RNVectorIcons.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNVectorIcons.xcodeproj; path = "../node_modules/react-native-vector-icons/RNVectorIcons.xcodeproj"; sourceTree = "<group>"; };
22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNI18n.xcodeproj; path = "../node_modules/react-native-i18n/ios/RNI18n.xcodeproj"; sourceTree = "<group>"; };
2D02E47B1E0B4A5D006451C7 /* RocketChatRN-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "RocketChatRN-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 2D02E47B1E0B4A5D006451C7 /* RocketChatRN-tvOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "RocketChatRN-tvOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
2D02E4901E0B4A5D006451C7 /* RocketChatRN-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "RocketChatRN-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 2D02E4901E0B4A5D006451C7 /* RocketChatRN-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "RocketChatRN-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
2EADB1731B5E47D093292B59 /* MaterialCommunityIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialCommunityIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf"; sourceTree = "<group>"; }; 2EADB1731B5E47D093292B59 /* MaterialCommunityIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = MaterialCommunityIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/MaterialCommunityIcons.ttf"; sourceTree = "<group>"; };
@ -519,6 +545,7 @@
7AFB8035205AE63000D004E7 /* RCTToast.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTToast.xcodeproj; path = "../node_modules/@remobile/react-native-toast/ios/RCTToast.xcodeproj"; sourceTree = "<group>"; }; 7AFB8035205AE63000D004E7 /* RCTToast.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTToast.xcodeproj; path = "../node_modules/@remobile/react-native-toast/ios/RCTToast.xcodeproj"; sourceTree = "<group>"; };
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; }; 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
8A2DD67ADD954AD9873F45FC /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = SimpleLineIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf"; sourceTree = "<group>"; }; 8A2DD67ADD954AD9873F45FC /* SimpleLineIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = SimpleLineIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/SimpleLineIcons.ttf"; sourceTree = "<group>"; };
921481B47B50490CA761932E /* libRNI18n.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNI18n.a; sourceTree = "<group>"; };
9A1E1766CCB84C91A62BD5A6 /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = "<group>"; }; 9A1E1766CCB84C91A62BD5A6 /* Foundation.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Foundation.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Foundation.ttf"; sourceTree = "<group>"; };
A18EFC3B0CFE40E0918A8F0C /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = "<group>"; }; A18EFC3B0CFE40E0918A8F0C /* EvilIcons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = EvilIcons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf"; sourceTree = "<group>"; };
AD0379F2BCE84C968538CDAF /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTVideo.xcodeproj; path = "../node_modules/react-native-video/ios/RCTVideo.xcodeproj"; sourceTree = "<group>"; }; AD0379F2BCE84C968538CDAF /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RCTVideo.xcodeproj; path = "../node_modules/react-native-video/ios/RCTVideo.xcodeproj"; sourceTree = "<group>"; };
@ -528,6 +555,7 @@
B8971BAC202A091D0000D245 /* KeyboardTrackingView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KeyboardTrackingView.xcodeproj; path = "../node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingView.xcodeproj"; sourceTree = "<group>"; }; B8971BAC202A091D0000D245 /* KeyboardTrackingView.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = KeyboardTrackingView.xcodeproj; path = "../node_modules/react-native-keyboard-tracking-view/lib/KeyboardTrackingView.xcodeproj"; sourceTree = "<group>"; };
B8C682611FD84CEF003A12C8 /* icomoon.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = icomoon.ttf; path = ../resources/fonts/icomoon.ttf; sourceTree = "<group>"; }; B8C682611FD84CEF003A12C8 /* icomoon.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = icomoon.ttf; path = ../resources/fonts/icomoon.ttf; sourceTree = "<group>"; };
BAAE4B947F5D44959F0A9D5A /* libRNZeroconf.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNZeroconf.a; sourceTree = "<group>"; }; BAAE4B947F5D44959F0A9D5A /* libRNZeroconf.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNZeroconf.a; sourceTree = "<group>"; };
C01CD6D4653143EEB5100C3A /* libRNI18n-tvOS.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = "libRNI18n-tvOS.a"; sourceTree = "<group>"; };
C21010507E5B4B37BA0E4C9D /* RNAudio.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNAudio.xcodeproj; path = "../node_modules/react-native-audio/ios/RNAudio.xcodeproj"; sourceTree = "<group>"; }; C21010507E5B4B37BA0E4C9D /* RNAudio.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNAudio.xcodeproj; path = "../node_modules/react-native-audio/ios/RNAudio.xcodeproj"; sourceTree = "<group>"; };
C23AEF1D9EBE4A38A1A6B97B /* RNSVG.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNSVG.xcodeproj; path = "../node_modules/react-native-svg/ios/RNSVG.xcodeproj"; sourceTree = "<group>"; }; C23AEF1D9EBE4A38A1A6B97B /* RNSVG.xcodeproj */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = "wrapper.pb-project"; name = RNSVG.xcodeproj; path = "../node_modules/react-native-svg/ios/RNSVG.xcodeproj"; sourceTree = "<group>"; };
DA50CE47374C4C35BE6D9D58 /* libRNSVG.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSVG.a; sourceTree = "<group>"; }; DA50CE47374C4C35BE6D9D58 /* libRNSVG.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNSVG.a; sourceTree = "<group>"; };
@ -535,8 +563,7 @@
DF26CC845883492D8AC8869B /* libRealmReact.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRealmReact.a; sourceTree = "<group>"; }; DF26CC845883492D8AC8869B /* libRealmReact.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRealmReact.a; sourceTree = "<group>"; };
E528DE3A405E43B4A37ABA68 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = "<group>"; }; E528DE3A405E43B4A37ABA68 /* Zocial.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Zocial.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Zocial.ttf"; sourceTree = "<group>"; };
F88C6541BD764BEEABB87272 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = "<group>"; }; F88C6541BD764BEEABB87272 /* Octicons.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = Octicons.ttf; path = "../node_modules/react-native-vector-icons/Fonts/Octicons.ttf"; sourceTree = "<group>"; };
1845C223DA364898A8400573 /* FastImage.xcodeproj */ = {isa = PBXFileReference; name = "FastImage.xcodeproj"; path = "../node_modules/react-native-fast-image/ios/FastImage.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; FD2E2837F110483CA29EE0D4 /* libFastImage.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libFastImage.a; sourceTree = "<group>"; };
FD2E2837F110483CA29EE0D4 /* libFastImage.a */ = {isa = PBXFileReference; name = "libFastImage.a"; path = "libFastImage.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -583,6 +610,7 @@
2C800DF680F8451599E80AF1 /* libSafariViewManager.a in Frameworks */, 2C800DF680F8451599E80AF1 /* libSafariViewManager.a in Frameworks */,
74815BBCB91147C08C8F7B3D /* libRNAudio.a in Frameworks */, 74815BBCB91147C08C8F7B3D /* libRNAudio.a in Frameworks */,
BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */, BAB7DC22804246F3923A1833 /* libFastImage.a in Frameworks */,
F5BF54DC78E1411B8343933B /* libRNI18n.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -598,6 +626,7 @@
2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */, 2D02E4C61E0B4AEC006451C7 /* libRCTSettings-tvOS.a in Frameworks */,
2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */, 2D02E4C71E0B4AEC006451C7 /* libRCTText-tvOS.a in Frameworks */,
2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */, 2D02E4C81E0B4AEC006451C7 /* libRCTWebSocket-tvOS.a in Frameworks */,
09CB5909C1E64707832358CE /* libRNI18n-tvOS.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -788,6 +817,23 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
7A770EBC20BECDC7001AD51A /* Products */ = {
isa = PBXGroup;
children = (
7A770EC620BECDC7001AD51A /* libRNI18n.a */,
7A770EC820BECDC7001AD51A /* libRNI18n-tvOS.a */,
);
name = Products;
sourceTree = "<group>";
};
7A770EBE20BECDC7001AD51A /* Products */ = {
isa = PBXGroup;
children = (
7A770EC220BECDC7001AD51A /* libFastImage.a */,
);
name = Products;
sourceTree = "<group>";
};
7A7F5C831FCC982500024129 /* Products */ = { 7A7F5C831FCC982500024129 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -843,6 +889,7 @@
4019A5E1911B4C61944FBCEC /* SafariViewManager.xcodeproj */, 4019A5E1911B4C61944FBCEC /* SafariViewManager.xcodeproj */,
C21010507E5B4B37BA0E4C9D /* RNAudio.xcodeproj */, C21010507E5B4B37BA0E4C9D /* RNAudio.xcodeproj */,
1845C223DA364898A8400573 /* FastImage.xcodeproj */, 1845C223DA364898A8400573 /* FastImage.xcodeproj */,
22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */,
); );
name = Libraries; name = Libraries;
sourceTree = "<group>"; sourceTree = "<group>";
@ -948,6 +995,9 @@
B2607FA180F14E6584301101 /* libSplashScreen.a */, B2607FA180F14E6584301101 /* libSplashScreen.a */,
1D3BB00B9ABF44EA9BD71318 /* libSafariViewManager.a */, 1D3BB00B9ABF44EA9BD71318 /* libSafariViewManager.a */,
1142E3442BA94B19BCF52814 /* libRNAudio.a */, 1142E3442BA94B19BCF52814 /* libRNAudio.a */,
FD2E2837F110483CA29EE0D4 /* libFastImage.a */,
921481B47B50490CA761932E /* libRNI18n.a */,
C01CD6D4653143EEB5100C3A /* libRNI18n-tvOS.a */,
); );
name = "Recovered References"; name = "Recovered References";
sourceTree = "<group>"; sourceTree = "<group>";
@ -1109,6 +1159,10 @@
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */; productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = ""; projectDirPath = "";
projectReferences = ( projectReferences = (
{
ProductGroup = 7A770EBE20BECDC7001AD51A /* Products */;
ProjectRef = 1845C223DA364898A8400573 /* FastImage.xcodeproj */;
},
{ {
ProductGroup = B8971BAD202A091D0000D245 /* Products */; ProductGroup = B8971BAD202A091D0000D245 /* Products */;
ProjectRef = B8971BAC202A091D0000D245 /* KeyboardTrackingView.xcodeproj */; ProjectRef = B8971BAC202A091D0000D245 /* KeyboardTrackingView.xcodeproj */;
@ -1185,6 +1239,10 @@
ProductGroup = B8E79A881F3CCC6C005B464F /* Products */; ProductGroup = B8E79A881F3CCC6C005B464F /* Products */;
ProjectRef = 4CD38E4891ED4601B7481448 /* RNFetchBlob.xcodeproj */; ProjectRef = 4CD38E4891ED4601B7481448 /* RNFetchBlob.xcodeproj */;
}, },
{
ProductGroup = 7A770EBC20BECDC7001AD51A /* Products */;
ProjectRef = 22D3971EAF2E4660B4FAB3DD /* RNI18n.xcodeproj */;
},
{ {
ProductGroup = 60B8375C1F3F6F4B00677E56 /* Products */; ProductGroup = 60B8375C1F3F6F4B00677E56 /* Products */;
ProjectRef = 4B38C7E37A8748E0BC665078 /* RNImagePicker.xcodeproj */; ProjectRef = 4B38C7E37A8748E0BC665078 /* RNImagePicker.xcodeproj */;
@ -1463,6 +1521,27 @@
remoteRef = 7A430E1D20238C02008F55BC /* PBXContainerItemProxy */; remoteRef = 7A430E1D20238C02008F55BC /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
7A770EC220BECDC7001AD51A /* libFastImage.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libFastImage.a;
remoteRef = 7A770EC120BECDC7001AD51A /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
7A770EC620BECDC7001AD51A /* libRNI18n.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRNI18n.a;
remoteRef = 7A770EC520BECDC7001AD51A /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
7A770EC820BECDC7001AD51A /* libRNI18n-tvOS.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = "libRNI18n-tvOS.a";
remoteRef = 7A770EC720BECDC7001AD51A /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
7A7F5C991FCC982500024129 /* libRCTVideo.a */ = { 7A7F5C991FCC982500024129 /* libRCTVideo.a */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = archive.ar; fileType = archive.ar;
@ -1773,6 +1852,7 @@
"$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-safari-view",
"$(SRCROOT)/../node_modules/react-native-audio/ios", "$(SRCROOT)/../node_modules/react-native-audio/ios",
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
); );
INFOPLIST_FILE = RocketChatRNTests/Info.plist; INFOPLIST_FILE = RocketChatRNTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@ -1787,6 +1867,8 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-ObjC", "-ObjC",
@ -1818,6 +1900,7 @@
"$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-safari-view",
"$(SRCROOT)/../node_modules/react-native-audio/ios", "$(SRCROOT)/../node_modules/react-native-audio/ios",
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
); );
INFOPLIST_FILE = RocketChatRNTests/Info.plist; INFOPLIST_FILE = RocketChatRNTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0; IPHONEOS_DEPLOYMENT_TARGET = 8.0;
@ -1832,6 +1915,8 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-ObjC", "-ObjC",
@ -1873,6 +1958,7 @@
"$(SRCROOT)/../node_modules/react-native-audio/ios", "$(SRCROOT)/../node_modules/react-native-audio/ios",
"$(SRCROOT)/../../../react-native/React/**", "$(SRCROOT)/../../../react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
); );
INFOPLIST_FILE = RocketChatRN/Info.plist; INFOPLIST_FILE = RocketChatRN/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -1919,6 +2005,7 @@
"$(SRCROOT)/../node_modules/react-native-audio/ios", "$(SRCROOT)/../node_modules/react-native-audio/ios",
"$(SRCROOT)/../../../react-native/React/**", "$(SRCROOT)/../../../react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
); );
INFOPLIST_FILE = RocketChatRN/Info.plist; INFOPLIST_FILE = RocketChatRN/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -1963,6 +2050,7 @@
"$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-safari-view",
"$(SRCROOT)/../node_modules/react-native-audio/ios", "$(SRCROOT)/../node_modules/react-native-audio/ios",
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
); );
INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist"; INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -1976,6 +2064,8 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-ObjC", "-ObjC",
@ -2017,6 +2107,7 @@
"$(SRCROOT)/../node_modules/react-native-safari-view", "$(SRCROOT)/../node_modules/react-native-safari-view",
"$(SRCROOT)/../node_modules/react-native-audio/ios", "$(SRCROOT)/../node_modules/react-native-audio/ios",
"$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**", "$(SRCROOT)/../node_modules/react-native-fast-image/ios/FastImage/**",
"$(SRCROOT)/../node_modules/react-native-i18n/ios",
); );
INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist"; INFOPLIST_FILE = "RocketChatRN-tvOS/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@ -2030,6 +2121,8 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-ObjC", "-ObjC",
@ -2067,6 +2160,8 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests"; PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -2100,6 +2195,8 @@
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"", "\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
); );
PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests"; PRODUCT_BUNDLE_IDENTIFIER = "com.facebook.REACT.RocketChatRN-tvOSTests";
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";

13
package-lock.json generated
View File

@ -8852,6 +8852,11 @@
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz",
"integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es=" "integrity": "sha1-MRYKNpMK2vH8BMYHT360FGXU7Es="
}, },
"i18n-js": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/i18n-js/-/i18n-js-3.0.3.tgz",
"integrity": "sha512-u144MQhV/8mz4Y5wP86SQAWMwS8gpe/JavIa9hugSI4WreezGgbhJPdk2Q60KcdIltKLiNefGtHNh1N8SSmQqQ=="
},
"iconv-lite": { "iconv-lite": {
"version": "0.4.19", "version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
@ -14806,6 +14811,14 @@
"prop-types": "15.6.1" "prop-types": "15.6.1"
} }
}, },
"react-native-i18n": {
"version": "2.0.12",
"resolved": "https://registry.npmjs.org/react-native-i18n/-/react-native-i18n-2.0.12.tgz",
"integrity": "sha512-2eTUk7BVZP5knthCmVt6y7rePFwrxXl4ym2I20e91oTYJnKM22sAjQMnLhRCYZWC4ucRBbe2pUp63uxNdTkkQw==",
"requires": {
"i18n-js": "3.0.3"
}
},
"react-native-image-picker": { "react-native-image-picker": {
"version": "0.26.10", "version": "0.26.10",
"resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-0.26.10.tgz", "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-0.26.10.tgz",

View File

@ -47,6 +47,7 @@
"react-native-fabric": "^0.5.1", "react-native-fabric": "^0.5.1",
"react-native-fast-image": "^4.0.14", "react-native-fast-image": "^4.0.14",
"react-native-fetch-blob": "^0.10.8", "react-native-fetch-blob": "^0.10.8",
"react-native-i18n": "^2.0.12",
"react-native-image-picker": "^0.26.10", "react-native-image-picker": "^0.26.10",
"react-native-keyboard-aware-scroll-view": "^0.5.0", "react-native-keyboard-aware-scroll-view": "^0.5.0",
"react-native-keyboard-input": "git+https://github.com/RocketChat/react-native-keyboard-input.git", "react-native-keyboard-input": "git+https://github.com/RocketChat/react-native-keyboard-input.git",