diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ca59086 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,59 @@ +name: Release to Chrome Web Store + +on: + workflow_dispatch: + inputs: + dry_run: + description: Authenticate without uploading or submitting + required: true + default: true + type: boolean + +concurrency: + group: chrome-web-store-release + cancel-in-progress: false + +jobs: + submit: + runs-on: ubuntu-latest + environment: chrome-web-store + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + - name: Require master for a real submission + if: ${{ !inputs.dry_run && github.ref != 'refs/heads/master' }} + run: exit 1 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm run compile + - run: pnpm run lint + - run: pnpm run test:unit + - run: pnpm run zip + - uses: actions/upload-artifact@v4 + with: + name: liuchan-chrome-${{ github.sha }} + path: .output/*-chrome.zip + if-no-files-found: error + - name: Verify Chrome Web Store credentials + if: ${{ inputs.dry_run }} + run: pnpm run submit -- --dry-run --chrome-zip .output/*-chrome.zip + env: + CHROME_API_VERSION: v2 + CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }} + CHROME_PUBLISHER_ID: ${{ secrets.CHROME_PUBLISHER_ID }} + CHROME_SERVICE_ACCOUNT_CLIENT_EMAIL: ${{ secrets.CHROME_SERVICE_ACCOUNT_CLIENT_EMAIL }} + CHROME_SERVICE_ACCOUNT_PRIVATE_KEY: ${{ secrets.CHROME_SERVICE_ACCOUNT_PRIVATE_KEY }} + - name: Submit update for review + if: ${{ !inputs.dry_run && github.ref == 'refs/heads/master' }} + run: pnpm run submit -- --chrome-zip .output/*-chrome.zip + env: + CHROME_API_VERSION: v2 + CHROME_EXTENSION_ID: ${{ secrets.CHROME_EXTENSION_ID }} + CHROME_PUBLISHER_ID: ${{ secrets.CHROME_PUBLISHER_ID }} + CHROME_SERVICE_ACCOUNT_CLIENT_EMAIL: ${{ secrets.CHROME_SERVICE_ACCOUNT_CLIENT_EMAIL }} + CHROME_SERVICE_ACCOUNT_PRIVATE_KEY: ${{ secrets.CHROME_SERVICE_ACCOUNT_PRIVATE_KEY }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..b5f307c --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,25 @@ +name: Verify extension + +on: + push: + branches: [master] + pull_request: + branches: [master] + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm run compile + - run: pnpm run lint + - run: pnpm run test:unit + - run: pnpm run build + - run: pnpm exec playwright install --with-deps chromium + - run: pnpm run test:e2e diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3fe97a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Config files +.webextrc +.webextrc.* + +.vite/ +.output/ +.wxt/ +OLD/ +playwright-report/ +test-results/ diff --git a/README.md b/README.md index d207d5b..0bb680e 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,53 @@ - -## LiuChan Chinese Popup Dictionary -LiuChan (*liú chàng*) is an extension for chrome that allows you to mouse-over Chinese to instantly lookup the dictionary. + -It started out as a port of RikaiChan (and its Rikai derivatives) and has since grown into an extension that has been completely rewritten with greatly improved performance and new features. +# LiuChan Chinese Popup Dictionary -### Current Features +LiuChan (_liú chàng_, 流畅) is a Chrome extension that looks up Chinese text as you move the pointer over it. Version 2 is a Manifest V3 rewrite with Mandarin and Cantonese support. -* Instantaneous translation of Chinese characters and words on mouse over -* Synchronized settings across all your devices -* Text input support -* A handy little notepad that you can open on any page :) -* Theme support -* Fuzzy search! Use chrome's omnibox to search the dictionary using hanzi, pinyin or just plain english -* Dictionaries automatically update to newer versions +## Features -### Usage +- Fast mouse-over lookup on page text, inputs, and textareas +- Simplified and traditional Hanzi +- CC-CEDICT Mandarin definitions with Pinyin, tone numbers, or Zhuyin +- CC-Canto definitions and supplemental Jyutping readings +- Mandarin, Cantonese, or combined dictionary display +- Synchronized display settings, themes, and custom colors +- Text highlighting, speech, clipboard export, and navigation hotkeys +- User-triggered dictionary updates without reinstalling the extension -**Mouse Over Dictionary:** Simply enable the extension and mouse over Chinese on a page! +Click the toolbar icon to enable or disable LiuChan. The options page documents the available popup hotkeys. -**Fuzzy search:** Type 'lc' in the omnibox followed by whatever term you want to look for (Chinese, pinyin or English), the results will show up as suggestions. +## Dictionary updates -### To Do +The extension includes an offline dictionary. In **Settings → Dictionary data**, click **Check for updates** to download the latest CC-CEDICT editor export and the latest published CC-Canto data. Downloads happen only after this button is clicked. New data is validated before it replaces the active dictionary; **Restore bundled data** always returns to the release snapshot. -- [ ] Add Cantonese dictionary -- [ ] Add word lists/Anki support -- [ ] Move fuzzy search to its own input box as opposed to omnibox so that it can be expanded upon (eg. use rich formatting, etc) +Dictionary files are data only. LiuChan does not download or execute remote code. -### Why is it called LiuChan? +## Development -流畅 (*liú chàng*) stands for fluency in a language. I kept -Chan as an homage to its origin. +Requirements: Node.js 22 and pnpm 10.11.0. -### Troubleshooting +```sh +pnpm install --frozen-lockfile +pnpm run compile +pnpm run lint +pnpm run test:unit +pnpm run build +pnpm exec playwright install chromium +pnpm run test:e2e +pnpm run zip +``` -If anything malfunctions, your best bet is disabling and re-enabling the extension and reloading the page you want it to work on. +Load `.output/chrome-mv3` as an unpacked extension for local testing. The Chrome Store zip is written to `.output/`. -In case a problem persists please open an issue on github and try to describe as clearly as possible how to recreate the problem. +## Data sources and licenses -#### Known issues: +- [CC-CEDICT](https://cc-cedict.org/) — community-maintained Mandarin dictionary published by MDBG, Creative Commons Attribution-ShareAlike 4.0. +- [CC-Canto](https://cccanto.org/download.html) — Cantonese dictionary, copyright Pleco Inc., Creative Commons Attribution-ShareAlike 3.0. +- CC-CEDICT Cantonese Readings — supplemental readings from the CC-Canto download, copyright Pleco Software Incorporated, Creative Commons Attribution-ShareAlike 3.0. -Currently fuzzy search isn't 'fuzzy' enough to match regular vowels with tonemarked ones. +LiuChan source code is licensed under GPL-3.0. + +## Troubleshooting + +Chrome cannot inject extensions into internal pages such as `chrome://` or into tabs that have not been reloaded since an extension update. Reload the affected page and try again. If a dictionary update fails, the previously working data remains active. diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000..acd2ec2 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,41 @@ +# Chrome Web Store release + +## Repository setup + +Create a protected GitHub environment named `chrome-web-store`, then add these repository or environment secrets: + +- `CHROME_EXTENSION_ID` +- `CHROME_PUBLISHER_ID` +- `CHROME_SERVICE_ACCOUNT_CLIENT_EMAIL` +- `CHROME_SERVICE_ACCOUNT_PRIVATE_KEY` + +The workflow uses Chrome Web Store API v2 with a service account, so it does +not need a user OAuth client or refresh token: + +1. Enable the Chrome Web Store API in a Google Cloud project. +2. Create a service account; it does not need a Google Cloud role for this API. +3. Create a JSON key for it. Store its `client_email` and `private_key` values + in the corresponding GitHub secrets above. Never commit the JSON key. +4. In the Chrome Web Store Developer Dashboard, open **Account** and add the + service account email. Chrome currently permits one service account per + publisher. +5. Copy the publisher ID from **Publisher > Settings** into + `CHROME_PUBLISHER_ID`. + +Follow the official [service-account setup](https://developer.chrome.com/docs/webstore/service-accounts) and enable two-step verification on the human developer account. The previously configured `CHROME_CLIENT_ID` and `CHROME_CLIENT_SECRET` are only used by the deprecated v1.1 API and can be removed from GitHub after the v2 dry run succeeds. + +## Before submitting + +1. Confirm `package.json` has a version greater than the currently published version. +2. Run the complete local verification sequence from the README. +3. Review the generated `.output/chrome-mv3/manifest.json` and zip contents. +4. Update the Store listing so it advertises only the features in the current README. +5. In Privacy practices, disclose that page text is processed locally for lookup and is not collected or transmitted. Dictionary update requests contact `cc-cedict.org` and `cccanto.org` only after a user clicks the update button. +6. Refresh screenshots to show the MV3 popup, Mandarin/Cantonese modes, and options page. +7. Keep the dictionary source and license attribution from the README/options page in the Store description. + +## Workflow + +Run **Release to Chrome Web Store** from the Actions tab with `dry_run` enabled first. This validates authentication without uploading. After it succeeds, run it from `master` with `dry_run` disabled. The workflow builds a fresh zip, retains it as an artifact, uploads it to the existing listing, and submits it for review. + +If automated submission is unavailable, download the workflow artifact and use **Upload New Package** in the Chrome Developer Dashboard. diff --git a/testing/DictTest.html b/assets/index.html similarity index 89% rename from testing/DictTest.html rename to assets/index.html index 9750519..c75c0f8 100644 --- a/testing/DictTest.html +++ b/assets/index.html @@ -5,16 +5,25 @@
一部二十四史,不知從何說起 + 一顆老鼠屎壞了一鍋湯 + 丈二金
剛摸不著頭腦
+ 三個臭皮匠,勝過一個諸葛亮 + + -