Sublime Forum

Is there a better way to turn off spell check for Japanese characters?

#1

I often deal with Japanese text, frequently mixed in with English text.

When I have spell check turned on, all Japanese characters are marked as misspelled, putting red lines everywhere, and it’s a little distracting.

I found this post from 2017, but the solution is very hard to understand, and seems to involve making specific file edits for the OP’s particular situation.

I’m hoping in 2020 there is a better approach. I’d like to be able to leave on the spell checker when editing files that contain English and Japanese, and either ignore the Japanese characters or correctly spell check it.

Is that possible?

0 Likes

#2

If you only need to disable it in Plain Text rather than every syntaxes. Q: Is is possible to deactivate the spellcheck for Japanese lines? is a solution to me.

But if you want to disable it in every syntaxes, no, I don’t want to maintain all those syntax by myself…


We can give CJK chars a special scope (meta.text.cjk in my example) and disable spell checking in that scope.

Plain text.tmLanguage:

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
  <dict>
    <key>fileTypes</key>
    <array>
      <string>txt</string>
    </array>
    <key>name</key>
    <string>Plain Text</string>
    <key>patterns</key>
    <array>
      <dict>
        <key>name</key>
        <string>meta.text.cjk</string>
        <key>begin</key>
        <!-- https://unicode-table.com/en/blocks/ -->
        <string>(?x)
          [\x{2E00}-\x{9FFF}] |
          [\x{A960}-\x{A97F}] |
          [\x{AC00}-\x{D7FF}] |
          [\x{F900}-\x{FAFF}] |
          [\x{FE30}-\x{FE6F}] |
          [\x{20000}-\x{3134F}]
        </string>
        <key>end</key>
        <string></string>
      </dict>
    </array>
    <key>scopeName</key>
    <string>text.plain</string>
  </dict>
</plist>

Preferences:

  1. Open a plain text file
  2. Main menu → Preferences → Settings - Syntax Specific
  3. ST should open a Plain text.sublime-settings and you fill in the following
{
    "spell_check": true,
    "spelling_selector": "- meta.text.cjk",
}
1 Like

#3

Yes, I only need this for plain text files, so I think your solution would work great.

However, I’m not totally clear on how to implement your fix.

I take the XML code you’ve provided, save it as meta.text.cjk, and then…

Where should I save the file (I’m on Windows 10)?

And then how do I access spelling_selector to edit it?

0 Likes

#4

No. The name is as-is, Plain text.tmLanguage.

  1. Preferences → Browse Packages
  2. Save the XML file as Text/Plain text.tmLanguage. If Text directory doesn’t exist, create it.

As it said, Preferences → Settings.

0 Likes

#5

I applied your suggestions, but it seems to not have taken effect.

I put the code in a file called Text/Plain Text.tmLanguage in the Packages directory with the XML code you provided.

I put this in the User side of Settings:

"spelling_selector": "markup.raw, source string.quoted - punctuation - meta.preprocessor.include, source comment - source comment.block.preprocessor, -(source, constant, keyword, storage, support, variable, markup.underline.link, meta.tag), - meta.text.cjk",

But Japanese text is still not being ignored:

Untitled-1

Did I do something wrong in my implementation?

0 Likes

#6

Ah, sorry I made it wrong. It should be

	"spelling_selector": "(markup.raw, source string.quoted - punctuation - meta.preprocessor.include, source comment - source comment.block.preprocessor, -(source, constant, keyword, storage, support, variable, markup.underline.link, meta.tag)) - meta.text.cjk",

All scopes should exclude meta.text.cjk.

0 Likes

#7

I’m sorry to report that I added your updated line, and Japanese text is still not being ignored.

Just to be sure, this is the version I have:

"spelling_selector": "(markup.raw, source string.quoted - punctuation - meta.preprocessor.include, source comment - source comment.block.preprocessor, -(source, constant, keyword, storage, support, variable, markup.underline.link, meta.tag)) - meta.text.cjk",

I also tried closing and restarting Sublime Text to see if that would help, and also turning spell check on and off.

0 Likes

#8

What’s the output when you press ctrl+alt+shift+p on JP chars.

0 Likes

#9

If I highlight Japanese text and press ctrl+alt+shift+p, a small window pops up that says text.plain, and there’s an option to Copy.

0 Likes

#10

Then it should be that the Text/Plain Text.tmLanguage part goes wrong. :thinking:
It should be text.plain meta.text.cjk if things go right.

0 Likes

#11

Can you share the full path of your Plain text.tmLanguage file.

0 Likes

#12

Sure!

C:\Users\xxxxxx\AppData\Roaming\Sublime Text 3\Packages\Text\Plain Text.tmLanguage

0 Likes

#13

Okay. I made another stupid mistake. The file name should be Plain text.tmLanguage with lowercase t.

0 Likes

#14

Thank you for all your help. The settings seem to have taken effect.

