proper default languages

This commit is contained in:
Jeremy Kauffman 2019-11-05 13:54:58 -05:00 committed by Sean Yesmunt
parent de5c5a9626
commit 8a2393cb67
10 changed files with 76 additions and 85 deletions

View file

@ -2,10 +2,10 @@ import { WEBPACK_ELECTRON_PORT } from 'config';
import { app, BrowserWindow, dialog, shell, screen } from 'electron'; import { app, BrowserWindow, dialog, shell, screen } from 'electron';
import isDev from 'electron-is-dev'; import isDev from 'electron-is-dev';
import windowStateKeeper from 'electron-window-state'; import windowStateKeeper from 'electron-window-state';
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
import setupBarMenu from './menu/setupBarMenu'; import setupBarMenu from './menu/setupBarMenu';
import * as PAGES from '../../ui/constants/pages'; import * as PAGES from '../../ui/constants/pages';
import setLanguage from './setLanguage';
export default appState => { export default appState => {
// Get primary display dimensions from Electron. // Get primary display dimensions from Electron.
@ -86,10 +86,9 @@ export default appState => {
deepLinkingURI = ''; deepLinkingURI = '';
} }
window.loadURL(rendererURL + deepLinkingURI);
setupBarMenu(); setupBarMenu();
setLanguage(window); window.loadURL(rendererURL + deepLinkingURI);
window.on('close', event => { window.on('close', event => {
if (!appState.isQuitting && !appState.autoUpdateAccepted) { if (!appState.isQuitting && !appState.autoUpdateAccepted) {
@ -125,12 +124,25 @@ export default appState => {
} }
); );
}); });
window.once('ready-to-show', () => { window.once('ready-to-show', () => {
window.show(); window.show();
}); });
window.webContents.on('did-finish-load', () => { window.webContents.on('did-finish-load', () => {
window.webContents.session.setUserAgent(`LBRY/${app.getVersion()}`); window.webContents.session.setUserAgent(`LBRY/${app.getVersion()}`);
// restore the user's previous language - we have to do this from here because only electron process can access app.getLocale()
window.webContents.executeJavaScript("localStorage.getItem('language')").then(storedLanguage => {
const language =
storedLanguage && storedLanguage !== 'undefined' && storedLanguage !== 'null'
? storedLanguage
: app.getLocale().slice(0, 2);
if (language !== 'en' && SUPPORTED_LANGUAGES[language]) {
window.webContents.send('language-set', language);
}
});
if (isDev) { if (isDev) {
window.webContents.openDevTools(); window.webContents.openDevTools();
} }

View file

@ -1,22 +0,0 @@
import SUPPORTED_LANGUAGES from '../../ui/constants/supported_languages';
export default async function setLanguage(window) {
const storedLanguage = await window.webContents.executeJavaScript("localStorage.getItem('language')");
const lang = storedLanguage || app.getLocale().slice(0, 2) || 'en';
const supportedNonEnglish = Object.keys(SUPPORTED_LANGUAGES).filter(language => language !== 'en');
if (supportedNonEnglish.includes(lang)) {
fetch('https://lbry.com/i18n/get/lbry-desktop/app-strings/' + lang + '.json')
.then(response => response.json())
.then(json => {
const messages = {};
messages[lang] = json;
window.webContents.send('language-set', messages, lang);
})
.catch(error => {
window.webContents.send('language-set', {}, lang, error);
});
} else {
window.webContents.send('language-set', {}, lang);
}
}

View file

@ -860,5 +860,6 @@
"No results for %query%": "No results for %query%", "No results for %query%": "No results for %query%",
"You haven't downloaded anything from LBRY yet.": "You haven't downloaded anything from LBRY yet.", "You haven't downloaded anything from LBRY yet.": "You haven't downloaded anything from LBRY yet.",
"Explore new content": "Explore new content", "Explore new content": "Explore new content",
"Use this address to receive LBC.": "Use this address to receive LBC." "Use this address to receive LBC.": "Use this address to receive LBC.",
"Embedded": "Embedded"
} }

View file

@ -7,22 +7,6 @@
<body> <body>
<div id="app"></div> <div id="app"></div>
<script> <script src="ui.js"></script>
function loadUi() {
const script = document.createElement('script');
script.setAttribute('src', 'ui.js');
document.body.appendChild(script);
}
require('electron').ipcRenderer.on('language-set', (event, messages, language, error) => {
window.i18n_messages = messages;
window.localStorage.setItem('language', language);
if(error) {
console.error('Can\'t set language to ' + language);
console.error(error);
}
loadUi();
});
</script>
</body> </body>
</html> </html>

View file

@ -24,24 +24,23 @@
document.body.appendChild(script); document.body.appendChild(script);
} }
function supportedNonEnglish(language) {
return language === 'pl' ||
language === 'id' ||
language === 'de'
}
let lang; let lang;
try { try {
browserLocale = window.navigator.language.slice(0,2); const browserLocale = window.navigator.language.slice(0,2);
lang = window.localStorage.getItem('language') || browserLocale || 'en'; lang = window.localStorage.getItem('language') || browserLocale || 'en';
} catch { } catch {
lang = 'en'; lang = 'en';
} }
if (lang && supportedNonEnglish(lang)) {
/*this should match doSetLanguage in action/settings.js*/
if (lang && lang != 'en') {
fetch('https://lbry.com/i18n/get/lbry-desktop/app-strings/' + lang + '.json') fetch('https://lbry.com/i18n/get/lbry-desktop/app-strings/' + lang + '.json')
.then(r => r.json()) .then(r => r.json())
.then(j => { window.i18n_messages[lang] = j; loadUi(); }) .then(j => { window.i18n_messages[lang] = j; loadUi(); })
.catch(loadUi); .catch(() => {
window.localStorage.removeItem('language');
loadUi();
});
} else { } else {
loadUi(); loadUi();
} }

