diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 67fe52e..7bc2af8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,6 +52,31 @@ storage_state = true Declare the **narrowest** HTTP allowlist that works — it's shown to the user before install and enforced at runtime. +### Translating what the user reads + +WaveFlow ships in 17 languages, but your manifest lives outside its translation files — so the app can only show what you write here. Add the translations in a **sibling `*_i18n` table**, leaving the English string exactly where it is: + +```toml +[plugin] +description = "Fetches Apple Music's animated album covers." + +[plugin.description_i18n] +fr = "Récupère les pochettes animées d'Apple Music." +de = "Holt animierte Albumcover von Apple Music." + +[[options]] +key = "prefer_hevc" +type = "bool" +label = "Prefer 4K HEVC covers" + +[options.label_i18n] +fr = "Préférer les pochettes 4K HEVC" +``` + +Locale codes: `en` `fr` `de` `es` `it` `nl` `pt` `pt-BR` `ru` `tr` `id` `ja` `ko` `zh-CN` `zh-TW` `ar` `hi`. Any subset is fine — WaveFlow falls back exact code → base language (`pt-BR` → `pt`) → `en` → any entry. Keep brand and codec tokens (`WaveFlow`, `Apple Music`, `Last.fm`, `HEVC`…) verbatim. + +> **Do not replace the string with a language map.** WaveFlow ≥ 1.8.0 also accepts `[plugin.description]` as an inline `en = … / fr = …` table, but a host predating that expects a string, errors on the table, and **drops your plugin entirely**. The sibling form is ignored by old hosts and understood by new ones, so it costs you nothing and needs no `min_app_version` bump. + ## 4. Release it Tag a semver release in your plugin repo. Copy [`templates/plugin-release.yml`](templates/plugin-release.yml) into `.github/workflows/` — it is a **single job** (no OS matrix) that: @@ -68,6 +93,7 @@ Open a PR against this repo adding your entry to [`registry.json`](registry.json - `version` = the release tag (without `v`). - `blake3` = the hash the release workflow printed. **This is what the app verifies.** Get it wrong and installs fail closed. - `permissions` = a byte-for-byte mirror of your `manifest.toml` `[permissions]`. +- `description` = a plain string, **always**. `registry.json` is one document fetched by every WaveFlow ever installed; an older build that finds an object here fails to decode the entire catalogue from all three delivery paths and its store goes dark — for every plugin, not just yours. Translations go in the optional `description_i18n` map next to it, which old builds ignore. CI validates your entry against [the schema](schema/registry.schema.json). Once merged, your plugin appears in every user's in-app store within minutes (raw.githubusercontent + jsDelivr are the delivery paths). diff --git a/README.md b/README.md index 4ec33f0..8bbedc9 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,9 @@ Every entry is validated against [`schema/registry.schema.json`](schema/registry "id": "apple-artwork", "name": "Apple Motion Artwork", "description": "Fetches Apple Music's animated album covers and plays them behind the now-playing view.", + "description_i18n": { + "fr": "Récupère les pochettes animées d'Apple Music et les affiche derrière la vue En cours de lecture." + }, "author": "InstaZDLL", "repo": "InstaZDLL/waveflow-plugin-apple-artwork", "homepage": "https://github.com/InstaZDLL/waveflow-plugin-apple-artwork", diff --git a/registry.json b/registry.json index 485c99c..f828ffb 100644 --- a/registry.json +++ b/registry.json @@ -6,6 +6,24 @@ "id": "apple-artwork", "name": "Apple Motion Artwork", "description": "Animated album covers from Apple Music, rendered behind the now-playing view.", + "description_i18n": { + "fr": "Pochettes d'album animées depuis Apple Music, affichées derrière la vue En cours de lecture.", + "de": "Animierte Albumcover aus Apple Music, hinter der Ansicht „Wird gespielt“ dargestellt.", + "es": "Portadas de álbum animadas de Apple Music, mostradas detrás de la vista Reproduciendo ahora.", + "it": "Copertine animate degli album da Apple Music, mostrate dietro la vista In riproduzione.", + "nl": "Geanimeerde albumhoezen van Apple Music, weergegeven achter de weergave Speelt nu.", + "pt": "Capas de álbum animadas do Apple Music, apresentadas por trás da vista Agora a reproduzir.", + "pt-BR": "Capas de álbum animadas do Apple Music, exibidas atrás da tela Tocando agora.", + "ru": "Анимированные обложки альбомов из Apple Music, отображаемые позади экрана «Сейчас играет».", + "tr": "Apple Music'ten animasyonlu albüm kapakları, Şimdi çalıyor görünümünün arkasında gösterilir.", + "id": "Sampul album animasi dari Apple Music, ditampilkan di belakang tampilan Sedang diputar.", + "ja": "Apple Music のアニメーションアルバムカバーを「再生中」画面の背景に表示します。", + "ko": "Apple Music의 애니메이션 앨범 커버를 '지금 재생 중' 화면 뒤에 표시합니다.", + "zh-CN": "来自 Apple Music 的动态专辑封面,显示在“正在播放”视图后方。", + "zh-TW": "來自 Apple Music 的動態專輯封面,顯示於「現在播放」畫面後方。", + "ar": "أغلفة ألبومات متحركة من Apple Music، تُعرض خلف واجهة «قيد التشغيل».", + "hi": "Apple Music से एनिमेटेड एल्बम कवर, \"अब चल रहा है\" व्यू के पीछे दिखाए जाते हैं।" + }, "author": "InstaZDLL", "repo": "InstaZDLL/waveflow-plugin-apple-artwork", "homepage": "https://github.com/InstaZDLL/waveflow-plugin-apple-artwork", diff --git a/schema/registry.schema.json b/schema/registry.schema.json index 6f14c0a..63dae83 100644 --- a/schema/registry.schema.json +++ b/schema/registry.schema.json @@ -30,7 +30,17 @@ "description": "Stable plugin id. MUST equal the install-dir name and the manifest.toml [plugin] id — the app refuses a mismatch." }, "name": { "type": "string", "minLength": 1, "description": "Human-readable display name." }, - "description": { "type": "string", "minLength": 1, "description": "One or two sentences shown on the store card." }, + "description": { "type": "string", "minLength": 1, "description": "One or two sentences shown on the store card. MUST stay a plain string: this file is fetched by every WaveFlow ever installed, and a build predating localized descriptions fails to decode the whole catalogue if it finds an object here — its store goes dark. Translations belong in description_i18n." }, + "description_i18n": { + "type": "object", + "minProperties": 1, + "additionalProperties": { "type": "string", "minLength": 1 }, + "propertyNames": { + "enum": ["en", "fr", "de", "es", "it", "nl", "pt", "pt-BR", "ru", "tr", "id", "ja", "ko", "zh-CN", "zh-TW", "ar", "hi"], + "description": "Exactly the codes WaveFlow ships, case included. A permissive pattern would wave through a typo like \"pt-br\" or \"jp\": the app looks the key up verbatim, so the entry would simply never be shown, silently. Add a code here when WaveFlow adds a locale." + }, + "description": "Translations of `description`, keyed by the app's locale codes (en, fr, de, es, it, nl, pt, pt-BR, ru, tr, id, ja, ko, zh-CN, zh-TW, ar, hi). WaveFlow 1.8.0+ shows the entry in the user's language and falls back exact code → base language → en → any entry; older builds ignore this field and render `description` as before. Keep brand tokens (WaveFlow, Apple Music, Last.fm, HEVC…) verbatim." + }, "author": { "type": "string", "minLength": 1 }, "repo": { "type": "string",