Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"dev": "vite",
"prebuild": "node scripts/copy-dictionaries.mjs",
"build": "vite build",
"test": "node --test scripts/*.test.mjs",
"preview": "vite preview",
"check": "svelte-check --tsconfig ./tsconfig.json",
"lint": "eslint .",
Expand Down Expand Up @@ -41,6 +42,7 @@
"dictionary-fr": "^3.0.0",
"dictionary-it": "^2.0.0",
"dictionary-nb": "^3.0.0",
"dictionary-nl": "^2.0.0",
"fflate": "^0.8.3",
"nspell": "^2.1.5",
"svelte-i18n": "^4.0.1",
Expand Down
2 changes: 1 addition & 1 deletion frontend/package.json.md5
Original file line number Diff line number Diff line change
@@ -1 +1 @@
48a90fd1c3ac1a9e4f4707bb63114d36
41981e805c2980f748c8242e519ab085
4 changes: 2 additions & 2 deletions frontend/scripts/copy-dictionaries.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ const scriptsDir = dirname(fileURLToPath(import.meta.url))
const frontend = dirname(scriptsDir)
const outDir = join(frontend, 'public', 'spellcheck')

// Latin-script locales Aerion ships translations for. zh-* excluded (CJK has no
// Latin-script locales Aerion ships dictionaries for. zh-* excluded (CJK has no
// Latin-style per-word spelling); vi omitted until a usable dictionary exists.
const LOCALES = ['en', 'cs', 'de', 'fr', 'it', 'nb']
const LOCALES = ['en', 'cs', 'de', 'fr', 'it', 'nb', 'nl']

await rm(outDir, { recursive: true, force: true })
await mkdir(outDir, { recursive: true })
Expand Down
31 changes: 31 additions & 0 deletions frontend/scripts/spellcheck.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import assert from 'node:assert/strict'
import { readFile } from 'node:fs/promises'
import test from 'node:test'
import nspell from 'nspell'
import { gunzipSync } from 'node:zlib'

async function dutchDictionary() {
const [aff, dic] = await Promise.all([
readFile(new URL('../node_modules/dictionary-nl/index.aff', import.meta.url), 'utf8'),
readFile(new URL('../node_modules/dictionary-nl/index.dic', import.meta.url), 'utf8'),
])
return nspell(aff, dic)
}

test('Dutch dictionary recognizes Dutch words and rejects a typo', async () => {
const spell = await dutchDictionary()

assert.equal(spell.correct('huis'), true)
assert.equal(spell.correct('huiss'), false)
assert.ok(spell.suggest('huiss').includes('huis'))
})

test('Dutch browser assets contain the dictionary files', async () => {
const [aff, dic] = await Promise.all([
readFile(new URL('../public/spellcheck/nl.aff.gz', import.meta.url)),
readFile(new URL('../public/spellcheck/nl.dic.gz', import.meta.url)),
])

assert.match(gunzipSync(aff).toString('utf8'), /Dutch support for Hunspell/)
assert.match(gunzipSync(dic).toString('utf8'), /\nhuis-\n/)
})
2 changes: 1 addition & 1 deletion frontend/src/lib/components/settings/ComposerTab.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
// Dictionaries Aerion ships, with their native display names.
const dictLanguages = SPELLCHECK_DICTS.map((code) => ({
code,
name: supportedLocales.find((l) => l.code === code)?.name ?? code,
name: supportedLocales.find((l) => l.code === code)?.name ?? (code === 'nl' ? 'Nederlands' : code),
}))

// Added-words list — read straight from the store (persists immediately on
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib/spellcheck/locales.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ const APP_TO_DICT: Record<string, string> = {
fr: 'fr',
it: 'it',
nb: 'nb',
nl: 'nl',
}

// Dictionaries bundled as static assets under /spellcheck/<key>.{aff,dic}.
export const SPELLCHECK_DICTS = ['en', 'cs', 'de', 'fr', 'it', 'nb'] as const
export const SPELLCHECK_DICTS = ['en', 'cs', 'de', 'fr', 'it', 'nb', 'nl'] as const

export function appLocaleToDict(locale: string | null | undefined): string | null {
if (!locale) return null
Expand Down