Skip to content

Commit

Permalink
Auto-detect note language (for spelling and fonts)
Browse files Browse the repository at this point in the history
This commit rebases the work done by @mirka in 528aa9c against the latest `develop`
to simplify the branching and merging which had been keeping it up to date.
  • Loading branch information
dmsnell committed Feb 11, 2020
1 parent c83d3fc commit 7b337d0
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 8 deletions.
8 changes: 8 additions & 0 deletions desktop/menus/edit-menu.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const platform = require('../detect/platform');
const { appCommandSender } = require('./utils');

const buildEditMenu = settings => {
Expand Down Expand Up @@ -50,6 +51,13 @@ const buildEditMenu = settings => {
checked: settings.spellCheckEnabled,
click: appCommandSender({ action: 'toggleSpellCheck' }),
},
{
label: '&Auto-Detect Language',
type: 'checkbox',
checked: settings.languageDetectionEnabled,
click: appCommandSender({ action: 'toggleLanguageDetection' }),
visible: !platform.isOSX(), // currently not working on Mac
},
],
};
};
Expand Down
1 change: 1 addition & 0 deletions lib/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const mapDispatchToProps: S.MapDispatch<
'setAccountName',
'toggleAutoHideMenuBar',
'toggleFocusMode',
'toggleLanguageDetection',
'toggleSpellCheck',
]),
dispatch
Expand Down
54 changes: 46 additions & 8 deletions lib/note-content-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export default class NoteContentEditor extends Component {
hasRemoteUpdate: PropTypes.bool.isRequired,
version: PropTypes.string,
}),
detectLanguage: PropTypes.bool.isRequired,
filter: PropTypes.string.isRequired,
noteId: PropTypes.string,
onChangeContent: PropTypes.func.isRequired,
Expand Down Expand Up @@ -89,6 +90,7 @@ export default class NoteContentEditor extends Component {
this.props.content.text,
this.props.filter
),
lang: undefined,
};

editorKey = 0;
Expand Down Expand Up @@ -152,16 +154,51 @@ export default class NoteContentEditor extends Component {
};

componentDidUpdate(prevProps) {
const { content, filter, noteId, spellCheckEnabled } = this.props;
const {
content,
detectLanguage,
filter,
noteId,
spellCheckEnabled,
} = this.props;

const { editorState } = this.state;

// To immediately reflect the changes to the spell check setting,
// we must remount the Editor and force update. The remount is
// done by changing the `key` prop on the Editor.
// https://stackoverflow.com/questions/35792275/
if (spellCheckEnabled !== prevProps.spellCheckEnabled) {
this.editorKey += 1;
this.forceUpdate();
const updateLanguage = () => {
const minimumContentLength = 10;
if (!detectLanguage || content.text.length < minimumContentLength) {
window.spellCheckHandler.switchLanguage(navigator.language);
this.setState({ lang: undefined });
} else {
// Auto-detect the note content language to switch spellchecker
window.spellCheckHandler.provideHintText(content.text).then(() => {
// Use the auto-detected language to set a `lang` attribute on the
// note, which helps Chromium in Electron pick an appropriate font
this.setState({
lang: window.spellCheckHandler.currentSpellcheckerLanguage,
});
});
}
};

// Only relevant in Electron
if (window.spellCheckHandler) {
// To immediately reflect the changes to the spell check setting,
// we must remount the Editor and force update. The remount is
// done by changing the `key` prop on the Editor.
// https://stackoverflow.com/questions/35792275/
if (spellCheckEnabled !== prevProps.spellCheckEnabled) {
this.editorKey += 1;
this.forceUpdate();
updateLanguage();
}

if (
noteId !== prevProps.noteId ||
detectLanguage !== prevProps.detectLanguage
) {
updateLanguage();
}
}

// If another note/revision is selected,
Expand Down Expand Up @@ -302,6 +339,7 @@ export default class NoteContentEditor extends Component {
render() {
return (
<div
lang={this.state.lang}
onCopy={this.copyPlainText}
onCut={this.copyPlainText}
style={{ height: '100%' }}
Expand Down
5 changes: 5 additions & 0 deletions lib/note-detail/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export class NoteDetail extends Component {
static displayName = 'NoteDetail';

static propTypes = {
detectLanguage: PropTypes.bool.isRequired,
dialogs: PropTypes.array.isRequired,
filter: PropTypes.string.isRequired,
fontSize: PropTypes.number,
Expand All @@ -33,6 +34,7 @@ export class NoteDetail extends Component {
};

static defaultProps = {
detectLanguage: false,
storeFocusEditor: noop,
storeHasFocus: noop,
};
Expand Down Expand Up @@ -184,6 +186,7 @@ export class NoteDetail extends Component {

render() {
const {
detectLanguage,
note,
filter,
fontSize,
Expand Down Expand Up @@ -223,6 +226,7 @@ export class NoteDetail extends Component {
>
<NoteContentEditor
ref={this.saveEditorRef}
detectLanguage={detectLanguage}
spellCheckEnabled={spellCheckEnabled}
storeFocusEditor={this.storeFocusContentEditor}
storeHasFocus={this.storeEditorHasFocus}
Expand All @@ -241,6 +245,7 @@ export class NoteDetail extends Component {
}

const mapStateToProps = ({ appState: state, ui, settings }) => ({
detectLanguage: settings.languageDetectionEnabled,
dialogs: state.dialogs,
filter: state.filter,
note: state.revision || ui.note,
Expand Down
2 changes: 2 additions & 0 deletions lib/state/action-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type SetSpellCheck = Action<
>;
export type SetTheme = Action<'setTheme', { theme: T.Theme }>;
export type SetWPToken = Action<'setWPToken', { token: string }>;
export type ToggleLanguageDetection = Action<'toggleLanguageDetection'>;

/*
* Normal action types
Expand Down Expand Up @@ -83,6 +84,7 @@ export type ActionType =
| SetTheme
| SetUnsyncedNoteIds
| SetWPToken
| ToggleLanguageDetection
| ToggleSimperiumConnectionStatus
| ToggleTagDrawer;

Expand Down
4 changes: 4 additions & 0 deletions lib/state/settings/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,7 @@ export const toggleAutoHideMenuBar = () => (dispatch, getState) => {
autoHideMenuBar: newValue,
});
};

export const toggleLanguageDetection: A.ActionCreator<A.ToggleLanguageDetection> = () => ({
type: 'toggleLanguageDetection',
});
6 changes: 6 additions & 0 deletions lib/state/settings/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const initialState = {
autoHideMenuBar: false,
focusModeEnabled: false,
fontSize: 16,
languageDetectionEnabled: false,
lineLength: 'narrow' as T.LineLength,
markdownEnabled: false,
noteDisplay: 'comfy' as T.ListDisplayMode,
Expand Down Expand Up @@ -53,6 +54,11 @@ const reducer: A.Reducer<typeof initialState> = (
return { ...state, theme: action.theme };
case 'setWPToken':
return { ...state, wpToken: action.token };
case 'toggleLanguageDetection':
return {
...state,
languageDetectionEnabled: !state.languageDetectionEnabled,
};
default:
return state;
}
Expand Down

0 comments on commit 7b337d0

Please sign in to comment.