Skip to content

Commit

Permalink
add chinese English dictionary
Browse files Browse the repository at this point in the history
  • Loading branch information
CodeApe committed Jul 25, 2024
1 parent 8c03054 commit 01a950c
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 62 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ jobs:
with:
go-version: '1.20'

- name: Build WASM
run: GOARCH=wasm GOOS=js go build -o ecdict.wasm
- name: Build WASM English-Chinese Dictionary
run: GOARCH=wasm GOOS=js go build -o ecdict.wasm ec_wasm.go ecdict.go

- name: Build WASM Chinese-English Dictionary
run: GOARCH=wasm GOOS=js go build -o cedict.wasm ce_wasm.go cedict.go

- name: Test
run: go test -v ./...
8 changes: 5 additions & 3 deletions cedict.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ func removeSurnames(entries []*DictEntryCE) []*DictEntryCE {
return result
}

func preLoadCeDict() (tw []*DictEntryCE, zh []*DictEntryCE) {
// PreLoadCeDict loads the CEDICT data from the embedded ZIP file and parses it into dictionary entries.
// It returns two slices of dictionary entries: one sorted by Traditional Chinese and the other by Simplified Chinese.
func PreLoadCeDict() (tw []*DictEntryCE, zh []*DictEntryCE) {
if len(ceDictSingletonTw) > 0 && len(ceDictSingletonCn) > 0 {
return ceDictSingletonTw, ceDictSingletonCn
}
Expand Down Expand Up @@ -155,7 +157,7 @@ func extractZipBytes(zipData []byte) (map[string][]byte, error) {
// Returns: A slice of pointers to DictEntryCE structs that match the search criteria.
func CeQueryLike(text string, isCnZh bool, count int) (result []*DictEntryCE) {
text = strings.TrimSpace(text)
tw, zh := preLoadCeDict()
tw, zh := PreLoadCeDict()
if isCnZh {
for _, w := range zh {
if strings.HasPrefix(w.Simplified, text) {
Expand Down Expand Up @@ -187,7 +189,7 @@ func CeQueryLike(text string, isCnZh bool, count int) (result []*DictEntryCE) {
// Returns: A pointer to a DictEntryCE struct if a match is found, or nil if no match is found.
func CeLookUp(text string, isCnZh bool) *DictEntryCE {
text = strings.TrimSpace(text)
tw, zh := preLoadCeDict()
tw, zh := PreLoadCeDict()
if isCnZh {
for _, w := range zh {
if strings.Compare(w.Simplified, text) == 0 {
Expand Down
7 changes: 5 additions & 2 deletions ecdict.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ func (d *DictEntryEC) Map() map[string]interface{} {
var dictMapSingleton = map[string]DictEntryEC{}
var lemmaMapSingleton = map[string]string{}

func preloadEcDict() {
// PreLoadEcDict ensures that the dictionary and lemma maps are loaded into memory.
// It checks if the `dictMapSingleton` and `lemmaMapSingleton` are empty.
// If they are empty, it calls `parseDict` to load the dictionary data and `parseLemma` to load the lemma data.
func PreLoadEcDict() {
if len(dictMapSingleton) == 0 {
dictMapSingleton = parseDict()
}
Expand Down Expand Up @@ -159,7 +162,7 @@ func parseLemma() map[string]string {
// Returns:
// - *DictEntryEC: A pointer to the dictionary item if found; otherwise, nil.
func EcLookUp(word string) *DictEntryEC {
preloadEcDict() // Ensure the dictionary is loaded before searching.
PreLoadEcDict() // Ensure the dictionary is loaded before searching.
word = strings.TrimSpace(word) // Trim spaces from the input word.
baseWord, ok := lemmaMapSingleton[word] // Check if the word has a base form in the lemma map.
if !ok {
Expand Down
71 changes: 38 additions & 33 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,22 @@ Thanks for https://github.com/skywind3000/ECDICT 's dictionary data.

```bash
# build wasm English-Chinese dictionary
GOARCH=wasm GOOS=js go build -o ecdict.wasm ec_build.go ecdict.go
GOARCH=wasm GOOS=js go build -o dict_ec.wasm wasm_ec/main.go

# build wasm Chinese-English dictionary
GOARCH=wasm GOOS=js go build -o cedict.wasm ce_build.go cedict.go
GOARCH=wasm GOOS=js go build -o dict_ce.wasm wasm_ce/main.go
```

or just use the prebuilt wasm file from https://github.com/mojocn/wasmecdict/releases/download/v1.0.1/ecdict.wasm

## How to use in JavaScript

### English-Chinese Dictionary WASM Usage

```typescript
import "./wasm_exec.js"; # from https://github.com/golang/go/blob/master/misc/wasm/wasm_exec.js

export interface WordItem {
export interface WordEntry {
word: string;
phonetic: string;
definition: string;
Expand All @@ -48,40 +50,41 @@ export interface WordItem {
}


type DictLookupFn = (word: string) => WordItem | null;

type DictLookupFn = (word: string) => WordEntry | undefined;

declare global {
export interface Window {
Go: any;
lookUp: DictLookupFn;
ecDictionary:()=>Object;
}
export interface Window {
Go: any;
ecLookUp: DictLookupFn;
ecDictInfo: () => Object;
}
}

//wasm binary file from https://github.com/mojocn/wasmecdict/releases/download/v1.0.1/ecdict.wasm
async function loadWasm(wasmUrl: string = "https://xxx.xxx.ame/ecdict.wasm") {
try {
if ("lookUp" in window && typeof window.lookUp === "function") {
return window.lookUp;
async function loadWasm(wasmUrl: string = "/dict_ec.wasm") {
//https://davetayls.me/blog/2022-11-24-use-wasm-compiled-golang-functions-in-nextjs
try {
if ("ecLookUp" in window && typeof window.ecLookUp === "function") {
return window.ecLookUp;
}
const go = new window.Go(); // Defined in wasm_exec.js
let wasm: WebAssembly.WebAssemblyInstantiatedSource;
if ("instantiateStreaming" in WebAssembly) {
wasm = await WebAssembly.instantiateStreaming(
fetch(wasmUrl),
go.importObject,
);
} else {
const resp = await fetch(wasmUrl);
const bytes = await resp.arrayBuffer();
wasm = await WebAssembly.instantiate(bytes, go.importObject);
}
go.run(wasm.instance);
return window.ecLookUp;
} catch (e) {
console.error(e);
return null;
}
const go = new window.Go(); // Defined in wasm_exec.js
let wasm: WebAssembly.WebAssemblyInstantiatedSource;
if ("instantiateStreaming" in WebAssembly) {
wasm = await WebAssembly.instantiateStreaming(
fetch(wasmUrl),
go.importObject,
);
} else {
const resp = await fetch(wasmUrl);
const bytes = await resp.arrayBuffer();
wasm = await WebAssembly.instantiate(bytes, go.importObject);
}
go.run(wasm.instance);
return window.lookUp;// now it's available, you can use `window.lookUp('Awesome')` to look up a word.
} catch (e) {
console.error(e);
return null;
}
}


Expand All @@ -91,11 +94,13 @@ usage:

```typescript

const wordInfo = window.lookUp('Awesome');
const wordInfo = window.ecLookUp('Awesome');
console.log(wordInfo);

```

### Chinese-English Dictionary WASM Usage



## how to use in Go
Expand Down
27 changes: 13 additions & 14 deletions ce_build.go → wasm_ce/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//go:build js && wasm

package wasmecdict
package main

import (
"github.com/mojocn/wasmecdict"
"syscall/js"
)

Expand All @@ -11,7 +12,7 @@ const versionCe = "1.0.1"
func ceLookUpTw(_ js.Value, args []js.Value) any {
if len(args) > 0 {
text := args[0].String()
res := CeLookUp(text, false)
res := wasmecdict.CeLookUp(text, false)
if res != nil {
return js.ValueOf(res.Map())
}
Expand All @@ -21,7 +22,7 @@ func ceLookUpTw(_ js.Value, args []js.Value) any {
func ceLookUpCn(_ js.Value, args []js.Value) any {
if len(args) > 0 {
text := args[0].String()
res := CeLookUp(text, true)
res := wasmecdict.CeLookUp(text, true)
if res != nil {
return js.ValueOf(res.Map())
}
Expand All @@ -31,7 +32,7 @@ func ceLookUpCn(_ js.Value, args []js.Value) any {
func ceQueryLikeTw(_ js.Value, args []js.Value) any {
if len(args) > 0 {
text := args[0].String()
words := CeQueryLike(text, false, 10)
words := wasmecdict.CeQueryLike(text, false, 10)
results := make([]map[string]interface{}, 0, len(words))
for _, word := range words {
results = append(results, word.Map())
Expand All @@ -43,7 +44,7 @@ func ceQueryLikeTw(_ js.Value, args []js.Value) any {
func ceQueryLikeCn(_ js.Value, args []js.Value) any {
if len(args) > 0 {
text := args[0].String()
words := CeQueryLike(text, true, 10)
words := wasmecdict.CeQueryLike(text, true, 10)
results := make([]map[string]interface{}, 0, len(words))
for _, word := range words {
results = append(results, word.Map())
Expand All @@ -56,7 +57,6 @@ func ceQueryLikeCn(_ js.Value, args []js.Value) any {
func ceDictInfo(_ js.Value, _ []js.Value) any {
return map[string]interface{}{
"version": versionCe,
"words": len(ceDictSingletonCn),
"author": "[email protected]",
"email": "[email protected]",
"DictionaryData": "https://www.mdbg.net/chinese/dictionary?page=cedict",
Expand All @@ -65,13 +65,12 @@ func ceDictInfo(_ js.Value, _ []js.Value) any {
}

func main() {
preLoadCeDict()
js.Global().Set("ceLookUpTw", js.FuncOf(ceLookUpTw)) //export window.ceLookUpTw to lookUp Chinese word
js.Global().Set("ceLookUpCn", js.FuncOf(ceLookUpCn)) //export window.ceLookUpCn to lookUp Chinese word
js.Global().Set("ceQueryLikeCn", js.FuncOf(ceQueryLikeCn)) //export window.ceLookUpCn to lookUp Chinese word
js.Global().Set("ceQueryLikeTw", js.FuncOf(ceQueryLikeTw)) //export window.ceLookUpCn to lookUp Chinese word
js.Global().Set("ceDictInfo", js.FuncOf(ceDictInfo)) //export window.ecInfo to get dictionary info

done := make(chan struct{}, 0)
wasmecdict.PreLoadCeDict()
js.Global().Set("ceLookUpTw", js.FuncOf(ceLookUpTw)) //export window.ceLookUpTw to lookUp Traditional Chinese word
js.Global().Set("ceLookUpCn", js.FuncOf(ceLookUpCn)) //export window.ceLookUpCn to lookUp Simplified Chinese word
js.Global().Set("ceQueryLikeCn", js.FuncOf(ceQueryLikeCn)) //export window.ceQueryLikeCn to query Simplified Chinese word
js.Global().Set("ceQueryLikeTw", js.FuncOf(ceQueryLikeTw)) //export window.ceQueryLikeTw to query Traditional Chinese word
js.Global().Set("ceDictInfo", js.FuncOf(ceDictInfo)) //export window.ceDictInfo to get dictionary info
done := make(chan struct{})
<-done
}
15 changes: 7 additions & 8 deletions ec_build.go → wasm_ec/main.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
//go:build js && wasm

package wasmecdict
package main

import (
"github.com/mojocn/wasmecdict"
"syscall/js"
)

Expand All @@ -11,7 +12,7 @@ const versionEc = "1.0.1"
func lookUp(_ js.Value, args []js.Value) any {
if len(args) > 0 {
text := args[0].String()
res := EcLookUp(text)
res := wasmecdict.EcLookUp(text)
if res != nil {
return js.ValueOf(res.Map())
}
Expand All @@ -22,8 +23,6 @@ func lookUp(_ js.Value, args []js.Value) any {
func ecDictInfo(_ js.Value, _ []js.Value) any {
return map[string]interface{}{
"version": versionEc,
"words": len(dictMapSingleton),
"lemmas": len(lemmaMapSingleton),
"author": "[email protected]",
"email": "[email protected]",
"DictionaryData": "https://github.com/skywind3000/ECDICT",
Expand All @@ -32,9 +31,9 @@ func ecDictInfo(_ js.Value, _ []js.Value) any {
}

func main() {
preloadEcDict()
js.Global().Set("ecLookUp", js.FuncOf(lookUp)) //export window.ecLookUp to lookUp English word
js.Global().Set("ecDictInfo", js.FuncOf(ecDictInfo)) //export window.ecInfo to get dictionary info
done := make(chan struct{}, 0)
wasmecdict.PreLoadEcDict()
js.Global().Set("ecLookUp", js.FuncOf(lookUp)) //use window.ecLookUp("word") to look up a word
js.Global().Set("ecDictInfo", js.FuncOf(ecDictInfo)) //use window.ecDictInfo() to get dictionary info
done := make(chan struct{})
<-done
}

0 comments on commit 01a950c

Please sign in to comment.