-
Notifications
You must be signed in to change notification settings - Fork 563
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Auto-detect note language (for spelling and fonts) #1205
Conversation
c3c0149
to
afbc023
Compare
afbc023
to
5feb67f
Compare
b36c0c3
to
8e0c914
Compare
lib/state/settings/actions.ts
Outdated
} = getState(); | ||
|
||
dispatch(setLanguageDetection(!languageDetectionEnabled)); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hey! fun fact - we don't ned to create imperative thunk-style action creators for toggle-actions like this. reducers are great at keeping things simpler and then our actions remain a basic data object representing the action our users want to take.
// state/action-types
export type ToggleLanguageDetection = Action<'TOGGLE_LANGUAGE_DETECTION'>;
// …/settings/actions.ts
import * as A from '../action-types';
export const toggleLanguageDetection: A.ActionCreator<A.ToggleLanguageDetection> = () => ( {
type: 'TOGGLE_LANGUAGE_DETECTION',
} );
// …/settings/reducer.ts
const languageDetection: A.Reducer<boolean> = (state = false, action) => {
switch (action.type) {
case 'SET_LANGUAGE_DETECTION':
return action.languageDetectionEnabled;
case 'TOGGLE_LANGUAGE_DETECTION':
return !state;
default:
return state;
}
}
Note here that we never need to base our intentions/actions off of the current app state - all we have to do is explain what we're trying to accomplish and then the reducers govern their own data type. It gets murkier when we mash together multiple data values into a single reducer, which is where combineReducers
can help (you can see how things were prior to #1216 - sometimes the boiler plate is valuable for other reasons, here in keeping separate data types isolated from each other and making it easier to reason about changes from the user's perspective).
It may also be the case that when we're working this way we don't need the SET_
action at all. This is the css with the edit/preview mode toggle, because the app starts in one mode and all that matters from the user's perspective is the intention to toggle the mode, not necessary to set it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that makes sense. And I see the benefits of the combineReducers
approach better now. Thanks for the tip!
@mirka it's so awesome to see you updating this PR - thanks so much! |
528aa9c
to
7b337d0
Compare
lib/note-content-editor.tsx
Outdated
if (spellCheckEnabled !== prevProps.spellCheckEnabled) { | ||
this.editorKey += 1; | ||
this.forceUpdate(); | ||
updateLanguage(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we instead incorporate the language into the key
itself so that we don't need to track an increasing number and force a re-render
?
getEditorKey = () => {
const { spellCheckEnabled } = this.props;
const { lang } = this.state;
return `${ spellCheckEnabled ? 'spellcheck' : 'no_spellcheck' }-${ lang || 'unknown_lang' }`;
}
render() {
…
key={ this.editorKey() }
…
}
With this I believe we should be able to get rid of the force-update cycles and allow the prop-changes to trigger the editor update naturally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
replaced in ef9fcb7
lib/note-detail/index.tsx
Outdated
@@ -241,6 +245,7 @@ export class NoteDetail extends Component { | |||
} | |||
|
|||
const mapStateToProps = ({ appState: state, ui, settings }) => ({ | |||
detectLanguage: settings.languageDetectionEnabled, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we might as well add this inside of <NoteContentEditor />
so we don't have to pass it through this component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated in ef9fcb7
checked: settings.languageDetectionEnabled, | ||
click: appCommandSender({ action: 'toggleLanguageDetection' }), | ||
visible: !platform.isOSX(), // currently not working on Mac | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides disabling language-detection (and switching back to English?) is there any way to manually choose the language?
I can imagine that if someone wants to write in one language about another language the detection could be consistently wrong but then I'd want to manually fix it.
For example, writing in German about French poetry.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is technically feasible, but I think that use case probably isn't common enough to warrant the clutter of an additional menu item. However, I did initially post a UI suggestion for a global manual select (as well as some other, per-note possibilities) in the original issue.
This is mostly a UI design decision, so my thinking was to start out with the most simplest design, which is auto detection. If that works well enough for the majority of our users, great. If not, we can revisit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did initially post a UI suggestion for a global manual select
Yeah that's what I meant. It's a good idea.
start out with the most simplest design
Also a great idea. I wouldn't want to hold up this PR for not adding more but I wanted to ask if it was something already available we might have just been overlooking, for example, in the right-click menu of the text view if all we had to do were set some boolean toggle…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to ask if it was something already available we might have just been overlooking
I'm afraid not 😅 Also, I wrote "technically feasible" but I overlooked one possible complication we might run into: Getting a definitive list of available spell checker languages. I haven't looked into it too deeply, but it doesn't seem like a language list is exposed through electron-spellchecker
. If Chromium doesn't expose a list, it might get complicated. (Just a heads up in case you consider it in the future.)
7cb3fad
to
710cd0f
Compare
@mirka I have rebased this PR against the latest |
@dmsnell Thanks for the review and improvements! Feel free to move forward however the team wishes 👍 |
ef9fcb7
to
c66fe2c
Compare
In this commit we're replacing the method of force-upating the editor to reflect language changes with a declarative method based on incorporating the relevant paratemers into the editor key. For example, instead of setting the editor key to `0` and then incrementing to `1` and force-updating it we now set the key to `NOTE_ID-with-spelling-lang-de` or if the detected language change to `NOTE_ID-with-spell-lang-en_US`. This should automatically recreate the editor as we want without going through a workaround to force it. We're also moving the dependent state-based props from `<NoteDetail />` to `<NoteContentEditor />` where they are used so that we don't inexplicably pass them _through_ the parent component.
c66fe2c
to
9559a8a
Compare
Closing for now. Too out of date. We can take a look when we are ready to work on this. |
Closes #949
Closes #788
This enhances the spellchecker by adding language auto-detection. It's working pretty well in my testing, and hopefully it will be a better experience than having to manually select a language from a dropdown.
Bonus: Better fonts on Windows
As a bonus, I'm using the auto-detected language to set a
lang
attribute to the note body. This will help Electron in Windows to select language-appropriate fonts when the primary OS language is not set to that (#788). One limitation to this is that it's only for the Note Editor, and not the NoteList, since that would be too costly. Still, it's an improvement over the current behavior.To test
These changes only affect Electron on Windows and Linux. (Don't know why, but the language detection feature in
electron-spellchecker
is disabled on Mac. It's strange because it works if I just comment out that line.)You can set
localStorage.debug="electron-spellchecker:*"
in the devtools console and reload to see the language switching in action. Language will be determined every time a different note is selected, or whenever the spelling/auto-detection menu items are toggled. If a language cannot be detected (either by being too short or ambiguous), it will use the OS language.Test instructions on Linux/Windows
Check Spelling
in the Edit menu.Auto-Detect Language
in the Edit menu.Test instructions on Mac
Auto-Detect Language
option in the Edit menu is hidden. (Feature is disabled on Mac)