Read More...

Learning Japanese with AppleScript and Simplenote

May 27, 2018 · 7 min read

If you happen to be using macOS and learning Japanese, you may have used the ウィズダム英和辞典 / The Wisdom English-Japanese Dictionary from macOS's default Dictionary app. It's an awesome dictionary!

When I didn't understand a Japanese word from an article or a TV show, I would perform the following actions...

  1. Open the Dictionary app
  2. Type the word I am searching for
  3. Use my mouse to highlight the definition
  4. Open Simplenote, a minimalist note taking app
  5. Create a new note
  6. Paste the definition

...All of this just so I can review it in the future! 🙂

Let's try to automate this process with the Automator.

Prerequisites

  1. macOS 🖥
  2. Simplenote

Getting Started

  1. Open Automator.
  2. Choose Service for the type of document.

ChooseType

  1. Once selected, on the top of your workspace, you will see Service receives selected text from any application. Since we are dealing with text in this scenario, we can leave it as is.
  2. In the search bar on the top left beside the Actions and Variables tab, search for the action called Get Specified Text.
  3. Drag Get Specified Text onto the gray space to the right. The gray box shows your workflow.
  4. Type whatever vocabulary you want to search in the newly dropped Get Specified Text. I chose 食べ物.

ChooseFirstAction

  1. Go back to the search bar and search for Get Definition of Word and drag it below your current workflow. You should see Get Specified Text connect with Get Definition of Word from a UI perspective.
  2. In Get Definition of Word, set the type of Dictionary to ウィズダム英和辞典/ウィズダム和英辞典. You have just created the first part of your workflow! Let's try executing it.
  3. Click on the ▶️ Run button on the top right to execute the flow.
  4. Click on the Results tab on Get Definition of Word box.
  5. Click on the { } tab right below it.

DictionaryFlow

  1. You will notice that we got our definition back! Get Specified Text passed the value 食べ物 in my case to Get Definition of Word. Unfortunately, the formatting is cleared with one long string as a result.
  2. We will have to reformat it slightly to make it somewhat legible and I'm going to use JavaScript. In the search bar, search for Run JavaScript and drag it below Get Definition of Word
  3. Paste the following code below into Run JavaScript. I won't go into the details of the logic of the code, but it reformats the string into a more legible format. It can definitely be optimized further, but this will work for now! When executed, the run function will be called, thus reformatting the code.
function run(input, parameters) {
  const stringifiedInput = input.toString()
  let title = ''
  let body = ''
  let firstSpaceIndex = null
  const indexOfFirstSemicolon = stringifiedInput.indexOf(';')
  const textBeforeFirstSemicolon = stringifiedInput.slice(
    0,
    indexOfFirstSemicolon
  )
  const textAfterFirstSemicolon = stringifiedInput.slice(
    indexOfFirstSemicolon + 1
  )
  const indexOfJapaneseCloseSquareBracket = textBeforeFirstSemicolon.indexOf(
    '】'
  )
  const hasJapaneseBracket = indexOfJapaneseCloseSquareBracket > -1
  if (!hasJapaneseBracket) {
    firstSpaceIndex = textBeforeFirstSemicolon.indexOf(' ')
    title = textBeforeFirstSemicolon.slice(0, firstSpaceIndex)
    body = stringifiedInput.slice(firstSpaceIndex)
  } else {
    title = textBeforeFirstSemicolon.slice(
      0,
      indexOfJapaneseCloseSquareBracket + 1
    )
    body = stringifiedInput.slice(indexOfJapaneseCloseSquareBracket + 1)
  }
  body = body.split(/([0-9]\s|[①-⑩]|[▸.])/g)
  let result = ''
  for (let i = 0; i < body.length; i++) {
    if (body[i].match(/([0-9]\s)/gi)) {
      result += `\n\n${body[i]}`
    } else if (
      body[i].match(/([①-⑩])/gi) ||
      ((body[i] === '▸' && body[i - 1] === '.') ||
        (body[i] === '▸' && body[i - 2] === '.'))
    ) {
      result += `\n${body[i]}`
    } else if (
      body[i] === '.' &&
      body[i - 2] !== '▸' &&
      body[i - 1] !== '▸' &&
      body[i - 1][body[i - 1].length - 1] !== ';'
    ) {
      result += `${body[i]}\n`
    } else if (body[i] === '】') {
      result += `${body[i]}\n`
    } else {
      result += body[i]
    }
  }
  if (result[0] === '\n') {
    return `${title}${result}`
  }
  return `${title}\n\n${result}`
}
  1. In the search bar, search for Copy to Clipboard and drag it below Run JavaScript. Copy to Clipboard copies the output from Run JavaScript.
  2. All that is left is to paste what we copied to Simplenote. Unfortunately, there isn't a Paste action, so this is where AppleScript comes into play.
  3. In the search bar, search for Run AppleScript and drag it below Copy to Clipboard. Copy the code below into Run AppleScript.
tell application "Simplenote"
  activate
  tell application "System Events"
    keystroke "n" using {command down}
    delay 0.2
    keystroke "v" using {command down}
    delay 0.5
    keystroke tab using {control down}
    keystroke "Japanese"
    delay 0.7
    keystroke return
    keystroke tab
  end tell
end tell

AppleScript

The code above does the following...

  1. Open Simplenote
  2. Create a new Note
  3. Paste the Definition
  4. Selects the Tag section of the Note and name it Japanese
  5. Blur focus from the Tag section

I added in the delay calls, because AppleScript seems to skip over commands, when a keystroke causes a UI change.

If you prefer to use a different note app, you can technically replace tell application "Simplenote" with your preferred app name like tell application "Note"

The code below is unique to Simplenote, so you should delete it if you want to paste to your own app.

keystroke tab using {control down}
keystroke "Japanese"
delay 0.7
keystroke return
keystroke tab
  1. Execute the flow with ▶️ Run on the top right, and you should see your definition saved in Simplenote with it tagged!

FullExecutionFlow

  1. Get Specified Text was only used for debugging purposes so remove it from the workflow by clicking on the ╳ on the top right corner or Get Specified Text
  2. Save your newly created Service. I named mine Japanese Dictionary.
  3. Now the Service is accessible in the context menu in your applications under the Service section, when you right-click. It is useful when looking up Japanese words from a browser.

BrowserUsage

  1. You can also activate a Service through a keyboard shortcut.

    1. Open System Preferences > Keyboard > Shortcuts.
    2. Click on Services on the Left Menu.
    3. Scroll down to the Text section and select your Service.
    4. Add a keyboard shortcut

BrowserUsage

Mine is set to Command + Shift + D, which might not work depending on the application you have opened as the application's keyboard shortcuts may override it.

The use case for the keyboard shortcut is when you are using the Dictionary app. If you decide to save the word, just highlight the word and use the shortcut command to save it to Simplenote. You save a few clicks. 😊

That being said though...I do sometimes run into errors, where the AppleScript doesn't seem to execute sequentially as if it the code was running asynchronously, so my quick fixes were to mess with the delay time.

Depending on the way you want things to work, just experiment with Automator! You don't have to save words the way I do. The only part I really had to code for was the JavaScript part but that's because I had to reformat the text. The AppleScript part is pretty self explanatory for the most part.

Anyways, the whole point of this article was to make your 日本語 studies more convenient.

Good Luck!