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?