diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1fb1149..80aa041 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -76,6 +76,9 @@ jobs: - kind: ja-JP tag: latest base: "/docs/" + - kind: no-config + tag: v0.14.1 + base: "/docs/" name: | Build for ${{ matrix.kind }} ${{ matrix.tag }} (base: ${{ matrix.base }}) steps: @@ -89,11 +92,14 @@ jobs: if: ${{ matrix.kind == 'ja-JP' }} run: bun run fetch-docs-ja-jp - name: Fetch docs assets - if: ${{ matrix.kind == 'official' }} + if: ${{ matrix.kind == 'official' || matrix.kind == 'no-config' }} shell: bash run: | set -euxo pipefail - bash scripts/fetch-docs-assets.sh --tag "${{ matrix.tag }}" --base "${{ matrix.base }}" --dest public + bash scripts/fetch-docs-assets.sh \ + --tag "${{ matrix.tag }}" \ + --base "${{ matrix.base }}" \ + --dest public ${{ matrix.kind == 'no-config' && '--skip metadata --skip favicon' || '' }} - name: Run Vite build run: bun run build diff --git a/scripts/fetch-docs-assets.sh b/scripts/fetch-docs-assets.sh index d466b63..5879393 100644 --- a/scripts/fetch-docs-assets.sh +++ b/scripts/fetch-docs-assets.sh @@ -7,20 +7,22 @@ set -euo pipefail print_usage() { cat <<'EOF' -Usage: fetch-docs-assets.sh [--tag TAG] [--base BASE] [--dest DEST] [--origin ORIGIN] +Usage: fetch-docs-assets.sh [--tag TAG] [--base BASE] [options...] Environment/args: --tag TAG (required) Release tag to download, e.g. v0.14.0 or latest --base BASE (required) Base path used by docs, e.g. / or /docs/ --dest DEST (optional) Destination directory to write files (default: public) --origin ORIGIN (optional) Origin URL for the deployed site, without base path (default: https://example.com/) + --skip FILE (optional) Skip one of the files (docs.json, docs-assets, favicon, metadata), can be specified multiple times This script performs the following: - - Downloads docs.json from the release tag - - Replaces '/DOCS-BASE/' placeholder in docs.json with the provided base - - Downloads docs-assets.zip and extracts it to destination/assets - - Downloads favicon and writes to destination/favicon.png - - Generates destination/metadata.json with basic deployment metadata + - docs.json: + - Downloads docs.json from the release tag + - Replaces '/DOCS-BASE/' placeholder in docs.json with the provided base + - docs-assets: Downloads docs-assets.zip and extracts it to destination/assets + - favicon: Downloads favicon and writes to destination/favicon.png + - metadata: Generates destination/metadata.json with basic deployment metadata EOF } @@ -30,6 +32,7 @@ DEST="public" ORIGIN="https://example.com/" TAG="" BASE="" +SKIP=() # Parse args while [[ $# -gt 0 ]]; do @@ -50,6 +53,19 @@ while [[ $# -gt 0 ]]; do ORIGIN="$2" shift 2 ;; + --skip) + case "$2" in + docs.json | docs-assets | favicon | metadata) + SKIP+=("$2") + shift 2 + ;; + *) + echo "Invalid --skip option: $2" >&2 + print_usage + exit 2 + ;; + esac + ;; --help | -h) print_usage exit 0 @@ -80,52 +96,67 @@ fi RELEASE_BASE_URL="https://github.com/${ORG}/dev-builds/releases/download/docs-${TAG}" # Download docs.json -DOCS_URL="${RELEASE_BASE_URL}/docs.json" -echo "Fetching docs from ${DOCS_URL}" -if ! curl -sSfL "$DOCS_URL" -o "${DEST}/docs.json"; then - echo "Failed to download docs.json from ${DOCS_URL}" >&2 - exit 3 -fi - -# Replace placeholder '/DOCS-BASE/' with provided base in docs.json -# Use `sd` if available, else fallback to sed -if command -v sd >/dev/null 2>&1; then - sd '/DOCS-BASE/' "$BASE" "${DEST}/docs.json" +if printf '%s\n' "${SKIP[@]}" | grep -qx "docs.json"; then + echo "Skipping docs.json download as per --skip option" else - # Use portable sed: escape slashes - ESCAPED_BASE=$(printf '%s' "$BASE" | sed 's|/|\\/|g') - sed -i "s/\/DOCS-BASE\//${ESCAPED_BASE}/g" "${DEST}/docs.json" + DOCS_URL="${RELEASE_BASE_URL}/docs.json" + echo "Fetching docs from ${DOCS_URL}" + if ! curl -sSfL "$DOCS_URL" -o "${DEST}/docs.json"; then + echo "Failed to download docs.json from ${DOCS_URL}" >&2 + exit 3 + fi + + # Replace placeholder '/DOCS-BASE/' with provided base in docs.json + # Use `sd` if available, else fallback to sed + if command -v sd >/dev/null 2>&1; then + sd '/DOCS-BASE/' "$BASE" "${DEST}/docs.json" + else + # Use portable sed: escape slashes + ESCAPED_BASE=$(printf '%s' "$BASE" | sed 's|/|\\/|g') + sed -i "s/\/DOCS-BASE\//${ESCAPED_BASE}/g" "${DEST}/docs.json" + fi fi # Download assets and extract -ASSETS_URL="${RELEASE_BASE_URL}/docs-assets.zip" -ASSETS_ZIP="docs-assets.zip" -if curl -sSfL "$ASSETS_URL" -o "$ASSETS_ZIP"; then - echo "Extracting ${ASSETS_ZIP} to ${DEST}/assets" - # Clean up existing assets if present - rm -rf "${DEST}/assets" - unzip -q "$ASSETS_ZIP" - if [[ -d assets ]]; then - mv assets "${DEST}/assets" +if printf '%s\n' "${SKIP[@]}" | grep -qx "docs-assets"; then + echo "Skipping docs-assets download as per --skip option" +else + ASSETS_URL="${RELEASE_BASE_URL}/docs-assets.zip" + ASSETS_ZIP="docs-assets.zip" + if curl -sSfL "$ASSETS_URL" -o "$ASSETS_ZIP"; then + echo "Extracting ${ASSETS_ZIP} to ${DEST}/assets" + # Clean up existing assets if present + rm -rf "${DEST}/assets" + unzip -q "$ASSETS_ZIP" + if [[ -d assets ]]; then + mv assets "${DEST}/assets" + else + echo "Downloaded zip did not contain assets/ folder" >&2 + # keep build going; not necessarily fatal + fi + rm -f "$ASSETS_ZIP" else - echo "Downloaded zip did not contain assets/ folder" >&2 - # keep build going; not necessarily fatal + echo "No assets ZIP was found at ${ASSETS_URL} (continuing without error)" >&2 fi - rm -f "$ASSETS_ZIP" -else - echo "No assets ZIP was found at ${ASSETS_URL} (continuing without error)" >&2 fi # Download favicon -FAVICON_URL="https://github.com/${ORG}/org/raw/main/design/typst-community.icon.png" -if curl -sSfL "$FAVICON_URL" -o "${DEST}/favicon.png"; then - echo "Wrote favicon to ${DEST}/favicon.png" +if printf '%s\n' "${SKIP[@]}" | grep -qx "favicon"; then + echo "Skipping favicon download as per --skip option" else - echo "Failed to download favicon from ${FAVICON_URL} (continuing without error)" >&2 + FAVICON_URL="https://github.com/${ORG}/org/raw/main/design/typst-community.icon.png" + if curl -sSfL "$FAVICON_URL" -o "${DEST}/favicon.png"; then + echo "Wrote favicon to ${DEST}/favicon.png" + else + echo "Failed to download favicon from ${FAVICON_URL} (continuing without error)" >&2 + fi fi # Write metadata.json -cat >"${DEST}/metadata.json" <"${DEST}/metadata.json" <"${DEST}/metadata.json" < { typstOfficialUrl: "https://typst.app/", typstOfficialDocsUrl: "https://typst.app/docs/", githubOrganizationUrl: "https://github.com/typst", - socialLinks: [ - { url: "https://github.com/typst/typst" }, - { - title: "Discord (dummy)", - url: "https://discord.gg/dummy", - }, - ], + socialLinks: [{ url: "https://github.com/typst/typst" }], originUrl: "https://example.com/", basePath: "/docs/", displayTranslationStatus: true, diff --git a/src/translation/index.tsx b/src/translation/index.tsx index 77b9bd8..67f1a30 100644 --- a/src/translation/index.tsx +++ b/src/translation/index.tsx @@ -1,14 +1,6 @@ import type { FC } from "hono/jsx"; import type { TooltipProps } from "../components/ui/Tooltip"; import { language } from "../metadata"; -import { - Translation as EnUSTranslation, - translation as enUSTranslation, -} from "./en-US"; -import { - Translation as JaJPTranslation, - translation as jaJPTranslation, -} from "./ja-JP"; /** * Translation dictionary for UI attributes and aria labels. @@ -105,12 +97,15 @@ export type TranslationComponentProps = export type TranslationComponent = FC; // Switch translation language. -const { Translation, translation } = (() => { +const { Translation, translation } = await (() => { + // These imports should be lazy and static. + // - Lazy: A translation may use special metadata (e.g., Discord/QQ URL), so not all translations can be safely imported in every build. Therefore, we have to use the import function, not the import statement. + // - Static: The argument of the import function has to be a plain string, not a variable. Dynamic import has limitations even with rollup and vite properly configured. switch (language) { - case "ja-JP": - return { Translation: JaJPTranslation, translation: jaJPTranslation }; case "en-US": - return { Translation: EnUSTranslation, translation: enUSTranslation }; + return import("./en-US"); + case "ja-JP": + return import("./ja-JP"); default: throw new Error(`Unsupported language: ${language}`); }