Unfortunately, however, I hate to say this, but… it seems the rules are only applying to the kanji part of the Japanese text, and not to all of it. I’m not sure if you know about Japanese text, but there are characters called “kana”, and they are not included in the rule to ignore Japanese text.

I feel bad that this is becoming so complicated. Maybe Japanese is just too much of a hassle to handle in this context.

0 Likes

#15

yes i do know some :smiley:

The CJK ranges on stackoverflow I found is not complete. I did some revise.

<string>[\x{2E00}-\x{9FFF}\x{A960}-\x{A97F}\x{AC00}-\x{D7FF}\x{FE30}-\x{FE6F}\x{20000}-\x{3134F}]+</string>
0 Likes

#16

Amazing! That’s done it. Spell checking on English words, Japanese is ignored.

Thanks!

Just for reference, here is the updated complete Text\Plain text.tmLanguage file:

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
  <dict>
    <key>fileTypes</key>
    <array>
      <string>txt</string>
    </array>
    <key>name</key>
    <string>Plain Text</string>
    <key>patterns</key>
    <array>
      <dict>
        <key>name</key>
        <string>meta.text.cjk</string>
        <key>begin</key>
        <string>[\x{3040}-\x{312f}\x{31f0}-\x{31ff}\x{4e00}-\x{9fff}\x{6300}-\x{77ff}\x{7800}-\x{8cff}\x{8d00}-\x{9fcc}\x{3400}-\x{4db5}\x{ff66}-\x{ff9f}\x{20000}-\x{215ff}\x{21600}-\x{230ff}\x{23100}-\x{245ff}\x{24600}-\x{260ff}\x{26100}-\x{275ff}\x{27600}-\x{290ff}\x{29100}-\x{2a6df}\x{2a700}-\x{2b734}\x{2b740}-\x{2b81d}]+</string>
        <key>end</key>
        <string></string>
      </dict>
    </array>
    <key>scopeName</key>
    <string>text.plain</string>
  </dict>
</plist>
0 Likes

#17

Here is a less intrusive language-specific settings for the Plain Text syntax.

  1. Open a plain text file
  2. Main menu → Preferences → Settings - Syntax Specific
  3. ST should open a Plain text.sublime-settings and you fill in the following
{
    "spell_check": true,
    "spelling_selector": "- meta.text.cjk",
}
1 Like

#18

I have created a custom syntax called ‘pine’, and I have tried to apply the same trick to turn off spell check for chinese (should work with cjk), but i just cannot get it to work. Any chance you may take a quick look for me @jfcherng?

File: pine.tmLanguage

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
  <dict>
    <key>fileTypes</key>
    <array>
      <string>pine</string>
    </array>
    <key>name</key>
    <string>pine</string>
    <key>patterns</key>
    <array>
      <dict>
        <key>name</key>
        <string>meta.text.cjk</string>
        <key>begin</key>
        <string>[\x{3040}-\x{312f}\x{31f0}-\x{31ff}\x{4e00}-\x{9fff}\x{6300}-\x{77ff}\x{7800}-\x{8cff}\x{8d00}-\x{9fcc}\x{3400}-\x{4db5}\x{ff66}-\x{ff9f}\x{20000}-\x{215ff}\x{21600}-\x{230ff}\x{23100}-\x{245ff}\x{24600}-\x{260ff}\x{26100}-\x{275ff}\x{27600}-\x{290ff}\x{29100}-\x{2a6df}\x{2a700}-\x{2b734}\x{2b740}-\x{2b81d}]+</string>
        <key>end</key>
        <string></string>
      </dict>
    </array>
    <key>scopeName</key>
    <string>source.pine</string>
  </dict>
</plist>
0 Likes

#19

File: pine.sublime-syntax

%YAML 1.2
---
name: pine
file_extensions:
  - pine
scope: source.pine

variables:
    identifier_regex: '[a-zA-Z_][a-zA-Z0-9_]*'

