3

I have an app which is mostly about studying a new language. In my application there is an input field which expects text in a language that user study. So if user focuses on that input, ideally, I want automatically to switch a layout to a target language. To make user experience more enjoyable (you don't need to worry about a wrong layout).

What I know and have tried

  1. As I know browsers not able to provide API which I can use to determine a current layout.
  2. I have tried to detect if the last entered character is not a typical character for the target language then I use my mapping between key codes and target language letters and replace that entered character in particular position in input. After that I get caret reset. So I return it to previous position.

The problem with the second approach that if you type fast enough you can encounter problems with a caret position. And it leads to a wrong string in the input.

Do you have any ideas how to achieve that behavior which works even when you type text with a speed when you almost immediately press two keys at the same time?

P.S. Code for that described approach

 const codeToEn = {
    65: 'a',
    // ... and so on
 }


 const acceptableChars = /^[a-zA-Z0-9 .+_)(%@!?,&$*'"`~]+$/g;

 document.getElementById('some-input-id').addEventListener('keyup', function (e) {
    if (codeToEn[e.which]
        && !acceptableChars.test(this.value)) {
        const char = codeToEn[e.which];
        const {selectionStart, selectionEnd} = this;
        const currentVal = this.value;
        let leftPart = currentVal.substring(0, selectionStart - 1);
        let rightPart = currentVal.substring(selectionStart );
        this.value = leftPart + char + rightPart;
        this.setSelectionRange(selectionStart, selectionEnd);
    }
});
Kirill Reznikov
  • 2,327
  • 3
  • 20
  • 27
  • 1
    Aren't you fighting giants here? IMHO keyboard layout should be set by the user in his system settings, not fixed *on-the-fly*, automagically, by some application. - What has to do a layout question with some issues related to mispositioning the caret due to fast-typing and (bottleneck) slow code iteration? And all without showing a [mcve]? – Roko C. Buljan Jan 29 '18 at 23:58
  • 1
    "keyboard layout should be set by the user in his system settings, not by some application." I have 3 keyboard layouts on my PC (it is very common in Ukraine). Sometimes I forget to switch layout and I see it when I already typed 5-6 character. (some users type even without watching on the screen, so they will notice it in the end of typing.) But that particular field context dependent. And it doesn't make sense to type text in other language. So I tired pressing backspace every time. – Kirill Reznikov Jan 30 '18 at 00:03
  • So, since you cannot set OS language preferences from a web application via JS (those properties are read-only) - what you're left with is some issue with fast-typing I'm not sure anyone could help you with (since no code is provided). Am I missing something? – Roko C. Buljan Jan 30 '18 at 00:18
  • How can I read a user layout in OS? – Kirill Reznikov Jan 30 '18 at 00:35
  • I'm not sure how you plan to detect a word (or several), some string of N length, at the time of typing is from a specific language - without using some sort of huge language library (usually several MB large) to hit compare against the current value without causing a total program slowdown (taken you're presumably not using multithreading with WebWorkers). At this point all I can see plausible is notifying the user *"Hey you're using a wrong keyboard layout"* given the detected non-standard `navigator.language` or `systemLanguage` versus the detected string language guess. – Roko C. Buljan Jan 30 '18 at 00:36
  • P.S. if you're not using jQuery, which normalizes `e.which`, use rather `e.keyCode`. Another problem you might face soon is: *"nooo argh, what if the user **pastes** some text using mouse of CTRL+V"...* which would than involve the use of the `input` event etc etc. Take a look also at https://stackoverflow.com/a/8892715/383904 – Roko C. Buljan Jan 30 '18 at 00:41
  • Also notice that when fast-typing say *GH* you'll always get the `gh` string value, regardless of whether you released first the *H* or the *G* key - but `keyup` will fire the exact released character order - which will result in a program bug - since the release keys sequence might be `hg`. – Roko C. Buljan Jan 30 '18 at 01:01

2 Answers2

6

Convert Layout will help you: https://github.com/ai/convert-layout

It really small and supports many languages.

Andrey Sitnik
  • 971
  • 6
  • 9
1

Before you look into the code below, please note that my solution assumes that all the users use QWERTY / ЙЦУКЕН keyboard layout. This may be a huge simplification and you'll have to find a more complex approach to the keyboard layout detection (generally it's all about finding a correct symbols mapping).

The more useful part here is a fast substitution of symbols. So type fast or even copy-paste text. Hope it helps!

const En = "qwertyuiop[]asdfghjkl;'zxcvbnm,.",
      Ru = "йцукенгшщзхъфывапролджэячсмитьбю";
const RuEn = [...Ru].reduce((a, e, i) => (a[e] = En[i]) && (a[e.toUpperCase()] = En[i].toUpperCase()) && a, {});
let corrected = 0;

document.getElementById('ta').addEventListener('input', function() {
  let end = this.selectionEnd;
  for (let i = !!corrected * (this.value.length - corrected - 1); i < end; i++) {
    let s = RuEn[this.value[i]];
    if (s) this.value = this.value.split(this.value[i]).join(s);
  }
  this.selectionEnd = end;
  corrected = this.value.length - 1;
});
<textarea id="ta" cols="50" rows="10"></textarea>
Kosh
  • 16,966
  • 2
  • 19
  • 34