View file

@ -1,8 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import { doSetClientSetting } from 'redux/actions/settings'; import { doSetLanguage } from 'redux/actions/settings';
import { makeSelectClientSetting } from 'redux/selectors/settings'; import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doToast } from 'lbry-redux';
import SettingLanguage from './view'; import SettingLanguage from './view';
const select = state => ({ const select = state => ({
@ -10,8 +9,7 @@ const select = state => ({
}); });
const perform = dispatch => ({ const perform = dispatch => ({
setClientSetting: (key, value) => dispatch(doSetClientSetting(key, value)), setLanguage: value => dispatch(doSetLanguage(value)),
showToast: options => dispatch(doToast(options)),
}); });
export default connect( export default connect(

View file

@ -3,43 +3,27 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { FormField } from 'component/common/form'; import { FormField } from 'component/common/form';
import Spinner from 'component/spinner'; import Spinner from 'component/spinner';
import { SETTINGS } from 'lbry-redux';
import SUPPORTED_LANGUAGES from '../../constants/supported_languages'; import SUPPORTED_LANGUAGES from '../../constants/supported_languages';
type Props = { type Props = {
language: string, language: string,
showToast: ({}) => void, setLanguage: string => void,
setClientSetting: (string, boolean) => void,
}; };
function SettingLanguage(props: Props) { function SettingLanguage(props: Props) {
const [isFetching, setIsFetching] = useState(false); const { language, setLanguage } = props;
const [previousLanguage, setPreviousLanguage] = useState(null);
const languages = SUPPORTED_LANGUAGES; const languages = SUPPORTED_LANGUAGES;
const { language, showToast, setClientSetting } = props; if (previousLanguage && language !== previousLanguage) {
setPreviousLanguage(null);
}
function onLanguageChange(e) { function onLanguageChange(e) {
const { value } = e.target; const { value } = e.target;
setIsFetching(true); setPreviousLanguage(language);
setLanguage(value);
// this should match the behavior/logic in the static index-XXX.html files
fetch('https://lbry.com/i18n/get/lbry-desktop/app-strings/' + value + '.json')
.then(r => r.json())
.then(j => {
window.i18n_messages[value] = j;
})
.then(() => {
setIsFetching(false);
window.localStorage.setItem(SETTINGS.LANGUAGE, value);
setClientSetting(SETTINGS.LANGUAGE, value);
})
.catch(e => {
showToast({
message: __('Failed to load translations.'),
error: true,
});
setIsFetching(false);
});
} }
return ( return (
@ -60,7 +44,7 @@ function SettingLanguage(props: Props) {
</option> </option>
))} ))}
</FormField> </FormField>
{isFetching && <Spinner type="small" />} {previousLanguage && <Spinner type="small" />}
</React.Fragment> </React.Fragment>
); );
} }

