Skip to content
Merged
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
8 changes: 8 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24
- name: Install locked dependencies without install scripts
run: npm ci --ignore-scripts
- name: Build the site (fails on dead links)
run: npm run build
- name: Check that Chinese and English pages match
run: python3 scripts/i18n.py
- name: Warn when a page changed in one language only
if: github.event_name == 'pull_request'
env:
BASE_REF: ${{ github.base_ref }}
run: python3 scripts/i18n.py --base "origin/$BASE_REF"
- name: Scan tracked files for private identity and paths
run: python3 scripts/privacy.py .
33 changes: 33 additions & 0 deletions README.en.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ModAVD documentation site

[简体中文](README.md) | **English**

<!-- README.md and README.en.md match section by section: if you change one, change the other in the same PR. -->

The source of the documentation site for [ModAVD](https://github.com/ModAVD/ModAVD), published at <https://modavd.github.io/> (English version: <https://modavd.github.io/en/>). It is built with [VitePress](https://vitepress.dev/).

- Pages are Markdown files under `docs/`, and Chinese is the primary language. English pages are under `docs/en/`, at the same paths as the Chinese pages. The navigation and sidebar are in `docs/.vitepress/config.mts`, and both languages use one table of pages.
- Every page has an "Edit this page on GitHub" link at the bottom; make your change and open a PR. How to write pages is described on the site under "Contributing → Documentation and this site".
- If you change a page in one language, change the other language in the same PR. If you only write one of the two, say so in the PR and the maintainer will add the other.

## Preview locally

You need Node.js 24.

```powershell
npm ci --ignore-scripts
npm run dev # local preview
npm run build # builds docs/.vitepress/dist; dead links fail the build
python scripts/i18n.py # checks the Chinese and English pages and headings, same as CI
python scripts/privacy.py . # privacy scan, same as CI
```

## CI

- `check.yml`: on a PR it builds the whole site (dead-link check), checks that the Chinese and English pages match (`scripts/i18n.py`: every page exists in both languages, headings have the same levels and order, site links do not cross languages, and every anchor resolves; a page changed in one language only gets a warning), and runs the privacy scan.
- `deploy.yml`: after a merge into `main` it builds the site and publishes it to GitHub Pages.
- Third-party actions are always pinned to a full 40-character commit SHA; no `pull_request_target`, no self-hosted runners.

## License

The documentation is published under the Apache License 2.0; see [LICENSE](LICENSE). Copyright 2026 qiyinxi.
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
# ModAVD 文档站

[ModAVD(魔改 AVD)](https://github.com/ModAVD/ModAVD) 的文档站源码,发布在 <https://modavd.github.io/>。用 [VitePress](https://vitepress.dev/) 编译。
**简体中文** | [English](README.en.md)

- 页面是 `docs/` 下的 Markdown;导航和侧边栏在 `docs/.vitepress/config.mts`。
<!-- README.md 和 README.en.md 逐节对应:改了其中一份,请在同一个 PR 里把另一份也改了。 -->

[ModAVD(魔改 AVD)](https://github.com/ModAVD/ModAVD) 的文档站源码,发布在 <https://modavd.github.io/>(英文版在 <https://modavd.github.io/en/>)。用 [VitePress](https://vitepress.dev/) 编译。

- 页面是 `docs/` 下的 Markdown,中文是主语言;英文页在 `docs/en/` 下,路径和中文页一一对应。导航和侧边栏在 `docs/.vitepress/config.mts`,两种语言用同一张页面表。
- 每页底部有「在 GitHub 上改这一页」,改完提 PR 就行。写法见站内的「参与开发 → 文档和本站」。
- 改了一种语言的页面,在同一个 PR 里把另一种也改了;只会写一种语言的,在 PR 里说一声,由维护者补上。

## 本地预览

Expand All @@ -13,12 +18,13 @@
npm ci --ignore-scripts
npm run dev # 本地预览
npm run build # 编出 docs/.vitepress/dist,有死链会报错
python scripts/i18n.py # 核对中英页面和标题,和 CI 一样
python scripts/privacy.py . # 隐私扫描,和 CI 一样
```

## CI

- `check.yml`:PR 上编译整站(查死链)、跑隐私扫描。
- `check.yml`:PR 上编译整站(查死链)、核对中英页面(`scripts/i18n.py`:每页都有两种语言,标题的层级和顺序相同,站内链接不串语言,锚点都找得到;只改了一种语言的页面会标出提醒)、跑隐私扫描。
- `deploy.yml`:合进 `main` 后编译并发布到 GitHub Pages。
- 第三方 action 一律钉到 40 位提交 SHA;不用 `pull_request_target`,不用自托管 runner。

Expand Down
252 changes: 151 additions & 101 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -1,110 +1,176 @@
import { defineConfig } from 'vitepress'
import { defineConfig, type DefaultTheme } from 'vitepress'

const repo = 'https://github.com/ModAVD/modavd.github.io'
const origin = 'https://modavd.github.io'

type Lang = 'zh' | 'en'

// 页面标题,两种语言放在同一张表里:新加页面时两边一起写。
// [链接, 中文标题, 英文标题]
type Page = [link: string, zh: string, en: string]

const guide: Page[] = [
['/guide/', '这是什么', 'What is ModAVD'],
['/guide/install', '安装', 'Install'],
['/guide/upgrade', '升级', 'Upgrade'],
['/guide/changes', '和官方模拟器有什么不同', 'How ModAVD differs from the official emulator'],
['/guide/feedback', '反馈问题', 'Report a problem'],
['/guide/privacy', '隐私', 'Privacy'],
['/guide/license', '许可证与源码', 'Licenses and source code'],
]

const components: Page[] = [
['/components/manager', '管理器和命令行', 'The manager and CLI'],
['/components/bridge', 'arm64 执行桥', 'The arm64 execution bridge'],
['/components/ime', '宿主输入法', 'The host IME'],
]

const develop: { group: [zh: string, en: string]; pages: Page[] }[] = [
{
group: ['开始', 'Getting started'],
pages: [
['/develop/', '参与 ModAVD', 'Contributing to ModAVD'],
['/develop/overview', '分区一览和通用要求', 'Areas and common requirements'],
['/develop/ai', '用 AI 工具协助', 'Using AI tools'],
],
},
{
group: ['各分区', 'Areas'],
pages: [
['/develop/emulator', '模拟器本体', 'The emulator itself'],
['/develop/build', '从源码构建', 'Building from source'],
['/develop/bridge', 'arm64 执行桥', 'The arm64 execution bridge'],
['/develop/manager', '管理器和命令行', 'The manager and CLI'],
['/develop/ime', '宿主输入法', 'The host IME'],
['/develop/package', '随包脚本', 'Bundled scripts'],
['/develop/docs', '文档和本站', 'Documentation and this site'],
['/develop/automas', 'AUTO-MAS 对接', 'AUTO-MAS integration'],
['/develop/testing', '游戏实测和兼容性报告', 'Game testing and compatibility reports'],
],
},
{
group: ['查问题', 'Investigating problems'],
pages: [
['/develop/adapt-game', '适配新游戏', 'Adapting a new game'],
['/develop/performance', '卡顿、掉帧怎么查', 'Investigating stutter and frame drops'],
['/develop/troubleshooting', '常见问题怎么查', 'Investigating common problems'],
],
},
]

const label = {
zh: {
guide: '使用', components: '组件', develop: '参与开发', download: '下载', fullPackage: 'ModAVD(整包)',
description: '基于 AOSP Android Emulator 的安卓模拟器',
},
en: {
guide: 'Guide', components: 'Components', develop: 'Contributing', download: 'Download', fullPackage: 'ModAVD (full package)',
description: 'An Android emulator built from the AOSP Android Emulator',
},
}

function nav(lang: Lang): DefaultTheme.NavItem[] {
const p = lang === 'en' ? '/en' : ''
const l = label[lang]
return [
{ text: l.guide, link: `${p}/guide/`, activeMatch: `${p}/guide/` },
{ text: l.components, link: `${p}/components/manager`, activeMatch: `${p}/components/` },
{ text: l.develop, link: `${p}/develop/`, activeMatch: `${p}/develop/` },
{
text: l.download,
items: [
{ text: l.fullPackage, link: 'https://github.com/ModAVD/ModAVD/releases' },
{ text: 'ModAVDManager', link: 'https://github.com/ModAVD/ModAVDManager/releases' },
{ text: 'ModAVDHostIME', link: 'https://github.com/ModAVD/ModAVDHostIME/releases' },
],
},
]
}

function sidebar(lang: Lang): DefaultTheme.Sidebar {
const p = lang === 'en' ? '/en' : ''
const items = (pages: Page[]) => pages.map(([link, zh, en]) => ({ text: lang === 'en' ? en : zh, link: p + link }))
const i = lang === 'en' ? 1 : 0
return {
[`${p}/guide/`]: [{ text: label[lang].guide, items: items(guide) }],
[`${p}/components/`]: [{ text: label[lang].components, items: items(components) }],
[`${p}/develop/`]: develop.map(({ group, pages }) => ({ text: group[i], items: items(pages) })),
}
}

// <link rel="alternate" hreflang> 指向同一页的另一种语言
function alternates(relativePath: string): [string, Record<string, string>][] {
if (!relativePath.endsWith('.md') || relativePath === '404.md') return []
const url = (path: string) => origin + '/' + path.replace(/\.md$/, '').replace(/(^|\/)index$/, '$1')
const zh = relativePath.replace(/^en\//, '')
return [
['link', { rel: 'alternate', hreflang: 'zh-CN', href: url(zh) }],
['link', { rel: 'alternate', hreflang: 'en', href: url('en/' + zh) }],
]
}

export default defineConfig({
lang: 'zh-CN',
title: 'ModAVD',
description: '基于 AOSP Android Emulator 的安卓模拟器',
cleanUrls: true,
lastUpdated: true,
// 不往外取字体、统计脚本,页面只用本站自己的文件
head: [['meta', { name: 'theme-color', content: '#3c6fb4' }]],
transformHead: ({ pageData }) => alternates(pageData.relativePath),

// 中文(根)和英文(/en/)各一份导航、侧边栏和界面文字,页面一一对应
locales: {
root: { label: '简体中文', lang: 'zh-CN' },
root: {
label: '简体中文',
lang: 'zh-CN',
description: label.zh.description,
themeConfig: {
nav: nav('zh'),
sidebar: sidebar('zh'),
editLink: { pattern: `${repo}/edit/main/docs/:path`, text: '在 GitHub 上改这一页' },
footer: { message: 'Android 是 Google LLC 的商标。', copyright: '文档按 Apache License 2.0 发布' },
outline: { level: [2, 3], label: '本页内容' },
docFooter: { prev: '上一页', next: '下一页' },
lastUpdated: { text: '最后更新' },
returnToTopLabel: '回到顶部',
sidebarMenuLabel: '目录',
darkModeSwitchLabel: '深色模式',
lightModeSwitchTitle: '切换到浅色',
darkModeSwitchTitle: '切换到深色',
langMenuLabel: '语言',
notFound: { title: '页面不存在', quote: '这个地址没有页面,可能是改名或挪走了。', linkText: '回首页' },
},
},
en: {
label: 'English',
lang: 'en-US',
description: 'An Android emulator built from the AOSP Android Emulator',
link: '/en/',
description: label.en.description,
themeConfig: {
nav: [{ text: 'GitHub', link: 'https://github.com/ModAVD/ModAVD' }],
sidebar: { '/en/': [{ text: 'English', items: [{ text: 'Overview', link: '/en/' }] }] },
nav: nav('en'),
sidebar: sidebar('en'),
editLink: { pattern: `${repo}/edit/main/docs/:path`, text: 'Edit this page on GitHub' },
footer: { message: 'Android is a trademark of Google LLC.', copyright: 'Documentation is published under the Apache License 2.0' },
outline: { level: [2, 3], label: 'On this page' },
docFooter: { prev: 'Previous page', next: 'Next page' },
lastUpdated: { text: 'Last updated' },
returnToTopLabel: 'Back to top',
sidebarMenuLabel: 'Menu',
darkModeSwitchLabel: 'Appearance',
lightModeSwitchTitle: 'Switch to light theme',
darkModeSwitchTitle: 'Switch to dark theme',
langMenuLabel: 'Language',
notFound: {
title: 'PAGE NOT FOUND',
quote: 'There is no page at this address; it may have been renamed or moved.',
linkText: 'Take me home',
},
},
},
},

themeConfig: {
nav: [
{ text: '使用', link: '/guide/', activeMatch: '/guide/' },
{ text: '组件', link: '/components/manager', activeMatch: '/components/' },
{ text: '参与开发', link: '/develop/', activeMatch: '/develop/' },
{
text: '下载',
items: [
{ text: 'ModAVD(整包)', link: 'https://github.com/ModAVD/ModAVD/releases' },
{ text: 'ModAVDManager', link: 'https://github.com/ModAVD/ModAVDManager/releases' },
{ text: 'ModAVDHostIME', link: 'https://github.com/ModAVD/ModAVDHostIME/releases' },
],
},
],

sidebar: {
'/guide/': [
{
text: '使用',
items: [
{ text: '这是什么', link: '/guide/' },
{ text: '安装', link: '/guide/install' },
{ text: '升级', link: '/guide/upgrade' },
{ text: '和官方模拟器有什么不同', link: '/guide/changes' },
{ text: '反馈问题', link: '/guide/feedback' },
{ text: '隐私', link: '/guide/privacy' },
{ text: '许可证与源码', link: '/guide/license' },
],
},
],
'/components/': [
{
text: '组件',
items: [
{ text: '管理器和命令行', link: '/components/manager' },
{ text: 'arm64 执行桥', link: '/components/bridge' },
{ text: '宿主输入法', link: '/components/ime' },
],
},
],
'/develop/': [
{
text: '开始',
items: [
{ text: '参与 ModAVD', link: '/develop/' },
{ text: '分区一览和通用要求', link: '/develop/overview' },
{ text: '用 AI 工具协助', link: '/develop/ai' },
],
},
{
text: '各分区',
items: [
{ text: '模拟器本体', link: '/develop/emulator' },
{ text: '从源码构建', link: '/develop/build' },
{ text: 'arm64 执行桥', link: '/develop/bridge' },
{ text: '管理器和命令行', link: '/develop/manager' },
{ text: '宿主输入法', link: '/develop/ime' },
{ text: '随包脚本', link: '/develop/package' },
{ text: '文档和本站', link: '/develop/docs' },
{ text: 'AUTO-MAS 对接', link: '/develop/automas' },
{ text: '游戏实测和兼容性报告', link: '/develop/testing' },
],
},
{
text: '查问题',
items: [
{ text: '适配新游戏', link: '/develop/adapt-game' },
{ text: '卡顿、掉帧怎么查', link: '/develop/performance' },
{ text: '常见问题怎么查', link: '/develop/troubleshooting' },
],
},
],
},

socialLinks: [{ icon: 'github', link: 'https://github.com/ModAVD' }],

editLink: {
pattern: `${repo}/edit/main/docs/:path`,
text: '在 GitHub 上改这一页',
},

search: {
provider: 'local',
options: {
Expand All @@ -122,21 +188,5 @@ export default defineConfig({
},
},
},

footer: {
message: 'Android 是 Google LLC 的商标。',
copyright: '文档按 Apache License 2.0 发布',
},

outline: { level: [2, 3], label: '本页内容' },
docFooter: { prev: '上一页', next: '下一页' },
lastUpdated: { text: '最后更新' },
returnToTopLabel: '回到顶部',
sidebarMenuLabel: '目录',
darkModeSwitchLabel: '深色模式',
lightModeSwitchTitle: '切换到浅色',
darkModeSwitchTitle: '切换到深色',
langMenuLabel: '语言',
notFound: { title: '页面不存在', quote: '这个地址没有页面,可能是改名或挪走了。', linkText: '回首页' },
},
})
Loading