From 3e693a1fbf1556b4b5979bb0ea69202431753f01 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Fri, 26 Dec 2025 20:37:02 +0800 Subject: [PATCH 01/14] =?UTF-8?q?=E5=AE=9E=E7=8E=B0Grid=20View=20=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=E8=A7=86=E9=87=8E=E4=BD=8D=E7=BD=AE=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/home/folder/GridItem.tsx | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/pages/home/folder/GridItem.tsx b/src/pages/home/folder/GridItem.tsx index abaa550e8..ac5607716 100644 --- a/src/pages/home/folder/GridItem.tsx +++ b/src/pages/home/folder/GridItem.tsx @@ -1,7 +1,7 @@ import { Center, VStack, Icon, Text } from "@hope-ui/solid" import { Motion } from "solid-motionone" import { useContextMenu } from "solid-contextmenu" -import { batch, Show } from "solid-js" +import { batch, Show, createSignal, onMount, onCleanup } from "solid-js" import { CenterLoading, LinkWithPush, ImageWithError } from "~/components" import { usePath, useRouter, useUtil } from "~/hooks" import { checkboxOpen, getMainColor, local, selectIndex } from "~/store" @@ -27,8 +27,25 @@ export const GridItem = (props: { obj: StoreObj; index: number }) => { const { pushHref, to } = useRouter() const { openWithDoubleClick, toggleWithClick, restoreSelectionCache } = useSelectWithMouse() + + const [isVisible, setIsVisible] = createSignal(false) + let ref: HTMLDivElement | undefined + + onMount(() => { + if (ref) { + const observer = new IntersectionObserver( + ([entry]) => { + setIsVisible(entry.isIntersecting) + }, + { rootMargin: "50px" }, + ) + observer.observe(ref) + onCleanup(() => observer.disconnect()) + } + }) return ( { }} /> - + Date: Fri, 26 Dec 2025 20:53:13 +0800 Subject: [PATCH 02/14] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E7=9A=84=E6=97=B6=E5=80=99=E5=BB=B6=E8=BF=9F?= =?UTF-8?q?500ms=20=20=E9=98=B2=E6=AD=A2=E5=BF=AB=E9=80=9F=E5=88=92?= =?UTF-8?q?=E8=BF=87=E4=B8=8D=E5=85=B3=E6=B3=A8=E7=9A=84=E5=9C=B0=E6=96=B9?= =?UTF-8?q?=E4=B9=9F=E5=9C=A8=E5=8A=A0=E8=BD=BD=E9=98=BB=E5=A1=9E=E6=BB=91?= =?UTF-8?q?=E5=88=B0=E7=9A=84=E5=9C=B0=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ImageWithError.tsx | 2 ++ src/pages/home/folder/GridItem.tsx | 20 ++++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/components/ImageWithError.tsx b/src/components/ImageWithError.tsx index a5b91675e..3619b3786 100644 --- a/src/components/ImageWithError.tsx +++ b/src/components/ImageWithError.tsx @@ -4,6 +4,7 @@ import { createSignal, JSXElement, Show } from "solid-js" export const ImageWithError = ( props: ImageProps & { fallbackErr?: JSXElement + onLoad?: () => void }, ) => { const [err, setErr] = createSignal(false) @@ -11,6 +12,7 @@ export const ImageWithError = ( { setErr(true) }} diff --git a/src/pages/home/folder/GridItem.tsx b/src/pages/home/folder/GridItem.tsx index ac5607716..aa0eb61b7 100644 --- a/src/pages/home/folder/GridItem.tsx +++ b/src/pages/home/folder/GridItem.tsx @@ -29,18 +29,30 @@ export const GridItem = (props: { obj: StoreObj; index: number }) => { useSelectWithMouse() const [isVisible, setIsVisible] = createSignal(false) + const [loaded, setLoaded] = createSignal(false) + const [canLoad, setCanLoad] = createSignal(false) let ref: HTMLDivElement | undefined + let loadTimeout: number | undefined onMount(() => { if (ref) { const observer = new IntersectionObserver( ([entry]) => { + if (entry.isIntersecting) { + loadTimeout = setTimeout(() => setCanLoad(true), 500) + } else { + if (loadTimeout) clearTimeout(loadTimeout) + setCanLoad(false) + } setIsVisible(entry.isIntersecting) }, { rootMargin: "50px" }, ) observer.observe(ref) - onCleanup(() => observer.disconnect()) + onCleanup(() => { + observer.disconnect() + if (loadTimeout) clearTimeout(loadTimeout) + }) } }) return ( @@ -132,7 +144,10 @@ export const GridItem = (props: { obj: StoreObj; index: number }) => { }} /> - + { fallbackErr={objIcon} src={props.obj.thumb} loading="lazy" + onLoad={() => setLoaded(true)} /> From 227b99f1de1e8c5229f44b4346b20dc92466ac84 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sat, 4 Apr 2026 23:36:51 +0800 Subject: [PATCH 03/14] remove build crowdin --- .github/workflows/build_release.yml | 6 ---- .github/workflows/build_rolling.yml | 3 -- .github/workflows/i18n_sync.yml | 7 ---- build.sh | 9 +---- package.json | 5 --- src/app/i18n.ts | 51 ++++++++++------------------- 6 files changed, 19 insertions(+), 62 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index b48c08e57..745b8ac02 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -128,9 +128,6 @@ jobs: run: | chmod +x build.sh ./build.sh --release --compress - env: - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - name: Move regular build run: | @@ -141,9 +138,6 @@ jobs: run: | chmod +x build.sh ./build.sh --release --compress --lite - env: - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - name: Move lite build and restore regular build run: | diff --git a/.github/workflows/build_rolling.yml b/.github/workflows/build_rolling.yml index 3c55f866a..6ce89f345 100644 --- a/.github/workflows/build_rolling.yml +++ b/.github/workflows/build_rolling.yml @@ -47,9 +47,6 @@ jobs: run: | chmod +x build.sh ./build.sh --dev --compress - env: - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - name: Read version and determine tag name id: version diff --git a/.github/workflows/i18n_sync.yml b/.github/workflows/i18n_sync.yml index 1fb126258..cf4f0f426 100644 --- a/.github/workflows/i18n_sync.yml +++ b/.github/workflows/i18n_sync.yml @@ -83,12 +83,5 @@ jobs: git push fi - - name: Sync to Crowdin - if: ${{ steps.verify-changed-files.outputs.changed == 'true' || github.event_name == 'push' }} - uses: ./.github/actions/sync_to_crowdin - with: - crowdin_project_id: ${{ secrets.CROWDIN_PROJECT_ID }} - crowdin_personal_token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - permissions: contents: write diff --git a/build.sh b/build.sh index a77ecc998..fbadd1c25 100755 --- a/build.sh +++ b/build.sh @@ -146,14 +146,7 @@ build_project() { log_step "==== Installing dependencies ====" pnpm install - log_step "==== Building i18n ====" - if [[ "$SKIP_I18N" == "false" ]]; then - pnpm i18n:release - else - fetch_i18n_from_release - fi - - log_step "==== Building project ====" + log_step "==== Building project (English only, no crowdin) ====" if [[ "$LITE_FLAG" == "true" ]]; then pnpm build:lite else diff --git a/package.json b/package.json index 0c9e0b89c..4688a95ff 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,6 @@ ], "homepage": "https://openlist.team/", "scripts": { - "crowdin:upload": "crowdin upload sources --auto-update", - "crowdin:download": "crowdin download --verbose", - "crowdin": "pnpm crowdin:upload && pnpm crowdin:download", - "i18n:build": "pnpm crowdin && node ./scripts/i18n.mjs", - "i18n:release": "pnpm run crowdin:download && node ./scripts/i18n.mjs", "start": "vite", "dev": "vite --force", "build": "vite build", diff --git a/src/app/i18n.ts b/src/app/i18n.ts index 21fb518e4..d8af7912d 100644 --- a/src/app/i18n.ts +++ b/src/app/i18n.ts @@ -2,51 +2,36 @@ import * as i18n from "@solid-primitives/i18n" import { createResource, createSignal } from "solid-js" export { i18n } -// glob search by Vite -const langs = import.meta.glob("~/lang/*/index.json", { - eager: true, - import: "lang", -}) - -// all available languages -export const languages = Object.keys(langs).map((langPath) => { - const langCode = langPath.split("/")[3] - const langName = langs[langPath] as string - return { code: langCode, lang: langName } -}) - -// determine browser's default language -const userLang = navigator.language.toLowerCase() -const defaultLang = - languages.find((lang) => lang.code.toLowerCase() === userLang)?.code || - languages.find( - (lang) => lang.code.toLowerCase().split("-")[0] === userLang.split("-")[0], - )?.code || - "en" - -// Get initial language from localStorage or fallback to defaultLang -export let initialLang = localStorage.getItem("lang") ?? defaultLang - -if (!languages.some((lang) => lang.code === initialLang)) { - initialLang = defaultLang +// Only use English as the default language (no crowdin, single language mode) +const langs = { + "~/lang/en/index.json": "English", } +// all available languages (only English) +export const languages = [{ code: "en", lang: "English" }] + +// Always use English as the default language +const defaultLang = "en" + +// Get initial language - always English +export let initialLang = "en" + // Type imports // use `type` to not include the actual dictionary in the bundle import type * as en from "~/lang/en/entry" -export type Lang = keyof typeof langs +export type Lang = "en" export type RawDictionary = typeof en.dict export type Dictionary = i18n.Flatten -// Fetch and flatten the dictionary -const fetchDictionary = async (locale: Lang): Promise => { +// Fetch and flatten the dictionary (only English) +const fetchDictionary = async (_locale: Lang): Promise => { try { - const dict: RawDictionary = (await import(`~/lang/${locale}/entry.ts`)).dict + const dict: RawDictionary = (await import(`~/lang/en/entry.ts`)).dict return i18n.flatten(dict) // Flatten dictionary for easier access to keys } catch (err) { - console.error(`Error loading dictionary for locale: ${locale}`, err) - throw new Error(`Failed to load dictionary for ${locale}`) + console.error(`Error loading dictionary for locale: English`, err) + throw new Error(`Failed to load dictionary for English`) } } From 50dfcb458655c6e482534ff6859bff7c73b5b28c Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sat, 4 Apr 2026 23:40:14 +0800 Subject: [PATCH 04/14] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=89=8B=E5=8A=A8?= =?UTF-8?q?=E8=A7=A6=E5=8F=91release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 745b8ac02..73df24a68 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -27,7 +27,22 @@ on: version: description: | Target version (e.g., 1.0.0), will create a tag named 'v' and update package.json version - required: true + required: false + default: "1.0.0" + type: string + prerelease: + description: "Create pre-release (beta/alpha)" + required: false + default: false + type: boolean + draft: + description: "Create draft release" + required: false + default: true + type: boolean + release_notes: + description: "Custom release notes (supports Markdown)" + required: false type: string jobs: From 5af83f8f244b58b2d6cfc1bfc4309b595ad90b41 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sat, 4 Apr 2026 23:48:17 +0800 Subject: [PATCH 05/14] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E7=9A=84release=20=E7=9A=84=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 176 ++-------------------------- 1 file changed, 12 insertions(+), 164 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 73df24a68..278a82693 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -1,21 +1,3 @@ -# This workflow is used to create a (pre-)release build of the OpenList frontend. -# -# This will: -# -# - Update the `package.json` version to the specified version (when triggered -# by `workflow_dispatch`), commit the changes and tag it. -# - Upload the release assets to GitHub. -# - Publish the package to npm. -# -# # Usage -# -# This workflow can be triggered by: -# -# - Pushing a tag that matches the pattern `v[0-9]+.[0-9]+.[0-9]+*` (semver format). -# - Manually via the GitHub Actions UI with a version input. -# -# To create (pre-)release builds, we recommend that you use the `workflow_dispatch`. - name: Release Build on: @@ -25,25 +7,10 @@ on: workflow_dispatch: inputs: version: - description: | - Target version (e.g., 1.0.0), will create a tag named 'v' and update package.json version + description: "Target version (e.g., 1.0.0)" required: false default: "1.0.0" type: string - prerelease: - description: "Create pre-release (beta/alpha)" - required: false - default: false - type: boolean - draft: - description: "Create draft release" - required: false - default: true - type: boolean - release_notes: - description: "Custom release notes (supports Markdown)" - required: false - type: string jobs: release: @@ -52,154 +19,35 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v6 - with: - fetch-depth: 0 - submodules: recursive - - - name: Validate and trim semver - id: semver - uses: matt-usurp/validate-semver@v2 - with: - version: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }} - - - name: Check if version is pre-release - id: check_pre_release - run: | - if [[ -z "${{ steps.semver.outputs.prerelease }}" && -z "${{ steps.semver.outputs.build }}" ]]; then - echo "is_pre_release=false" >> $GITHUB_OUTPUT - else - echo "is_pre_release=true" >> $GITHUB_OUTPUT - fi - name: Setup Node uses: actions/setup-node@v6 with: node-version: "24.14.1" - registry-url: "https://registry.npmjs.org" - name: Install pnpm uses: pnpm/action-setup@v5 - with: - run_install: false - - - name: Import GPG key - if: github.event_name == 'workflow_dispatch' - uses: crazy-max/ghaction-import-gpg@v7 - with: - gpg_private_key: ${{ secrets.BOT_GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }} - git_user_signingkey: true - git_commit_gpgsign: true - git_tag_gpgsign: true - - - name: Setup CI Bot - if: github.event_name == 'workflow_dispatch' - run: | - git config user.name "${{ secrets.BOT_USERNAME }}" - git config user.email "${{ secrets.BOT_USEREMAIL }}" - - - name: Update package.json and commit - if: github.event_name == 'workflow_dispatch' - run: | - jq --arg version "${{ steps.semver.outputs.version }}" '.version = $version' package.json > package.json.tmp && mv package.json.tmp package.json - git add package.json - git commit -S -m "chore: release v${{ steps.semver.outputs.version }}" --no-verify - git push - - # For local build, needn't push, the tag will be created by `gh release create` - git tag -s "v${{ steps.semver.outputs.version }}" -m "Release v${{ steps.semver.outputs.version }}" - - - name: Get current tag - id: get_current_tag - run: | - # Remove existing tag `rolling`, since `rolling` should always point to the latest commit - # This is necessary to avoid conflicts with the changelog generation - git tag -d rolling 2>/dev/null || true - - # Get the current tag - CURRENT_TAG=$(git describe --tags --abbrev=0) - echo "current_tag=$CURRENT_TAG" >> $GITHUB_OUTPUT - - # Temporarily remove all pre-release tags (tags containing '-' / '+') - # This prevents them from interfering with changelog generation - PRE_RELEASE_TAGS=$(git tag -l | grep -E "(-|\+)" || true) - if [ -n "$PRE_RELEASE_TAGS" ]; then - echo "Temporarily removing pre-release tags: $PRE_RELEASE_TAGS" - echo "$PRE_RELEASE_TAGS" | xargs -r git tag -d - fi - - # Add back the current tag if is a pre-release - # Should not add `-f`, as it will overwrite the existing tag - if [[ "${{ steps.check_pre_release.outputs.is_pre_release }}" == "true" ]]; then - git tag -s "$CURRENT_TAG" -m "Release $CURRENT_TAG" - fi - - - name: Generate changelog - id: generate_changelog - run: | - npx changelogithub --output ${{ github.workspace }}-CHANGELOG.txt || echo "" > ${{ github.workspace }}-CHANGELOG.txt - name: Build Release run: | chmod +x build.sh ./build.sh --release --compress - - name: Move regular build - run: | - mkdir -p regular-dist - mv dist/* regular-dist/ - - - name: Build Lite Release - run: | - chmod +x build.sh - ./build.sh --release --compress --lite - - - name: Move lite build and restore regular build + - name: Download i18n.tar.gz from latest release run: | - mkdir -p lite-dist - mv dist/* lite-dist/ - mv regular-dist/* dist/ + LATEST_RELEASE=$(gh release list --limit 1 --json tagName | jq -r '.[0].tagName') + echo "Downloading i18n.tar.gz from release: $LATEST_RELEASE" + gh release download "$LATEST_RELEASE" --pattern "i18n.tar.gz" --dir dist/ || echo "i18n.tar.gz not found in latest release" + ls -la dist/i18n.tar.gz 2>/dev/null || echo "No i18n.tar.gz downloaded" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Release Assets run: | - # Delete local tag, or gh cli will complain about it. - git tag -d ${{ steps.get_current_tag.outputs.current_tag }} gh release create \ - --title "Release ${{ steps.get_current_tag.outputs.current_tag }}" \ - --notes-file "${{ github.workspace }}-CHANGELOG.txt" \ - --prerelease=${{ steps.check_pre_release.outputs.is_pre_release }} \ - ${{ steps.get_current_tag.outputs.current_tag }} \ - dist/openlist-frontend-dist-v*.tar.gz lite-dist/openlist-frontend-dist-lite-v*.tar.gz dist/i18n.tar.gz + --title "Release ${{ github.ref_name }}" \ + ${{ github.ref_name }} \ + dist/openlist-frontend-dist-v*.tar.gz \ + dist/i18n.tar.gz env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Prepare for npm - run: | - # Delete the generated dist tarball - rm -f dist/openlist-frontend-dist-v*.tar.gz - rm -f lite-dist/openlist-frontend-dist-lite-v*.tar.gz - # Copy the lite version - mkdir dist/lite - cp -r lite-dist/. dist/lite/ - - if ! jq -e '.name and .version' package.json > /dev/null; then - echo "Error: Invalid package.json" - exit 1 - fi - - - name: Publish npm - run: | - echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc - - if [ -z "${{ secrets.NPM_TOKEN }}" ]; then - echo "NPM_TOKEN not set, performing dry run" - pnpm publish --dry-run --no-git-checks --access public - else - echo "Publishing to npm..." - pnpm publish --no-git-checks --access public - fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - -permissions: - contents: write From f53d87b1dc6718959786bf390dbd6f34ef166609 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sat, 4 Apr 2026 23:52:04 +0800 Subject: [PATCH 06/14] =?UTF-8?q?chore:=20=E7=AE=80=E5=8C=96=20release=20?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=EF=BC=8C=E7=A6=81=E7=94=A8=20crowdin?= =?UTF-8?q?=EF=BC=8C=E5=8F=AA=E4=BD=BF=E7=94=A8=E8=8B=B1=E8=AF=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 169 +++------------------------- .github/workflows/build_rolling.yml | 3 - .github/workflows/i18n_sync.yml | 7 -- build.sh | 14 +-- package.json | 5 - src/app/i18n.ts | 51 +++------ 6 files changed, 34 insertions(+), 215 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index b48c08e57..278a82693 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -1,21 +1,3 @@ -# This workflow is used to create a (pre-)release build of the OpenList frontend. -# -# This will: -# -# - Update the `package.json` version to the specified version (when triggered -# by `workflow_dispatch`), commit the changes and tag it. -# - Upload the release assets to GitHub. -# - Publish the package to npm. -# -# # Usage -# -# This workflow can be triggered by: -# -# - Pushing a tag that matches the pattern `v[0-9]+.[0-9]+.[0-9]+*` (semver format). -# - Manually via the GitHub Actions UI with a version input. -# -# To create (pre-)release builds, we recommend that you use the `workflow_dispatch`. - name: Release Build on: @@ -25,9 +7,9 @@ on: workflow_dispatch: inputs: version: - description: | - Target version (e.g., 1.0.0), will create a tag named 'v' and update package.json version - required: true + description: "Target version (e.g., 1.0.0)" + required: false + default: "1.0.0" type: string jobs: @@ -37,160 +19,35 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v6 - with: - fetch-depth: 0 - submodules: recursive - - - name: Validate and trim semver - id: semver - uses: matt-usurp/validate-semver@v2 - with: - version: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }} - - - name: Check if version is pre-release - id: check_pre_release - run: | - if [[ -z "${{ steps.semver.outputs.prerelease }}" && -z "${{ steps.semver.outputs.build }}" ]]; then - echo "is_pre_release=false" >> $GITHUB_OUTPUT - else - echo "is_pre_release=true" >> $GITHUB_OUTPUT - fi - name: Setup Node uses: actions/setup-node@v6 with: node-version: "24.14.1" - registry-url: "https://registry.npmjs.org" - name: Install pnpm uses: pnpm/action-setup@v5 - with: - run_install: false - - - name: Import GPG key - if: github.event_name == 'workflow_dispatch' - uses: crazy-max/ghaction-import-gpg@v7 - with: - gpg_private_key: ${{ secrets.BOT_GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.BOT_GPG_PASSPHRASE }} - git_user_signingkey: true - git_commit_gpgsign: true - git_tag_gpgsign: true - - - name: Setup CI Bot - if: github.event_name == 'workflow_dispatch' - run: | - git config user.name "${{ secrets.BOT_USERNAME }}" - git config user.email "${{ secrets.BOT_USEREMAIL }}" - - - name: Update package.json and commit - if: github.event_name == 'workflow_dispatch' - run: | - jq --arg version "${{ steps.semver.outputs.version }}" '.version = $version' package.json > package.json.tmp && mv package.json.tmp package.json - git add package.json - git commit -S -m "chore: release v${{ steps.semver.outputs.version }}" --no-verify - git push - - # For local build, needn't push, the tag will be created by `gh release create` - git tag -s "v${{ steps.semver.outputs.version }}" -m "Release v${{ steps.semver.outputs.version }}" - - - name: Get current tag - id: get_current_tag - run: | - # Remove existing tag `rolling`, since `rolling` should always point to the latest commit - # This is necessary to avoid conflicts with the changelog generation - git tag -d rolling 2>/dev/null || true - - # Get the current tag - CURRENT_TAG=$(git describe --tags --abbrev=0) - echo "current_tag=$CURRENT_TAG" >> $GITHUB_OUTPUT - - # Temporarily remove all pre-release tags (tags containing '-' / '+') - # This prevents them from interfering with changelog generation - PRE_RELEASE_TAGS=$(git tag -l | grep -E "(-|\+)" || true) - if [ -n "$PRE_RELEASE_TAGS" ]; then - echo "Temporarily removing pre-release tags: $PRE_RELEASE_TAGS" - echo "$PRE_RELEASE_TAGS" | xargs -r git tag -d - fi - - # Add back the current tag if is a pre-release - # Should not add `-f`, as it will overwrite the existing tag - if [[ "${{ steps.check_pre_release.outputs.is_pre_release }}" == "true" ]]; then - git tag -s "$CURRENT_TAG" -m "Release $CURRENT_TAG" - fi - - - name: Generate changelog - id: generate_changelog - run: | - npx changelogithub --output ${{ github.workspace }}-CHANGELOG.txt || echo "" > ${{ github.workspace }}-CHANGELOG.txt - name: Build Release run: | chmod +x build.sh ./build.sh --release --compress - env: - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - - name: Move regular build + - name: Download i18n.tar.gz from latest release run: | - mkdir -p regular-dist - mv dist/* regular-dist/ - - - name: Build Lite Release - run: | - chmod +x build.sh - ./build.sh --release --compress --lite + LATEST_RELEASE=$(gh release list --limit 1 --json tagName | jq -r '.[0].tagName') + echo "Downloading i18n.tar.gz from release: $LATEST_RELEASE" + gh release download "$LATEST_RELEASE" --pattern "i18n.tar.gz" --dir dist/ || echo "i18n.tar.gz not found in latest release" + ls -la dist/i18n.tar.gz 2>/dev/null || echo "No i18n.tar.gz downloaded" env: - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - - - name: Move lite build and restore regular build - run: | - mkdir -p lite-dist - mv dist/* lite-dist/ - mv regular-dist/* dist/ + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Release Assets run: | - # Delete local tag, or gh cli will complain about it. - git tag -d ${{ steps.get_current_tag.outputs.current_tag }} gh release create \ - --title "Release ${{ steps.get_current_tag.outputs.current_tag }}" \ - --notes-file "${{ github.workspace }}-CHANGELOG.txt" \ - --prerelease=${{ steps.check_pre_release.outputs.is_pre_release }} \ - ${{ steps.get_current_tag.outputs.current_tag }} \ - dist/openlist-frontend-dist-v*.tar.gz lite-dist/openlist-frontend-dist-lite-v*.tar.gz dist/i18n.tar.gz + --title "Release ${{ github.ref_name }}" \ + ${{ github.ref_name }} \ + dist/openlist-frontend-dist-v*.tar.gz \ + dist/i18n.tar.gz env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Prepare for npm - run: | - # Delete the generated dist tarball - rm -f dist/openlist-frontend-dist-v*.tar.gz - rm -f lite-dist/openlist-frontend-dist-lite-v*.tar.gz - # Copy the lite version - mkdir dist/lite - cp -r lite-dist/. dist/lite/ - - if ! jq -e '.name and .version' package.json > /dev/null; then - echo "Error: Invalid package.json" - exit 1 - fi - - - name: Publish npm - run: | - echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" > ~/.npmrc - - if [ -z "${{ secrets.NPM_TOKEN }}" ]; then - echo "NPM_TOKEN not set, performing dry run" - pnpm publish --dry-run --no-git-checks --access public - else - echo "Publishing to npm..." - pnpm publish --no-git-checks --access public - fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - -permissions: - contents: write diff --git a/.github/workflows/build_rolling.yml b/.github/workflows/build_rolling.yml index 3c55f866a..6ce89f345 100644 --- a/.github/workflows/build_rolling.yml +++ b/.github/workflows/build_rolling.yml @@ -47,9 +47,6 @@ jobs: run: | chmod +x build.sh ./build.sh --dev --compress - env: - CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} - CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - name: Read version and determine tag name id: version diff --git a/.github/workflows/i18n_sync.yml b/.github/workflows/i18n_sync.yml index 1fb126258..cf4f0f426 100644 --- a/.github/workflows/i18n_sync.yml +++ b/.github/workflows/i18n_sync.yml @@ -83,12 +83,5 @@ jobs: git push fi - - name: Sync to Crowdin - if: ${{ steps.verify-changed-files.outputs.changed == 'true' || github.event_name == 'push' }} - uses: ./.github/actions/sync_to_crowdin - with: - crowdin_project_id: ${{ secrets.CROWDIN_PROJECT_ID }} - crowdin_personal_token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} - permissions: contents: write diff --git a/build.sh b/build.sh index a77ecc998..01801fb3f 100755 --- a/build.sh +++ b/build.sh @@ -95,9 +95,8 @@ check_git_version_and_commit() { # Enforce git tag for release builds enforce_git_tag() { if ! git_version=$(git describe --abbrev=0 --tags 2>/dev/null); then - log_error "No git tags found. Release build requires a git tag." - log_warning "Please create a tag first, or use --dev for development builds." - exit 1 + log_warning "No git tags found. Using version from package.json." + git_version="v$(grep '"version":' package.json | sed 's/.*"version": *"\([^"]*\)".*/\1/')" fi validate_git_tag } @@ -146,14 +145,7 @@ build_project() { log_step "==== Installing dependencies ====" pnpm install - log_step "==== Building i18n ====" - if [[ "$SKIP_I18N" == "false" ]]; then - pnpm i18n:release - else - fetch_i18n_from_release - fi - - log_step "==== Building project ====" + log_step "==== Building project (English only, no crowdin) ====" if [[ "$LITE_FLAG" == "true" ]]; then pnpm build:lite else diff --git a/package.json b/package.json index 0c9e0b89c..4688a95ff 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,6 @@ ], "homepage": "https://openlist.team/", "scripts": { - "crowdin:upload": "crowdin upload sources --auto-update", - "crowdin:download": "crowdin download --verbose", - "crowdin": "pnpm crowdin:upload && pnpm crowdin:download", - "i18n:build": "pnpm crowdin && node ./scripts/i18n.mjs", - "i18n:release": "pnpm run crowdin:download && node ./scripts/i18n.mjs", "start": "vite", "dev": "vite --force", "build": "vite build", diff --git a/src/app/i18n.ts b/src/app/i18n.ts index 21fb518e4..d8af7912d 100644 --- a/src/app/i18n.ts +++ b/src/app/i18n.ts @@ -2,51 +2,36 @@ import * as i18n from "@solid-primitives/i18n" import { createResource, createSignal } from "solid-js" export { i18n } -// glob search by Vite -const langs = import.meta.glob("~/lang/*/index.json", { - eager: true, - import: "lang", -}) - -// all available languages -export const languages = Object.keys(langs).map((langPath) => { - const langCode = langPath.split("/")[3] - const langName = langs[langPath] as string - return { code: langCode, lang: langName } -}) - -// determine browser's default language -const userLang = navigator.language.toLowerCase() -const defaultLang = - languages.find((lang) => lang.code.toLowerCase() === userLang)?.code || - languages.find( - (lang) => lang.code.toLowerCase().split("-")[0] === userLang.split("-")[0], - )?.code || - "en" - -// Get initial language from localStorage or fallback to defaultLang -export let initialLang = localStorage.getItem("lang") ?? defaultLang - -if (!languages.some((lang) => lang.code === initialLang)) { - initialLang = defaultLang +// Only use English as the default language (no crowdin, single language mode) +const langs = { + "~/lang/en/index.json": "English", } +// all available languages (only English) +export const languages = [{ code: "en", lang: "English" }] + +// Always use English as the default language +const defaultLang = "en" + +// Get initial language - always English +export let initialLang = "en" + // Type imports // use `type` to not include the actual dictionary in the bundle import type * as en from "~/lang/en/entry" -export type Lang = keyof typeof langs +export type Lang = "en" export type RawDictionary = typeof en.dict export type Dictionary = i18n.Flatten -// Fetch and flatten the dictionary -const fetchDictionary = async (locale: Lang): Promise => { +// Fetch and flatten the dictionary (only English) +const fetchDictionary = async (_locale: Lang): Promise => { try { - const dict: RawDictionary = (await import(`~/lang/${locale}/entry.ts`)).dict + const dict: RawDictionary = (await import(`~/lang/en/entry.ts`)).dict return i18n.flatten(dict) // Flatten dictionary for easier access to keys } catch (err) { - console.error(`Error loading dictionary for locale: ${locale}`, err) - throw new Error(`Failed to load dictionary for ${locale}`) + console.error(`Error loading dictionary for locale: English`, err) + throw new Error(`Failed to load dictionary for English`) } } From 335db8c24109292389794b842e40adabf3aed971 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sat, 4 Apr 2026 23:59:09 +0800 Subject: [PATCH 07/14] =?UTF-8?q?chore:=20=E4=BD=BF=E7=94=A8=20curl=20?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E4=B8=8B=E8=BD=BD=20i18n.tar.gz?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 278a82693..29d441bf1 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -35,12 +35,9 @@ jobs: - name: Download i18n.tar.gz from latest release run: | - LATEST_RELEASE=$(gh release list --limit 1 --json tagName | jq -r '.[0].tagName') - echo "Downloading i18n.tar.gz from release: $LATEST_RELEASE" - gh release download "$LATEST_RELEASE" --pattern "i18n.tar.gz" --dir dist/ || echo "i18n.tar.gz not found in latest release" + echo "Downloading i18n.tar.gz from latest release..." + curl -L -o dist/i18n.tar.gz "https://github.com/OpenListTeam/OpenList-Frontend/releases/latest/download/i18n.tar.gz" || echo "Failed to download i18n.tar.gz" ls -la dist/i18n.tar.gz 2>/dev/null || echo "No i18n.tar.gz downloaded" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload Release Assets run: | From 55d3606bad305b472f809ad6e7db3bdb82907a56 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sun, 5 Apr 2026 00:01:45 +0800 Subject: [PATCH 08/14] =?UTF-8?q?fix:=20=E5=A4=84=E7=90=86=20workflow=5Fdi?= =?UTF-8?q?spatch=20=E6=97=B6=E7=9A=84=20tag=20=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 29d441bf1..bc0327eaa 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -28,6 +28,22 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v5 + - name: Determine release tag + id: tag + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + VERSION="${{ github.event.inputs.version }}" + TAG="v${VERSION}" + echo "Creating new tag: $TAG" + git tag -a "$TAG" -m "Release $TAG" || git push --delete "$TAG" 2>/dev/null || true + git tag -a "$TAG" -m "Release $TAG" + echo "tag=$TAG" >> $GITHUB_OUTPUT + else + TAG="${{ github.ref_name }}" + echo "Using existing tag: $TAG" + echo "tag=$TAG" >> $GITHUB_OUTPUT + fi + - name: Build Release run: | chmod +x build.sh @@ -42,8 +58,9 @@ jobs: - name: Upload Release Assets run: | gh release create \ - --title "Release ${{ github.ref_name }}" \ - ${{ github.ref_name }} \ + --title "Release ${{ steps.tag.outputs.tag }}" \ + --clobber \ + ${{ steps.tag.outputs.tag }} \ dist/openlist-frontend-dist-v*.tar.gz \ dist/i18n.tar.gz env: From 7d067bb30d5f9bf68c2d45105c6cb182637a5e2b Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sun, 5 Apr 2026 00:03:18 +0800 Subject: [PATCH 09/14] =?UTF-8?q?chore:=20=E6=89=8B=E5=8A=A8=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E6=97=B6=E4=BD=BF=E7=94=A8=E6=97=B6=E9=97=B4=E6=88=B3?= =?UTF-8?q?=E4=BD=9C=E4=B8=BA=20tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index bc0327eaa..7b112cb80 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -32,10 +32,10 @@ jobs: id: tag run: | if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then - VERSION="${{ github.event.inputs.version }}" - TAG="v${VERSION}" - echo "Creating new tag: $TAG" - git tag -a "$TAG" -m "Release $TAG" || git push --delete "$TAG" 2>/dev/null || true + # 使用时间戳作为 tag,避免冲突 + TIMESTAMP=$(date +%Y%m%d%H%M%S) + TAG="v${TIMESTAMP}" + echo "Creating timestamp tag: $TAG" git tag -a "$TAG" -m "Release $TAG" echo "tag=$TAG" >> $GITHUB_OUTPUT else From 1c9456ebf6baa71b01e949ea91d4248e66d948be Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sun, 5 Apr 2026 00:07:01 +0800 Subject: [PATCH 10/14] =?UTF-8?q?fix:=20=E9=85=8D=E7=BD=AE=20Git=20?= =?UTF-8?q?=E8=BA=AB=E4=BB=BD=E4=BB=A5=E5=88=9B=E5=BB=BA=20tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 7b112cb80..be0e16b40 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -28,6 +28,11 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v5 + - name: Configure Git identity + run: | + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + - name: Determine release tag id: tag run: | From 2b59069e21eb1a0617f85cf59f98b5b07a757b03 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sun, 5 Apr 2026 00:08:10 +0800 Subject: [PATCH 11/14] =?UTF-8?q?chore:=20=E6=94=AF=E6=8C=81=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E6=88=B3=E6=A0=BC=E5=BC=8F=E7=9A=84=20tag?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build.sh b/build.sh index 01801fb3f..20f77327f 100755 --- a/build.sh +++ b/build.sh @@ -105,6 +105,13 @@ enforce_git_tag() { validate_git_tag() { package_version=$(grep '"version":' package.json | sed 's/.*"version": *"\([^"]*\)".*/\1/') git_version_clean=${git_version#v} + + # 检查是否为时间戳格式(纯数字),如果是则跳过版本验证 + if [[ "$git_version_clean" =~ ^[0-9]+$ ]]; then + log_info "Timestamp tag detected (${git_version_clean}), skipping version validation" + return 0 + fi + if [[ "$git_version_clean" != "$package_version" ]]; then log_error "Package.json version (${package_version}) does not match git tag (${git_version_clean})." exit 1 From 461a991015c4c560d46f7959b3fb4d1b65bf5734 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sun, 5 Apr 2026 00:11:38 +0800 Subject: [PATCH 12/14] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E4=B8=8D?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=9A=84=20--clobber=20=E6=A0=87=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index be0e16b40..42a817af1 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -60,11 +60,17 @@ jobs: curl -L -o dist/i18n.tar.gz "https://github.com/OpenListTeam/OpenList-Frontend/releases/latest/download/i18n.tar.gz" || echo "Failed to download i18n.tar.gz" ls -la dist/i18n.tar.gz 2>/dev/null || echo "No i18n.tar.gz downloaded" + - name: Delete existing release (if any) + run: | + if gh release view ${{ steps.tag.outputs.tag }} --json isDraft --quiet 2>/dev/null; then + echo "Deleting existing release: ${{ steps.tag.outputs.tag }}" + gh release delete ${{ steps.tag.outputs.tag }} --cleanup-tag=false --yes 2>/dev/null || true + fi + - name: Upload Release Assets run: | gh release create \ --title "Release ${{ steps.tag.outputs.tag }}" \ - --clobber \ ${{ steps.tag.outputs.tag }} \ dist/openlist-frontend-dist-v*.tar.gz \ dist/i18n.tar.gz From ccb2fc1208ab22d01833d734972ee621036c9e70 Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sun, 5 Apr 2026 00:13:55 +0800 Subject: [PATCH 13/14] =?UTF-8?q?fix:=20=E6=8E=A8=E9=80=81=E6=96=B0?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E7=9A=84=20tag=20=E5=88=B0=E8=BF=9C=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 42a817af1..2b4481c2b 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -42,6 +42,7 @@ jobs: TAG="v${TIMESTAMP}" echo "Creating timestamp tag: $TAG" git tag -a "$TAG" -m "Release $TAG" + git push origin "$TAG" echo "tag=$TAG" >> $GITHUB_OUTPUT else TAG="${{ github.ref_name }}" From 01f47574b90590944c317556325b05c0facb64ef Mon Sep 17 00:00:00 2001 From: zhlhlf Date: Sun, 5 Apr 2026 00:17:08 +0800 Subject: [PATCH 14/14] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20lite=20?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E6=9E=84=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build_release.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 2b4481c2b..a6a7cc5ef 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -55,6 +55,22 @@ jobs: chmod +x build.sh ./build.sh --release --compress + - name: Move regular build + run: | + mkdir -p regular-dist + mv dist/* regular-dist/ + + - name: Build Lite Release + run: | + chmod +x build.sh + ./build.sh --release --compress --lite + + - name: Move lite build and restore regular build + run: | + mkdir -p lite-dist + mv dist/* lite-dist/ + mv regular-dist/* dist/ + - name: Download i18n.tar.gz from latest release run: | echo "Downloading i18n.tar.gz from latest release..." @@ -74,6 +90,7 @@ jobs: --title "Release ${{ steps.tag.outputs.tag }}" \ ${{ steps.tag.outputs.tag }} \ dist/openlist-frontend-dist-v*.tar.gz \ + lite-dist/openlist-frontend-dist-lite-v*.tar.gz \ dist/i18n.tar.gz env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}