Speak the editor in each person's Home Assistant language: every text in the editor section of en.json, the mockup in the screens' language, and one Language & region card for all screens

- vue-i18n 11 with the Composition API: English comes with the page, any other language loads the first time it is
  needed from screen_manager/translations, and a text a language lacks shows in English. The build keeps only _meta
  and editor of each file (vite.config.ts), never the screens' or the add-on's texts.
- The editor follows the language of the user's Home Assistant profile (<html lang> of Home Assistant's page), else
  the browser's; plural forms follow the file's _meta.plural, with the screens' rules.
- Every request tells the add-on the editor's language (X-ESP-Screens-Language), so its own words can follow it.
- The mockup draws the screens' words (Unavailable, Page 2 ›, the date, "5 min ago") in the screens' language, with
  their clock and number format.
- Settings → Language & region: the screen language, time format and number format for every screen, with the user's
  own profile offered when it differs. The per-screen clock choice goes; the top bar points there. A screen that
  still needs the new language says so in its update badge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Max Gramser
2026-09-19 14:40:29 +02:00
parent c2cf3391d6
commit 1dc2eab0cf
58 changed files with 2573 additions and 672 deletions
+90 -1
View File
@@ -8,7 +8,8 @@
"name": "esp-screens-editor",
"version": "0.0.0",
"dependencies": {
"vue": "^3.5.18"
"vue": "^3.5.18",
"vue-i18n": "^11.4.12"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
@@ -637,6 +638,67 @@
"node": ">=18"
}
},
"node_modules/@intlify/core-base": {
"version": "11.4.12",
"resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-11.4.12.tgz",
"integrity": "sha512-tvYUWgMJmk+UvLFa7ck8uRQ9m19tTI9B2e01KCAjBV7+HN2zFLnnORvMO85hM1P8DIw4MTvot1ZSBUdoR+F6jA==",
"license": "MIT",
"dependencies": {
"@intlify/devtools-types": "11.4.12",
"@intlify/message-compiler": "11.4.12",
"@intlify/shared": "11.4.12"
},
"engines": {
"node": ">= 22"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/devtools-types": {
"version": "11.4.12",
"resolved": "https://registry.npmjs.org/@intlify/devtools-types/-/devtools-types-11.4.12.tgz",
"integrity": "sha512-Ctkcs8DQItaEL9HHdkyasFFcZFP59iBvZmrjiA7b72JFq/JlI6c6GPQHN7oEwbYTo8rndPMqNY7SX71aPm4MkA==",
"license": "MIT",
"dependencies": {
"@intlify/core-base": "11.4.12",
"@intlify/shared": "11.4.12"
},
"engines": {
"node": ">= 22"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/message-compiler": {
"version": "11.4.12",
"resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.4.12.tgz",
"integrity": "sha512-kBczk9r44fdBYnkC5tXRWa/UaA+e9NglXE3cX7jPnDd2nHzoFHYrKGfIbn8JFZpMA9omexZZo2WxOpTvlHdjsw==",
"license": "MIT",
"dependencies": {
"@intlify/shared": "11.4.12",
"source-map-js": "^1.0.2"
},
"engines": {
"node": ">= 22"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@intlify/shared": {
"version": "11.4.12",
"resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.4.12.tgz",
"integrity": "sha512-ojfehaXMFrGFcSnK3cJPaMxlrSXT8FwZUG9H4i+WKX4OFD4Yl1WKdTmfwoC0REnwIfTrnt1QhRtd8kwi/te6bQ==",
"license": "MIT",
"engines": {
"node": ">= 22"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz",
@@ -1270,6 +1332,12 @@
"@vue/shared": "3.5.43"
}
},
"node_modules/@vue/devtools-api": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
"integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
"license": "MIT"
},
"node_modules/@vue/language-core": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.3.11.tgz",
@@ -2541,6 +2609,27 @@
"dev": true,
"license": "MIT"
},
"node_modules/vue-i18n": {
"version": "11.4.12",
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-11.4.12.tgz",
"integrity": "sha512-yvArvvo3ErLKFNlQrZUGmRkxL/ctM5xFYtE9FxTKiE/PalWP1bnTopBgbSRGLluYEyYSNl1Pt8l2J7zVavbXww==",
"license": "MIT",
"dependencies": {
"@intlify/core-base": "11.4.12",
"@intlify/devtools-types": "11.4.12",
"@intlify/shared": "11.4.12",
"@vue/devtools-api": "^6.5.0"
},
"engines": {
"node": ">= 22"
},
"funding": {
"url": "https://github.com/sponsors/kazupon"
},
"peerDependencies": {
"vue": "^3.0.0"
}
},
"node_modules/vue-tsc": {
"version": "3.3.11",
"resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.3.11.tgz",