View file

@ -13,7 +13,7 @@ import ReactDOM from 'react-dom';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { doConditionalAuthNavigate, doDaemonReady, doAutoUpdate, doOpenModal, doHideModal } from 'redux/actions/app'; import { doConditionalAuthNavigate, doDaemonReady, doAutoUpdate, doOpenModal, doHideModal } from 'redux/actions/app';
import { Lbry, doToast, isURIValid, setSearchApi } from 'lbry-redux'; import { Lbry, doToast, isURIValid, setSearchApi } from 'lbry-redux';
import { doUpdateIsNightAsync } from 'redux/actions/settings'; import { doSetLanguage, doUpdateIsNightAsync } from 'redux/actions/settings';
import { import {
doAuthenticate, doAuthenticate,
Lbryio, Lbryio,
@ -175,6 +175,10 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
} }
}); });
ipcRenderer.on('language-set', (event, language) => {
app.store.dispatch(doSetLanguage(language));
});
ipcRenderer.on('open-menu', (event, uri) => { ipcRenderer.on('open-menu', (event, uri) => {
if (uri && uri.startsWith('/help')) { if (uri && uri.startsWith('/help')) {
app.store.dispatch(push('/$/help')); app.store.dispatch(push('/$/help'));

View file

@ -27,7 +27,10 @@ class ModalIncompatibleDaemon extends React.PureComponent<Props> {
{__( {__(
'This app is running with an incompatible version of the LBRY protocol. You can still use it, but there may be issues. Re-run the installation package for best results.' 'This app is running with an incompatible version of the LBRY protocol. You can still use it, but there may be issues. Re-run the installation package for best results.'
)}{' '} )}{' '}
<Button button="link" label={__('Learn more')} href="https://lbry.com/faq/incompatible-protocol-version" />. {/* I noticed the period below could end up on a line by itself. This is probably not the ideal solution, but seems better than not adding this. */}
<span style={{ whiteSpace: 'nowrap' }}>
<Button button="link" label={__('Learn more')} href="https://lbry.com/faq/incompatible-protocol-version" />
</span>
</p> </p>
</Modal> </Modal>
); );

View file

@ -1,6 +1,7 @@
import { Lbry, ACTIONS } from 'lbry-redux'; import { Lbry, ACTIONS, doToast } from 'lbry-redux';
import * as SETTINGS from 'constants/settings'; import * as SETTINGS from 'constants/settings';
import analytics from 'analytics'; import analytics from 'analytics';
import SUPPORTED_LANGUAGES from 'constants/supported_languages';
const UPDATE_IS_NIGHT_INTERVAL = 5 * 60 * 1000; const UPDATE_IS_NIGHT_INTERVAL = 5 * 60 * 1000;
@ -82,3 +83,30 @@ export function doSetDarkTime(value, options) {
dispatch(doUpdateIsNight()); dispatch(doUpdateIsNight());
}; };
} }
export function doSetLanguage(language) {
return dispatch => {
// this should match the behavior/logic in index-web.html
fetch('https://lbry.com/i18n/get/lbry-desktop/app-strings/' + language + '.json')
.then(r => r.json())
.then(j => {
window.i18n_messages[language] = j;
})
.then(() => {
// set on localStorage so it can be read outside of redux
window.localStorage.setItem(SETTINGS.LANGUAGE, language);
dispatch(doSetClientSetting(SETTINGS.LANGUAGE, language));
})
.catch(e => {
window.localStorage.setItem(SETTINGS.LANGUAGE, 'en');
dispatch(doSetClientSetting(SETTINGS.LANGUAGE, 'en'));
const languageName = SUPPORTED_LANGUAGES[language] ? SUPPORTED_LANGUAGES[language] : language;
dispatch(
doToast({
message: __('Failed to load %language% translations.', { language: languageName }),
error: true,
})
);
});
};
}