contexts:
  main:
    - match: //.*
      scope: comment.pine

  #constants

    - match: \b(true|false)\b
      scope: constant.language.pine

    - match: \b(bool|float|integer|string)\b
      scope: constant.language.pine

    - match: \b(time|timenow|year|month|weekofyear|dayofmonth|dayofweek|hour|minute|second|interval|isdaily|isdwm|isintraday|ismonthly|isweekly)\b
      scope: constant.language.pine

    - match: \b(open|high|low|close|volume|na|period|tikerid|source|symbol)\b
      scope: constant.language.pine

    - match: \b(accdist|area|areabr|hl(2|c3)|ohlc4)\b
      scope: constant.language.pine

    - match: \badjustment\.(dividends|none|splits)\b
      scope: constant.language.pine

    - match: \b(monday|tuesday|wednesday|thursday|friday|saturday|sunday|dayofweek)\b
      scope: constant.language.pine

    - match: \b(line|stepline|histogram|cross[^\(]|area|columns|circles)\b
      scope: constant.language.pine

    - match: \b(solid|dotted|dashed)\b
      scope: constant.language.pine

    - match: \b(session|session.(extended|regular))\b
      scope: constant.language.pine

    - match: \bscale.(left|none|right)\b
      scope: constant.language.pine

    - match: \bbarmerge\.(gaps_(off|on)|lookahead_(off|on))\b
      scope: constant.language.pine

    - match: \bbarstate\.is(confirmed|first|history|last|new|realtime)\b
      scope: constant.language.pine

    - match: \bcurrency\.(AUD|CAD|CHF|EUR|GBP|HKD|JPY|NOK|NONE|NZD|RUB|SEK|SGD|TRY|USD|ZAR)\b
      scope: constant.language.pine

    - match: \blocation\.(abovebar|belowbar|top|bottom|absolute)\b
      scope: constant.language.pine

    - match: \bshape\.(x(cross)?|(triangle|arrow|label)(up|down)|flag|circle|square|diamond)\b
      scope: constant.language.pine

    - match: \bsize\.(auto|huge|large|normal|small|tiny)\b
      scope: constant.language.pine

    - match: \bstrategy\.(cash|closedtrades|commission\.(cash_per_contract|cash_per_order|percent)|direction\.(all|long|short)|equity|eventrades|fixed|grossloss|grossprofit|initial_capital|long|losstrades|max_contracts_held_all|max_contracts_held_long|max_contracts_held_short|max_drawdown|netprofit|oca\.(cancel|none|reduce)|openprofit|opentrades|percent_of_equity|position_avg_price|position_entry_name|position_size|short|wintrades)\b
      scope: constant.language.pine

    - match: \bsyminfo\.(mintick|pointvalue|prefix|root|session|timezone)\b
      scope: constant.language.pine

    - match: \b(aqua|black|silver|gray|white|maroon|red|purple|fuchsia|green|lime|olive|yellow|navy|blue|teal|orange)\b
      scope: constant.language.pine

    - match: '#[a-fA-F0-9]{6}'
      scope: support.constant.pine

    - match: '\b([0-9]+)\b'
      scope: constant.numeric.pine

  # strings

    - match: ''''
      push: single-quoted-string
    - match: '"'
      push: double-quoted-string

  # operators

    - match: (\-|\+|\*|/|%)
      scope: keyword.operator.arithmetic.pine
    - match: (==|!=|<=|>=|<|>|\:=)
      scope: keyword.operator.comparison.pine
    - match: (\?|\:)
      scope: keyword.operator.ternary.pine
    - match: \b(and|or|not)\b
      scope: keyword.operator.logical.pine
    - match: "="
      scope: keyword.operator.assignment.pine

  # functions

    - match: '\b(alertcondition|a(bs|cos|lma|sin|tan|tr|vg)|bar(color|since)|bgcolor|cci|ceil|change|cog|color|correlation|cos|cross(over|under)?|cum|dayof(month|week)|dev|(e|s)ma|exp|falling|fill|fixnan|floor|heikinashi|highest(bars)?|hline|iff|input|kagi|linebreak|linreg|log(10)?|lowest(bars)?|macd|m(ax|in)|minute|mom|month|n(a|z)|offset|percentile_linear_(interpolation|nearest_rank)|percentrank|pivot(high|low)|plot(arrow|bar|candle|char|shape|figure)?|pow|renko|rising|r(ma|oc|si)|round|sar|second|security|sign|sin|sqrt|stdev|stoch|strategy|strategy\.(cancel|cancel_all|close|close_all|entry|exit|order)|study|sum|swma|tan|tickerid|time(stamp)?|tostring|tr|tsi|valuewhen|variance|v(wap|wma)|weekofyear|wma|year|{{identifier_regex}})(?=\()'
      captures:
        1: support.function.pine

    - match: '{{identifier_regex}}\s*(?=:?\=)'
      scope: variable.parameter.pine

    - match: ('({{identifier_regex}})\(.*\)\s(=>)\s'|if|else)
      captures:
        1: entity.name.function
        2: keyword.operator.assignment.pine

  single-quoted-string:
    - meta_scope: string.quoted.single.pine
    - match: \\.
      scope: constant.character.escape.pine
    - match: ''''
      pop: true

  double-quoted-string:
    - meta_scope: string.quoted.double.pine
    - match: \\.
      scope: constant.character.escape.pine
    - match: '"'
      pop: true
0 Likes

#20

File: pine_comments.tmPreferences

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
  <key>name</key>
  <string>Comments</string>
  <key>scope</key>
  <string>source.pine</string>
  <key>settings</key>
  <dict>
    <key>shellVariables</key>
    <array>
      <dict>
        <key>name</key>
        <string>TM_COMMENT_START</string>
        <key>value</key>
        <string>// </string>
      </dict>
    </array>
  </dict>
</dict>
</plist>
0 Likes