mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-10-02 00:24:34 -04:00
docs: move English sources into docs/en/ locale folder (#5501)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
1 parent
92cfbaee9b
commit
11bc37c968
42 files changed
+155
-110
No files matched your search
@@ -39,7 +39,7 @@ jobs:
|
||||
'^feature/.*/src/commonMain/.*/(ui|component|screen)/|^feature/.*/src/androidMain/.*/ui/|^core/ui/src/commonMain/' \
|
||||
| grep -v 'Test\|Preview\|__Snapshots__' || true)
|
||||
|
||||
docs_changed=$(echo "$changed" | grep -E '^docs/(user|developer)/' || true)
|
||||
docs_changed=$(echo "$changed" | grep -E '^docs/en/(user|developer)/' || true)
|
||||
|
||||
echo "views_changed<<EOF" >> "$GITHUB_OUTPUT"
|
||||
echo "$views_changed" >> "$GITHUB_OUTPUT"
|
||||
@@ -64,9 +64,9 @@ jobs:
|
||||
const body = [
|
||||
'## 📄 Docs staleness check — advisory',
|
||||
'',
|
||||
'This PR modifies user-facing UI source files but does not update any page under `docs/user/` or `docs/developer/`.',
|
||||
'This PR modifies user-facing UI source files but does not update any page under `docs/en/user/` or `docs/en/developer/`.',
|
||||
'',
|
||||
'> ⚠️ Doc changes propagate to **3 consumers**: in-app docs browser, Jekyll site (GitHub Pages), and meshtastic.org (Docusaurus sync). Updating a page in `docs/` automatically flows to all three.',
|
||||
'> ⚠️ Doc changes propagate to **3 consumers**: in-app docs browser, Jekyll site (GitHub Pages), and meshtastic.org (Docusaurus sync). Updating a page in `docs/en/` automatically flows to all three.',
|
||||
'',
|
||||
'**Changed source files:**',
|
||||
'```',
|
||||
@@ -76,19 +76,19 @@ jobs:
|
||||
'**What to check:**',
|
||||
'| Changed area | Likely doc page |',
|
||||
'|---|---|',
|
||||
'| `feature/messaging/` | `docs/user/messages-and-channels.md` |',
|
||||
'| `feature/node/` | `docs/user/nodes.md` or `docs/user/node-metrics.md` |',
|
||||
'| `feature/map/` | `docs/user/map-and-waypoints.md` |',
|
||||
'| `feature/connections/` | `docs/user/connections.md` |',
|
||||
'| `feature/settings/` | `docs/user/settings-radio-user.md` or `docs/user/settings-module-admin.md` |',
|
||||
'| `feature/firmware/` | `docs/user/firmware.md` |',
|
||||
'| `feature/intro/` | `docs/user/onboarding.md` |',
|
||||
'| `feature/discovery/` | `docs/user/discovery.md` |',
|
||||
'| `feature/messaging/` | `docs/en/user/messages-and-channels.md` |',
|
||||
'| `feature/node/` | `docs/en/user/nodes.md` or `docs/en/user/node-metrics.md` |',
|
||||
'| `feature/map/` | `docs/en/user/map-and-waypoints.md` |',
|
||||
'| `feature/connections/` | `docs/en/user/connections.md` |',
|
||||
'| `feature/settings/` | `docs/en/user/settings-radio-user.md` or `docs/en/user/settings-module-admin.md` |',
|
||||
'| `feature/firmware/` | `docs/en/user/firmware.md` |',
|
||||
'| `feature/intro/` | `docs/en/user/onboarding.md` |',
|
||||
'| `feature/discovery/` | `docs/en/user/discovery.md` |',
|
||||
'| `feature/docs/` | Internal docs infrastructure |',
|
||||
'| `core/ui/` | `docs/developer/codebase.md` or component-specific user pages |',
|
||||
'| `core/ui/` | `docs/en/developer/codebase.md` or component-specific user pages |',
|
||||
'',
|
||||
'**New page checklist** (if adding a new doc page):',
|
||||
'1. Create the `.md` file in `docs/user/` or `docs/developer/` with `last_updated` frontmatter',
|
||||
'1. Create the `.md` file in `docs/en/user/` or `docs/en/developer/` with `last_updated` frontmatter',
|
||||
'2. Register in `DocBundleLoader.kt` with string resources (in-app browser)',
|
||||
'3. Jekyll and Docusaurus sync pick up new pages automatically — no config change needed',
|
||||
'',
|
||||
@@ -141,14 +141,14 @@ jobs:
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: existing.id,
|
||||
body: '## ✅ Docs staleness check passed\n\nThis PR includes updates to `docs/` alongside the source changes. Thank you!',
|
||||
body: '## ✅ Docs staleness check passed\n\nThis PR includes updates to `docs/en/` alongside the source changes. Thank you!',
|
||||
});
|
||||
}
|
||||
|
||||
- name: Advisory status
|
||||
if: steps.changed.outputs.stale == 'true'
|
||||
run: |
|
||||
echo "::warning::UI source files changed without corresponding docs/ updates."
|
||||
echo "::warning::UI source files changed without corresponding docs/en/ updates."
|
||||
echo "Add the 'skip-docs-check' label if this PR does not require a doc update."
|
||||
echo "NOTE: This check is advisory while docs coverage matures across platforms."
|
||||
echo "To upgrade to blocking, change this step to 'exit 1'."
|
||||
@@ -170,7 +170,7 @@ jobs:
|
||||
node-version: "24"
|
||||
|
||||
- name: Validate internal links
|
||||
run: node scripts/validate-doc-links.js docs
|
||||
run: node scripts/validate-doc-links.js docs/en
|
||||
|
||||
- name: Check doc coverage
|
||||
run: node scripts/check-doc-coverage.js .
|
||||
@@ -179,7 +179,7 @@ jobs:
|
||||
run: |
|
||||
loader="feature/docs/src/commonMain/kotlin/org/meshtastic/feature/docs/data/DocBundleLoader.kt"
|
||||
missing=0
|
||||
for f in docs/user/*.md docs/developer/*.md; do
|
||||
for f in docs/en/user/*.md docs/en/developer/*.md; do
|
||||
slug=$(basename "$f" .md)
|
||||
if ! grep -q "\"$slug\"" "$loader"; then
|
||||
echo "ERROR: $slug not registered in DocBundleLoader.kt"
|
||||
|
||||
@@ -100,9 +100,10 @@ abstract class GenerateDocsBundleTask : DefaultTask() {
|
||||
val indexEntries = mutableListOf<String>()
|
||||
var pageCount = 0
|
||||
|
||||
// Process English user and developer directories
|
||||
// Process English user and developer directories (under docs/en/)
|
||||
val enDir = File(src, "en")
|
||||
listOf("user", "developer").forEach { section ->
|
||||
val sectionDir = File(src, section)
|
||||
val sectionDir = File(enDir, section)
|
||||
if (!sectionDir.exists()) return@forEach
|
||||
|
||||
sectionDir.listFiles { f -> f.extension == "md" }?.sortedBy { it.name }?.forEach { mdFile ->
|
||||
@@ -143,8 +144,9 @@ abstract class GenerateDocsBundleTask : DefaultTask() {
|
||||
|
||||
// Process Crowdin locale directories: docs/{qualifier}/user/*.md
|
||||
// Crowdin %android_code% produces: fr, pt-rBR, zh-rCN, zh-rTW
|
||||
// Skip "en" since English sources are handled above.
|
||||
val localePattern = Regex("^[a-z]{2,3}(-r[A-Z]{2})?$")
|
||||
src.listFiles { f -> f.isDirectory && localePattern.matches(f.name) }
|
||||
src.listFiles { f -> f.isDirectory && localePattern.matches(f.name) && f.name != "en" }
|
||||
?.sortedBy { it.name }
|
||||
?.forEach { localeDir ->
|
||||
val locale = localeDir.name
|
||||
@@ -198,7 +200,7 @@ abstract class GenerateDocsBundleTask : DefaultTask() {
|
||||
File(cssDir, "docs.css").writeText(generateCss())
|
||||
|
||||
// Write locales manifest (for consumers that need to know available translations)
|
||||
val localesManifest = src.listFiles { f -> f.isDirectory && localePattern.matches(f.name) }
|
||||
val localesManifest = src.listFiles { f -> f.isDirectory && localePattern.matches(f.name) && f.name != "en" }
|
||||
?.map { it.name }?.sorted() ?: emptyList()
|
||||
val manifestFile = File(out, "locales.json")
|
||||
manifestFile.writeText(localesManifest.joinToString(", ", "[", "]") { "\"$it\"" })
|
||||
@@ -258,7 +260,7 @@ abstract class GenerateDocsBundleTask : DefaultTask() {
|
||||
.replace(Regex("^---[\\s\\S]*?---\\s*", RegexOption.MULTILINE), "")
|
||||
.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
val dir = if (locale == "ar") "rtl" else "ltr"
|
||||
// Locale pages are one level deeper: docs/{locale}/user/foo.html vs docs/user/foo.html
|
||||
// Locale pages are one level deeper: docs/{locale}/user/foo.html vs docs/en/user/foo.html
|
||||
val cssPath = if (locale != "en") "../../styles/docs.css" else "../styles/docs.css"
|
||||
return """
|
||||
|<!DOCTYPE html>
|
||||
|
||||
+3
-2
@@ -11,10 +11,11 @@ files:
|
||||
- source: /fastlane/metadata/android/en-US/changelogs/default.txt
|
||||
translation: /fastlane/metadata/android/%locale%/changelogs/%original_file_name%
|
||||
# In-app docs — user guide only (developer guide is English-only)
|
||||
# English sources live under docs/en/; translations land at docs/{android_code}/
|
||||
# Uses %android_code% to output Android/CMP qualifier format directly (pt-rBR, zh-rCN, fr)
|
||||
- source: /docs/user/*.md
|
||||
- source: /docs/en/user/*.md
|
||||
translation: /docs/%android_code%/user/%original_file_name%
|
||||
type: md
|
||||
- source: /docs/index.md
|
||||
- source: /docs/en/index.md
|
||||
translation: /docs/%android_code%/%original_file_name%
|
||||
type: md
|
||||
@@ -0,0 +1,45 @@
|
||||
# Documentation Structure
|
||||
|
||||
This directory contains the source documentation for the Meshtastic Android/Desktop/iOS app.
|
||||
It serves three consumers:
|
||||
|
||||
1. **In-app docs browser** — bundled via Compose Resources at build time
|
||||
2. **Jekyll site** — GitHub Pages (this directory is the Jekyll source root)
|
||||
3. **meshtastic.org** — Docusaurus sync (upstream consumption)
|
||||
|
||||
## Locale Layout
|
||||
|
||||
```
|
||||
docs/
|
||||
├── _config.yml, _data/, _layouts/, _sass/ ← Jekyll site infrastructure
|
||||
├── en/ ← English source (edit here)
|
||||
│ ├── user/ ← User Guide pages
|
||||
│ ├── developer/ ← Developer Guide pages
|
||||
│ ├── index.md ← Site home page
|
||||
│ ├── user.md ← User Guide nav parent
|
||||
│ ├── developer.md ← Developer Guide nav parent
|
||||
│ └── translations.md ← Translations landing page
|
||||
├── fr-rFR/ ← French (Crowdin-generated)
|
||||
│ └── user/ ← Translated user guide
|
||||
├── de-rDE/ ← German (Crowdin-generated)
|
||||
│ └── user/
|
||||
└── ... ← Other locales
|
||||
```
|
||||
|
||||
## Editing Guidelines
|
||||
|
||||
- **English source**: Edit files under `docs/en/`. These are the authoritative source.
|
||||
- **Translations**: Do **not** edit files in locale folders directly. They are auto-generated
|
||||
by [Crowdin](https://crowdin.com/project/meshtastic-android) and will be overwritten on sync.
|
||||
Contribute translations via Crowdin instead.
|
||||
- **Adding a page**: Create the `.md` file in `docs/en/user/` or `docs/en/developer/`, then
|
||||
register it in `feature/docs/.../DocBundleLoader.kt` for in-app bundling.
|
||||
|
||||
## How Translations Work
|
||||
|
||||
1. English source files (`docs/en/user/*.md`) are uploaded to Crowdin as translation sources
|
||||
2. Volunteers translate via the Crowdin web UI
|
||||
3. Crowdin PRs land translated files at `docs/{android_code}/user/*.md` (e.g., `fr-rFR`, `pt-rBR`)
|
||||
4. At build time, the Gradle `syncTranslatedDocsToComposeResources` task bundles them into
|
||||
locale-qualified Compose Resources for the in-app reader
|
||||
5. The in-app `DocBundleLoader` tries the user's locale first, then falls back to English
|
||||
+41
-40
@@ -28,12 +28,12 @@ color_scheme: meshtastic
|
||||
# Default front-matter for pages in subdirectories
|
||||
defaults:
|
||||
- scope:
|
||||
path: "user/"
|
||||
path: "en/user/"
|
||||
values:
|
||||
parent: User Guide
|
||||
layout: default
|
||||
- scope:
|
||||
path: "developer/"
|
||||
path: "en/developer/"
|
||||
values:
|
||||
parent: Developer Guide
|
||||
layout: default
|
||||
@@ -41,229 +41,229 @@ defaults:
|
||||
# They use a dedicated locale layout with a back-link to the English version.
|
||||
# Auto-generated from Android app locales (values-* resource dirs).
|
||||
- scope:
|
||||
path: "ar/"
|
||||
path: "ar"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: ar
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "be/"
|
||||
path: "be"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: be
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "bg/"
|
||||
path: "bg"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: bg
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "ca/"
|
||||
path: "ca"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: ca
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "cs/"
|
||||
path: "cs"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: cs
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "de/"
|
||||
path: "de"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: de
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "el/"
|
||||
path: "el"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: el
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "es/"
|
||||
path: "es"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: es
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "et/"
|
||||
path: "et"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: et
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "fi/"
|
||||
path: "fi"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: fi
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "fr/"
|
||||
path: "fr"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: fr
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "ga/"
|
||||
path: "ga"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: ga
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "gl/"
|
||||
path: "gl"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: gl
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "he/"
|
||||
path: "he"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: he
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "hr/"
|
||||
path: "hr"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: hr
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "ht/"
|
||||
path: "ht"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: ht
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "hu/"
|
||||
path: "hu"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: hu
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "is/"
|
||||
path: "is"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: is
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "it/"
|
||||
path: "it"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: it
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "ja/"
|
||||
path: "ja"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: ja
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "ko/"
|
||||
path: "ko"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: ko
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "lt/"
|
||||
path: "lt"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: lt
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "nl/"
|
||||
path: "nl"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: nl
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "no/"
|
||||
path: "no"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: no
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "pl/"
|
||||
path: "pl"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: pl
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "pt/"
|
||||
path: "pt"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: pt
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "pt-rBR/"
|
||||
path: "pt-rBR"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: pt-rBR
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "ro/"
|
||||
path: "ro"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: ro
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "ru/"
|
||||
path: "ru"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: ru
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "sk/"
|
||||
path: "sk"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: sk
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "sl/"
|
||||
path: "sl"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: sl
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "sq/"
|
||||
path: "sq"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: sq
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "sr/"
|
||||
path: "sr"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: sr
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "sv/"
|
||||
path: "sv"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: sv
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "tr/"
|
||||
path: "tr"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: tr
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "uk/"
|
||||
path: "uk"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: uk
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "zh-rCN/"
|
||||
path: "zh-rCN"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: zh-rCN
|
||||
nav_exclude: true
|
||||
- scope:
|
||||
path: "zh-rTW/"
|
||||
path: "zh-rTW"
|
||||
values:
|
||||
layout: locale_page
|
||||
locale: zh-rTW
|
||||
@@ -285,5 +285,6 @@ exclude:
|
||||
- Gemfile
|
||||
- Gemfile.lock
|
||||
- assets/screenshots/.gitkeep
|
||||
- README.md
|
||||
- "*.sh"
|
||||
|
||||
@@ -7,7 +7,8 @@ layout: default
|
||||
{% assign page_path = page.path %}
|
||||
{% assign path_parts = page_path | split: "/" %}
|
||||
{% assign remaining_parts = path_parts | slice: 1, path_parts.size %}
|
||||
{% assign en_path = remaining_parts | join: "/" | replace: ".md", "" %}
|
||||
{% assign en_relative = remaining_parts | join: "/" | replace: ".md", "" %}
|
||||
{% assign en_path = "en/" | append: en_relative %}
|
||||
|
||||
<div class="locale-page-banner" {% if locale_info.dir == "rtl" %}dir="rtl"{% endif %}>
|
||||
<p class="locale-notice">
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -59,24 +59,16 @@ kotlin {
|
||||
*/
|
||||
val syncDocsToComposeResources by
|
||||
tasks.registering(Sync::class) {
|
||||
description = "Syncs docs/ markdown source into composeResources for in-app bundling"
|
||||
description = "Syncs docs/en/ markdown source into composeResources for in-app bundling"
|
||||
group = "docs"
|
||||
|
||||
val docsSourceDir = rootProject.layout.projectDirectory.dir("docs")
|
||||
val docsEnDir = rootProject.layout.projectDirectory.dir("docs/en")
|
||||
val screenshotsDir = rootProject.layout.projectDirectory.dir("docs/screenshots")
|
||||
val composeResourcesTarget = layout.projectDirectory.dir("src/commonMain/composeResources/files/docs")
|
||||
|
||||
from(docsSourceDir) {
|
||||
from(docsEnDir) {
|
||||
include("user/**/*.md")
|
||||
include("developer/**/*.md")
|
||||
// Exclude Jekyll/site-only files that are not needed in-app
|
||||
exclude("_config.yml")
|
||||
exclude("_data/**")
|
||||
exclude("_includes/**")
|
||||
exclude("_layouts/**")
|
||||
exclude("index.md")
|
||||
exclude("assets/**")
|
||||
exclude("Gemfile*")
|
||||
}
|
||||
|
||||
// FR-038: Bundle screenshots into assets/screenshots/ to match markdown image paths.
|
||||
@@ -117,8 +109,7 @@ val syncTranslatedDocsToComposeResources by
|
||||
from(docsDir) {
|
||||
// Crowdin outputs dirs in Android qualifier format (fr, pt-rBR, zh-rCN)
|
||||
include("*/user/**/*.md")
|
||||
exclude("user/**")
|
||||
exclude("developer/**")
|
||||
exclude("en/**")
|
||||
exclude("_*/**")
|
||||
exclude("assets/**")
|
||||
exclude("screenshots/**")
|
||||
@@ -133,6 +124,8 @@ val syncTranslatedDocsToComposeResources by
|
||||
if (segments.size >= 3) {
|
||||
val qualifier = segments[0]
|
||||
val rest = segments.drop(1).joinToString("/")
|
||||
// Output: files/{locale}/docs/user/page.md
|
||||
// English source lives at: docs/en/$rest
|
||||
path = "$qualifier/docs/$rest"
|
||||
}
|
||||
}
|
||||
|
||||
+26
-26
@@ -241,7 +241,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"onboarding",
|
||||
CoreRes.string.doc_title_onboarding,
|
||||
CoreRes.string.doc_keywords_onboarding,
|
||||
"docs/user/onboarding.html",
|
||||
"en/user/onboarding.html",
|
||||
1,
|
||||
listOf("first-launch", "setup", "intro"),
|
||||
3200,
|
||||
@@ -251,7 +251,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"connections",
|
||||
CoreRes.string.doc_title_connections,
|
||||
CoreRes.string.doc_keywords_connections,
|
||||
"docs/user/connections.html",
|
||||
"en/user/connections.html",
|
||||
2,
|
||||
listOf("bluetooth", "usb", "tcp", "pairing"),
|
||||
4100,
|
||||
@@ -261,7 +261,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"messages-and-channels",
|
||||
CoreRes.string.doc_title_messages,
|
||||
CoreRes.string.doc_keywords_messages,
|
||||
"docs/user/messages-and-channels.html",
|
||||
"en/user/messages-and-channels.html",
|
||||
3,
|
||||
listOf("channels", "direct-messages", "messaging", "conversations"),
|
||||
4500,
|
||||
@@ -271,7 +271,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"nodes",
|
||||
CoreRes.string.doc_title_nodes,
|
||||
CoreRes.string.doc_keywords_nodes,
|
||||
"docs/user/nodes.html",
|
||||
"en/user/nodes.html",
|
||||
4,
|
||||
listOf("node-list", "mesh-nodes", "peers"),
|
||||
3800,
|
||||
@@ -281,7 +281,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"node-metrics",
|
||||
CoreRes.string.doc_title_node_metrics,
|
||||
CoreRes.string.doc_keywords_node_metrics,
|
||||
"docs/user/node-metrics.html",
|
||||
"en/user/node-metrics.html",
|
||||
5,
|
||||
listOf("metrics", "telemetry", "device-metrics", "signal"),
|
||||
5200,
|
||||
@@ -291,7 +291,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"map-and-waypoints",
|
||||
CoreRes.string.doc_title_map,
|
||||
CoreRes.string.doc_keywords_map,
|
||||
"docs/user/map-and-waypoints.html",
|
||||
"en/user/map-and-waypoints.html",
|
||||
6,
|
||||
listOf("map", "waypoints", "gps", "location"),
|
||||
3600,
|
||||
@@ -301,7 +301,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"settings-radio-user",
|
||||
CoreRes.string.doc_title_settings_radio,
|
||||
CoreRes.string.doc_keywords_settings_radio,
|
||||
"docs/user/settings-radio-user.html",
|
||||
"en/user/settings-radio-user.html",
|
||||
7,
|
||||
listOf("settings", "radio-config", "user-config", "lora"),
|
||||
6800,
|
||||
@@ -311,7 +311,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"settings-module-admin",
|
||||
CoreRes.string.doc_title_settings_module,
|
||||
CoreRes.string.doc_keywords_settings_module,
|
||||
"docs/user/settings-module-admin.html",
|
||||
"en/user/settings-module-admin.html",
|
||||
8,
|
||||
listOf("modules", "module-config", "administration"),
|
||||
5500,
|
||||
@@ -321,7 +321,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"telemetry-and-sensors",
|
||||
CoreRes.string.doc_title_telemetry,
|
||||
CoreRes.string.doc_keywords_telemetry,
|
||||
"docs/user/telemetry-and-sensors.html",
|
||||
"en/user/telemetry-and-sensors.html",
|
||||
9,
|
||||
listOf("sensors", "environment", "weather", "power-metrics"),
|
||||
4800,
|
||||
@@ -331,7 +331,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"tak",
|
||||
CoreRes.string.doc_title_tak,
|
||||
CoreRes.string.doc_keywords_tak,
|
||||
"docs/user/tak.html",
|
||||
"en/user/tak.html",
|
||||
10,
|
||||
listOf("tak", "atak", "team-awareness-kit"),
|
||||
2400,
|
||||
@@ -341,7 +341,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"mqtt",
|
||||
CoreRes.string.doc_title_mqtt,
|
||||
CoreRes.string.doc_keywords_mqtt,
|
||||
"docs/user/mqtt.html",
|
||||
"en/user/mqtt.html",
|
||||
11,
|
||||
listOf("mqtt", "internet-bridge", "broker"),
|
||||
4200,
|
||||
@@ -351,7 +351,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"discovery",
|
||||
CoreRes.string.doc_title_discovery,
|
||||
CoreRes.string.doc_keywords_discovery,
|
||||
"docs/user/discovery.html",
|
||||
"en/user/discovery.html",
|
||||
12,
|
||||
listOf("mesh-discovery", "local-discovery", "network-scan"),
|
||||
2800,
|
||||
@@ -361,7 +361,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"firmware",
|
||||
CoreRes.string.doc_title_firmware,
|
||||
CoreRes.string.doc_keywords_firmware,
|
||||
"docs/user/firmware.html",
|
||||
"en/user/firmware.html",
|
||||
13,
|
||||
listOf("firmware", "update", "ota", "flash"),
|
||||
3400,
|
||||
@@ -371,7 +371,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"desktop",
|
||||
CoreRes.string.doc_title_desktop,
|
||||
CoreRes.string.doc_keywords_desktop,
|
||||
"docs/user/desktop.html",
|
||||
"en/user/desktop.html",
|
||||
14,
|
||||
listOf("desktop", "linux", "macos", "windows", "jvm"),
|
||||
3900,
|
||||
@@ -381,7 +381,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"signal-meter",
|
||||
CoreRes.string.doc_title_signal_meter,
|
||||
CoreRes.string.doc_keywords_signal_meter,
|
||||
"docs/user/signal-meter.html",
|
||||
"en/user/signal-meter.html",
|
||||
15,
|
||||
listOf("signal-quality", "signal-strength", "rssi", "snr"),
|
||||
3500,
|
||||
@@ -391,7 +391,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"units-and-locale",
|
||||
CoreRes.string.doc_title_units,
|
||||
CoreRes.string.doc_keywords_units,
|
||||
"docs/user/units-and-locale.html",
|
||||
"en/user/units-and-locale.html",
|
||||
16,
|
||||
listOf("measurement", "units", "locale", "metric", "imperial"),
|
||||
3800,
|
||||
@@ -401,7 +401,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"translate",
|
||||
CoreRes.string.doc_title_translate,
|
||||
CoreRes.string.doc_keywords_translate,
|
||||
"docs/user/translate.html",
|
||||
"en/user/translate.html",
|
||||
17,
|
||||
listOf("crowdin", "localization", "language", "i18n", "contribute"),
|
||||
3700,
|
||||
@@ -433,7 +433,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"architecture",
|
||||
"Architecture",
|
||||
"developer",
|
||||
"docs/developer/architecture.html",
|
||||
"en/developer/architecture.html",
|
||||
1,
|
||||
listOf("architecture", "kmp", "module", "layer", "core", "feature", "compose"),
|
||||
listOf("layers", "module-architecture", "kmp"),
|
||||
@@ -444,7 +444,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"codebase",
|
||||
"Codebase",
|
||||
"developer",
|
||||
"docs/developer/codebase.html",
|
||||
"en/developer/codebase.html",
|
||||
2,
|
||||
listOf("codebase", "repository", "layout", "gradle", "build", "namespace", "convention"),
|
||||
listOf("repository-layout", "project-structure", "source-code"),
|
||||
@@ -455,7 +455,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"adding-a-feature-module",
|
||||
"Adding a Feature Module",
|
||||
"developer",
|
||||
"docs/developer/adding-a-feature-module.html",
|
||||
"en/developer/adding-a-feature-module.html",
|
||||
3,
|
||||
listOf("module", "feature", "new", "create", "plugin", "di", "koin"),
|
||||
listOf("new-module", "feature-module", "module-guide"),
|
||||
@@ -466,7 +466,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"navigation-and-deep-links",
|
||||
"Navigation & Deep Links",
|
||||
"developer",
|
||||
"docs/developer/navigation-and-deep-links.html",
|
||||
"en/developer/navigation-and-deep-links.html",
|
||||
4,
|
||||
listOf("navigation", "deeplink", "route", "navkey", "backstack", "typed"),
|
||||
listOf("deeplinks", "navigation-3", "routes"),
|
||||
@@ -477,7 +477,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"transport",
|
||||
"Transport",
|
||||
"developer",
|
||||
"docs/developer/transport.html",
|
||||
"en/developer/transport.html",
|
||||
5,
|
||||
listOf("transport", "ble", "serial", "tcp", "radio", "connection"),
|
||||
listOf("ble", "serial", "tcp", "radio-transport"),
|
||||
@@ -488,7 +488,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"persistence",
|
||||
"Persistence",
|
||||
"developer",
|
||||
"docs/developer/persistence.html",
|
||||
"en/developer/persistence.html",
|
||||
6,
|
||||
listOf("room", "database", "datastore", "prefs", "storage", "migration"),
|
||||
listOf("room", "database", "datastore", "prefs"),
|
||||
@@ -499,7 +499,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"testing",
|
||||
"Testing",
|
||||
"developer",
|
||||
"docs/developer/testing.html",
|
||||
"en/developer/testing.html",
|
||||
7,
|
||||
listOf("test", "unit", "screenshot", "compose", "roborazzi", "ci"),
|
||||
listOf("tests", "unit-tests", "screenshot-tests"),
|
||||
@@ -510,7 +510,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"contributing",
|
||||
"Contributing",
|
||||
"developer",
|
||||
"docs/developer/contributing.html",
|
||||
"en/developer/contributing.html",
|
||||
8,
|
||||
listOf("contributing", "pull-request", "branch", "commit", "style", "pr"),
|
||||
listOf("contributing", "pull-request", "branch-naming"),
|
||||
@@ -521,7 +521,7 @@ class DefaultDocBundleLoader : DocBundleLoader {
|
||||
"measurement",
|
||||
"Measurement & Formatting",
|
||||
"developer",
|
||||
"docs/developer/measurement.html",
|
||||
"en/developer/measurement.html",
|
||||
9,
|
||||
listOf("formatter", "metric", "number", "locale", "temperature", "conversion", "api"),
|
||||
listOf("metric-formatter", "number-formatter", "measurement"),
|
||||
|
||||
@@ -12,7 +12,7 @@ const path = require("path");
|
||||
const { forEachDocPage } = require("./lib/frontmatter");
|
||||
|
||||
const REPO_ROOT = path.resolve(process.argv[2] || ".");
|
||||
const DOCS_DIR = path.join(REPO_ROOT, "docs");
|
||||
const DOCS_DIR = path.join(REPO_ROOT, "docs", "en");
|
||||
|
||||
// Map of feature module directory names to expected doc page slugs.
|
||||
// Modules not listed here are considered internal (no user-facing docs required).
|
||||
|
||||
@@ -13,7 +13,7 @@ const { parseFrontmatter, forEachDocPage } = require("./lib/frontmatter");
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const positional = args.filter(a => !a.startsWith("--"));
|
||||
const DOCS_DIR = path.resolve(positional[0] || "docs");
|
||||
const DOCS_DIR = path.resolve(positional[0] || path.join("docs", "en"));
|
||||
|
||||
const maxAgeArg = args.find(a => a.startsWith("--max-age-days="));
|
||||
const MAX_AGE_DAYS = maxAgeArg ? parseInt(maxAgeArg.split("=")[1], 10) : 180;
|
||||
|
||||
@@ -37,8 +37,8 @@ const IMAGE_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".gif", ".svg", ".web
|
||||
const ANDROID_REPO_ROOT = positionalArgs.length > 0
|
||||
? path.resolve(positionalArgs[0])
|
||||
: path.resolve(__dirname, "..");
|
||||
const SRC_DOCS_DIR = path.join(ANDROID_REPO_ROOT, "docs");
|
||||
const SRC_SCREENSHOTS_DIR = path.join(SRC_DOCS_DIR, "assets", "screenshots");
|
||||
const SRC_DOCS_DIR = path.join(ANDROID_REPO_ROOT, "docs", "en");
|
||||
const SRC_SCREENSHOTS_DIR = path.join(ANDROID_REPO_ROOT, "docs", "assets", "screenshots");
|
||||
|
||||
if (!fs.existsSync(SRC_DOCS_DIR)) {
|
||||
console.error(`Error: docs directory not found at ${SRC_DOCS_DIR}`);
|
||||
|
||||
@@ -11,7 +11,9 @@ const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { discoverSlugs, forEachDocPage } = require("./lib/frontmatter");
|
||||
|
||||
const DOCS_DIR = path.resolve(process.argv[2] || "docs");
|
||||
const DOCS_DIR = path.resolve(process.argv[2] || path.join("docs", "en"));
|
||||
// Assets (screenshots) live at docs/ root, not inside the en/ locale folder
|
||||
const DOCS_ROOT = path.resolve(DOCS_DIR, "..");
|
||||
const IMAGE_EXTS = new Set([".png", ".jpg", ".jpeg", ".gif", ".svg", ".webp"]);
|
||||
|
||||
// Collect known page slugs from both sections
|
||||
@@ -64,7 +66,7 @@ forEachDocPage(DOCS_DIR, (filePath, slug, section) => {
|
||||
if (/^https?:/.test(imgPath)) continue;
|
||||
|
||||
const resolved = imgPath.startsWith("/")
|
||||
? path.join(DOCS_DIR, imgPath)
|
||||
? path.join(DOCS_ROOT, imgPath)
|
||||
: path.resolve(path.dirname(filePath), imgPath);
|
||||
if (!fs.existsSync(resolved)) {
|
||||
console.log(` ERROR: ${section}/${slug}.md:${lineNum} — missing image '${imgPath}'`);
|
||||
|
||||
Reference in new issue
Block a user