i18n #80
10
src/i18n.js
|
@ -1,10 +1,13 @@
|
|||
![]() No, the commented code can be removed. No, the commented code can be removed.
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
import { NativeModules, Platform } from 'react-native';
|
||||
import { SETTINGS } from 'lbry-redux';
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
import { doTransifexUpload } from 'lbryinc';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
import RNFS from 'react-native-fs';
|
||||
|
||||
const isProduction = !__DEV__; // eslint-disable-line no-undef
|
||||
let knownMessages = null;
|
||||
|
||||
window.language = 'en';
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
window.i18n_messages = window.i18n_messages || {};
|
||||
|
||||
function saveMessage(message) {
|
||||
|
@ -55,11 +58,12 @@ function checkMessageAndSave(message, messagesFilePath) {
|
|||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
}
|
||||
|
||||
export function __(message, tokens) {
|
||||
let language =
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
Platform.OS === 'android'
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
let language = window.language;
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
/* Platform.OS === 'android'
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
? NativeModules.I18nManager.localeIdentifier
|
||||
: NativeModules.SettingsManager.settings.AppleLocale;
|
||||
language = language ? language.substring(0, 2) : 'en';
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
window.language = language ? language.substring(0, 2) : 'en'; */
|
||||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
||||
|
||||
if (!isProduction) {
|
||||
saveMessage(message);
|
||||
|
|
|||
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
![]() do you want this here? do you want this here?
![]() No, the commented code can be removed. No, the commented code can be removed.
|
|
@ -1,5 +1,5 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { SETTINGS } from 'lbry-redux';
|
||||
import { SETTINGS, doToast } from 'lbry-redux';
|
||||
import { doPushDrawerStack, doPopDrawerStack, doSetPlayerVisible } from 'redux/actions/drawer';
|
||||
import { doSetClientSetting } from 'redux/actions/settings';
|
||||
import { selectCurrentRoute, selectDrawerStack } from 'redux/selectors/drawer';
|
||||
|
@ -12,6 +12,7 @@ const select = state => ({
|
|||
currentRoute: selectCurrentRoute(state),
|
||||
drawerStack: selectDrawerStack(state),
|
||||
keepDaemonRunning: makeSelectClientSetting(SETTINGS.KEEP_DAEMON_RUNNING)(state),
|
||||
language: makeSelectClientSetting(SETTINGS.LANGUAGE)(state),
|
||||
showNsfw: makeSelectClientSetting(SETTINGS.SHOW_NSFW)(state),
|
||||
showUriBarSuggestions: makeSelectClientSetting(SETTINGS.SHOW_URI_BAR_SUGGESTIONS)(state),
|
||||
receiveSubscriptionNotifications: makeSelectClientSetting(SETTINGS.RECEIVE_SUBSCRIPTION_NOTIFICATIONS)(state),
|
||||
|
@ -21,6 +22,7 @@ const select = state => ({
|
|||
});
|
||||
|
||||
const perform = dispatch => ({
|
||||
notify: data => dispatch(doToast(data)),
|
||||
pushDrawerStack: () => dispatch(doPushDrawerStack(Constants.DRAWER_ROUTE_SETTINGS)),
|
||||
popDrawerStack: () => dispatch(doPopDrawerStack()),
|
||||
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)),
|
||||
|
|
|
@ -1,12 +1,32 @@
|
|||
import React from 'react';
|
||||
import { SETTINGS } from 'lbry-redux';
|
||||
import { Text, View, ScrollView, Switch, NativeModules } from 'react-native';
|
||||
import { ActivityIndicator, Picker, Platform, Text, View, ScrollView, Switch, NativeModules } from 'react-native';
|
||||
import { navigateBack } from 'utils/helper';
|
||||
import { __ } from 'i18n';
|
||||
import AsyncStorage from '@react-native-community/async-storage';
|
||||
import Colors from 'styles/colors';
|
||||
import Constants from 'constants'; // eslint-disable-line node/no-deprecated-api
|
||||
import PageHeader from 'component/pageHeader';
|
||||
import RNFS from 'react-native-fs';
|
||||
import settingsStyle from 'styles/settings';
|
||||
|
||||
const languageOptions = [
|
||||
{ code: 'default', name: __('Use device language') },
|
||||
{ code: 'en', name: __('English') },
|
||||
{ code: 'gu', name: __('Gujarati') },
|
||||
{ code: 'hi', name: __('Hindi') },
|
||||
{ code: 'id', name: __('Indonesian') },
|
||||
{ code: 'ms', name: __('Malay') },
|
||||
{ code: 'pl', name: __('Polish') },
|
||||
{ code: 'pt', name: __('Portuguese') },
|
||||
{ code: 'es', name: __('Spanish') },
|
||||
];
|
||||
|
||||
class SettingsPage extends React.PureComponent {
|
||||
state = {
|
||||
downloadingLanguage: false,
|
||||
};
|
||||
|
||||
static navigationOptions = {
|
||||
title: 'Settings',
|
||||
};
|
||||
|
@ -53,17 +73,68 @@ class SettingsPage extends React.PureComponent {
|
|||
return value === null || value === undefined ? defaultValue : value;
|
||||
};
|
||||
|
||||
handleLanguageValueChange = value => {
|
||||
const { notify, setClientSetting } = this.props;
|
||||
|
||||
let language;
|
||||
if (value === 'default') {
|
||||
language =
|
||||
Platform.OS === 'android'
|
||||
? NativeModules.I18nManager.localeIdentifier
|
||||
: NativeModules.SettingsManager.settings.AppleLocale;
|
||||
language = language ? language.substring(0, 2) : 'en';
|
||||
} else {
|
||||
language = value;
|
||||
}
|
||||
|
||||
// check the local filesystem for the language first? Or download remote strings first?
|
||||
|
||||
// download and save the language file
|
||||
this.setState({ downloadingLanguage: true }, () => {
|
||||
fetch('https://lbry.com/i18n/get/lbry-mobile/app-strings/' + language + '.json')
|
||||
.then(r => r.json())
|
||||
.then(j => {
|
||||
window.i18n_messages[language] = j;
|
||||
|
||||
console.log(window.i18n_messages);
|
||||
|
||||
// write the language file to the filesystem
|
||||
const langFilePath = RNFS.ExternalDirectoryPath + '/' + language + '.json';
|
||||
RNFS.writeFile(langFilePath, JSON.stringify(j), 'utf8');
|
||||
|
||||
// update state and client setting
|
||||
window.language = language;
|
||||
setClientSetting(SETTINGS.LANGUAGE, value);
|
||||
|
||||
this.setState({ downloadingLanguage: false });
|
||||
})
|
||||
.catch(e => {
|
||||
notify({ message: __('Failed to load %language% translations.', { language: language }), isError: true });
|
||||
this.setState({ downloadingLanguage: false });
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
handleBackPressed = () => {
|
||||
const { navigation, notify, drawerStack, popDrawerStack } = this.props;
|
||||
|
||||
if (this.state.downloadingLanguage) {
|
||||
notify({ message: 'Please wait for the language file to finish downloading' });
|
||||
return;
|
||||
}
|
||||
|
||||
navigateBack(navigation, drawerStack, popDrawerStack);
|
||||
};
|
||||
|
||||
render() {
|
||||
const {
|
||||
![]() I believe this needs to happen on startup and/or at some other interval to ensure a user receives new translations after changing their language. I believe this needs to happen on startup and/or at some other interval to ensure a user receives new translations after changing their language.
![]() I can make this happen on startup. We probably don't need to do an interval since it's unlikely the translations are going to be changing that often. I can make this happen on startup. We probably don't need to do an interval since it's unlikely the translations are going to be changing that often.
|
||||
backgroundPlayEnabled,
|
||||
drawerStack,
|
||||
keepDaemonRunning,
|
||||
navigation,
|
||||
popDrawerStack,
|
||||
receiveSubscriptionNotifications,
|
||||
receiveRewardNotifications,
|
||||
receiveInterestsNotifications,
|
||||
receiveCreatorNotifications,
|
||||
language,
|
||||
showNsfw,
|
||||
showUriBarSuggestions,
|
||||
setClientSetting,
|
||||
|
@ -78,10 +149,7 @@ class SettingsPage extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<View style={settingsStyle.container}>
|
||||
<PageHeader
|
||||
title={__('Settings')}
|
||||
onBackPressed={() => navigateBack(navigation, drawerStack, popDrawerStack)}
|
||||
/>
|
||||
<PageHeader title={__('Settings')} onBackPressed={this.handleBackPressed} />
|
||||
<ScrollView style={settingsStyle.scrollContainer}>
|
||||
<Text style={settingsStyle.sectionTitle}>{__('Content')}</Text>
|
||||
<View style={settingsStyle.row}>
|
||||
|
@ -99,6 +167,27 @@ class SettingsPage extends React.PureComponent {
|
|||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={settingsStyle.sectionTitle}>{__('Language')}</Text>
|
||||
<View style={settingsStyle.row}>
|
||||
<View style={settingsStyle.pickerText}>
|
||||
<Text style={settingsStyle.label}>{__('Choose language')}</Text>
|
||||
</View>
|
||||
<View style={settingsStyle.pickerContainer}>
|
||||
{this.state.downloadingLanguage && <ActivityIndicator size={'small'} color={Colors.NextLbryGreen} />}
|
||||
<Picker
|
||||
enabled={!this.state.downloadingLanguage}
|
||||
selectedValue={language || 'default'}
|
||||
style={settingsStyle.languagePicker}
|
||||
itemStyle={settingsStyle.languagePickerItem}
|
||||
onValueChange={this.handleLanguageValueChange}
|
||||
>
|
||||
{languageOptions.map(option => (
|
||||
<Picker.Item label={option.name} value={option.code} key={option.code} />
|
||||
))}
|
||||
</Picker>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View style={settingsStyle.row}>
|
||||
<View style={settingsStyle.switchText}>
|
||||
<Text style={settingsStyle.label}>{__('Show mature content')}</Text>
|
||||
|
|
|
@ -28,6 +28,12 @@ const settingsStyle = StyleSheet.create({
|
|||
width: '25%',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
pickerText: {
|
||||
width: '50%',
|
||||
},
|
||||
pickerContainer: {
|
||||
width: '50%',
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontFamily: 'Inter-UI-Regular',
|
||||
|
|
do you want this here?