Weekdays that fit the weather columns, the top bar's own abbreviation, tile texts that fit, and a check that measures them
- The CYD's weather columns hold two letters beside the icon: every language has its own two-letter days (the CLDR's short width, Polish nd pn wt); French mar became nar there. check fails on a longer one. - The top bar takes the language's abbreviation (sam. 19 sept., Sa., 19. Sept.), English keeps Sa 19 Sep. - The editor's clock and date follow the screens: 7:05 PM in the top bar, 7:05 on the clock card. - A long weather word ends in an ellipsis before the days. - Tile lines that were cut on a screen are shorter (Zum Öffnen, Ouvrir, Otwórz, Sin imagen, ...); check measures them with the screens' font against the tile width of both boards. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -88,11 +88,13 @@ inline std::string ago_text(int64_t then, int64_t now) {
|
||||
return plural(txt::time_years_ago, n(31536000));
|
||||
}
|
||||
|
||||
// "Mo 14 Sep" in English, "ma 14 sep" in Dutch (screen.date.top_bar); day_of_week 1 is Sunday, as ESPHome counts.
|
||||
// "Mo 14 Sep" in English, "za 19 sep" in Dutch, "sam. 19 sept." in French (screen.date.top_bar, with the language's
|
||||
// abbreviation as {weekday} or its two letters as {weekday_min}); day_of_week 1 is Sunday, as ESPHome counts.
|
||||
inline std::string date_text(int day_of_week, int day_of_month, int month) {
|
||||
using namespace screen_text;
|
||||
if (day_of_week < 1 || day_of_week > 7 || month < 1 || month > 12) return "—";
|
||||
std::string text = fill(txt::date_top_bar, "weekday", tr(txt::date_weekdays_min + day_of_week - 1));
|
||||
std::string text = fill(txt::date_top_bar, "weekday", tr(txt::date_weekdays_short + day_of_week - 1));
|
||||
text = fill(text, "weekday_min", tr(txt::date_weekdays_min + day_of_week - 1));
|
||||
text = fill(text, "day", std::to_string(day_of_month));
|
||||
return fill(text, "month", tr(txt::date_months_short + month - 1));
|
||||
}
|
||||
|
||||
@@ -2617,7 +2617,9 @@ inline void render_forecast(Widgets &w,const Tile &t,bool large,int width,int he
|
||||
auto *icon=part_label(w,0,w.icon_font,0,y+(std::max(icon_h,temp_h)-icon_h)/2,icon_h+4,LV_TEXT_ALIGN_LEFT,t.available()?weather_icon(t.state):"\U000F0595");
|
||||
lv_obj_set_width(icon,lv_font_get_line_height(w.icon_font)+4);
|
||||
part_label(w,1,temp_font,icon_h+6,y+(std::max(icon_h,temp_h)-temp_h)/2,left-icon_h-6,LV_TEXT_ALIGN_LEFT,std::isfinite(t.current)?b:"");
|
||||
part_label(w,2,w.value_font,0,y+std::max(icon_h,temp_h)+2,left-4,LV_TEXT_ALIGN_LEFT,weather_text(t.state));
|
||||
// Home Assistant's word for the weather can be long ("częściowe zachmurzenie"): it ends in an ellipsis before the days.
|
||||
auto *condition=part_label(w,2,w.value_font,0,y+std::max(icon_h,temp_h)+2,left-4,LV_TEXT_ALIGN_LEFT,weather_text(t.state));
|
||||
if(lv_label_get_long_mode(condition)!=LV_LABEL_LONG_DOT)lv_label_set_long_mode(condition,LV_LABEL_LONG_DOT);
|
||||
int column=(width-left)/5;
|
||||
for(unsigned k=0;k<5;++k){
|
||||
static const Forecast no_day;int x=left+k*column;bool has=k<t.extra().forecast.size();const auto &f=has?t.extra().forecast[k]:no_day;
|
||||
|
||||
+5
-2
@@ -27,7 +27,9 @@ Three parts fill themselves. Don't change them by hand:
|
||||
[Home Assistant's translations](https://developers.home-assistant.io/docs/translations/); we pick it up from there.
|
||||
- `screen.date` holds day and month names and the order of a date. `screen.number` says how numbers are written.
|
||||
`screen.time.am` and `.pm` are the day periods. All of this comes from the Unicode CLDR, the same data every browser
|
||||
uses, through `tools/i18n.py cldr`. `screen.number.percent` follows Home Assistant's own rule: a space before `%` in
|
||||
uses, through `tools/i18n.py cldr`. One list is yours: `screen.date.weekdays_min`, the days of the weather card in
|
||||
two letters (`di`, `lu`, `ma` in French), because the small screen has room for no more. `cldr` starts a new language
|
||||
with a guess and then leaves the list alone. `screen.number.percent` follows Home Assistant's own rule: a space before `%` in
|
||||
Czech, German, Finnish, French, Slovak and Swedish, none in the other languages.
|
||||
- `_meta.clock`, 12 or 24 hours, also comes from the CLDR.
|
||||
|
||||
@@ -44,7 +46,8 @@ there is a `sv.json`, but already the Swedish 24-hour clock and `1 234,5`.
|
||||
- wrong words;
|
||||
- words that differ from the ones the Home Assistant app uses in your language (the Home Assistant app is the
|
||||
reference: *Dashboard*, *Automation*, *Entity* are what people know);
|
||||
- texts that are too long for a small screen.
|
||||
- texts that are too long for a small screen. `tools/i18n.py check` measures the line under a tile's name with the
|
||||
screens' own font and says when it doesn't fit; for the rest, compare with the English.
|
||||
3. Look at it for real, if you can. In ESP Screens open **Settings → Language & region** and choose your language. The
|
||||
editor itself follows the language of your Home Assistant profile. The screens show the new texts after their
|
||||
firmware update.
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+8
-8
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<title>ESP Screens</title>
|
||||
<script type="module" crossorigin src="./assets/index-CRR4xeFy.js"></script>
|
||||
<script type="module" crossorigin src="./assets/index-Cw-mwwtp.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="./assets/index-B7AxjXTR.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -142,7 +142,7 @@
|
||||
"hours_minutes": "{h} Std. {m}"
|
||||
},
|
||||
"tile": {
|
||||
"tap_to_open": "Zum Öffnen tippen",
|
||||
"tap_to_open": "Zum Öffnen",
|
||||
"page": "Seite {n}",
|
||||
"refused": "Abgelehnt",
|
||||
"command_sent": "Befehl gesendet...",
|
||||
@@ -214,7 +214,7 @@
|
||||
},
|
||||
"media": {
|
||||
"muted": "Stumm",
|
||||
"not_playing": "Keine Wiedergabe",
|
||||
"not_playing": "Nichts läuft",
|
||||
"loading": "Wird geladen"
|
||||
},
|
||||
"timer": {
|
||||
@@ -245,7 +245,7 @@
|
||||
"loading": "Bild wird geladen",
|
||||
"live": "Live",
|
||||
"recording": "Aufnahme",
|
||||
"tap_to_view": "Zum Ansehen tippen",
|
||||
"tap_to_view": "Ansehen",
|
||||
"no_image_yet": "Noch kein Bild"
|
||||
},
|
||||
"calibration": {
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
"Nov",
|
||||
"Dec"
|
||||
],
|
||||
"top_bar": "{weekday} {day} {month}",
|
||||
"top_bar": "{weekday_min} {day} {month}",
|
||||
"full": "{weekday} {day} {month}",
|
||||
"day_month": "{day} {month}",
|
||||
"weekday_time": "{weekday} {time}"
|
||||
|
||||
@@ -50,13 +50,13 @@
|
||||
"sáb"
|
||||
],
|
||||
"weekdays_min": [
|
||||
"dom",
|
||||
"lun",
|
||||
"mar",
|
||||
"mié",
|
||||
"jue",
|
||||
"vie",
|
||||
"sáb"
|
||||
"do",
|
||||
"lu",
|
||||
"ma",
|
||||
"mi",
|
||||
"ju",
|
||||
"vi",
|
||||
"sá"
|
||||
],
|
||||
"months": [
|
||||
"enero",
|
||||
@@ -214,7 +214,7 @@
|
||||
},
|
||||
"media": {
|
||||
"muted": "Silenciado",
|
||||
"not_playing": "No se reproduce nada",
|
||||
"not_playing": "Inactivo",
|
||||
"loading": "Cargando"
|
||||
},
|
||||
"timer": {
|
||||
@@ -246,7 +246,7 @@
|
||||
"live": "En directo",
|
||||
"recording": "Grabando",
|
||||
"tap_to_view": "Toca para ver",
|
||||
"no_image_yet": "Aún no hay imagen"
|
||||
"no_image_yet": "Sin imagen"
|
||||
},
|
||||
"calibration": {
|
||||
"title": "Sigue la calibración",
|
||||
|
||||
@@ -50,13 +50,13 @@
|
||||
"sam."
|
||||
],
|
||||
"weekdays_min": [
|
||||
"dim",
|
||||
"lun",
|
||||
"mar",
|
||||
"mer",
|
||||
"jeu",
|
||||
"ven",
|
||||
"sam"
|
||||
"di",
|
||||
"lu",
|
||||
"ma",
|
||||
"me",
|
||||
"je",
|
||||
"ve",
|
||||
"sa"
|
||||
],
|
||||
"months": [
|
||||
"janvier",
|
||||
@@ -142,7 +142,7 @@
|
||||
"hours_minutes": "{h} h {m}"
|
||||
},
|
||||
"tile": {
|
||||
"tap_to_open": "Touchez pour ouvrir",
|
||||
"tap_to_open": "Ouvrir",
|
||||
"page": "Page {n}",
|
||||
"refused": "Refusé",
|
||||
"command_sent": "Commande envoyée...",
|
||||
@@ -246,7 +246,7 @@
|
||||
"live": "En direct",
|
||||
"recording": "Enregistrement",
|
||||
"tap_to_view": "Touchez pour voir",
|
||||
"no_image_yet": "Pas encore d'image"
|
||||
"no_image_yet": "Pas d'image"
|
||||
},
|
||||
"calibration": {
|
||||
"title": "Suivez l'étalonnage",
|
||||
|
||||
@@ -50,13 +50,13 @@
|
||||
"sab"
|
||||
],
|
||||
"weekdays_min": [
|
||||
"dom",
|
||||
"lun",
|
||||
"mar",
|
||||
"mer",
|
||||
"gio",
|
||||
"ven",
|
||||
"sab"
|
||||
"do",
|
||||
"lu",
|
||||
"ma",
|
||||
"me",
|
||||
"gi",
|
||||
"ve",
|
||||
"sa"
|
||||
],
|
||||
"months": [
|
||||
"gennaio",
|
||||
@@ -214,7 +214,7 @@
|
||||
},
|
||||
"media": {
|
||||
"muted": "Muto",
|
||||
"not_playing": "Nessuna riproduzione",
|
||||
"not_playing": "Inattivo",
|
||||
"loading": "Caricamento"
|
||||
},
|
||||
"timer": {
|
||||
@@ -246,7 +246,7 @@
|
||||
"live": "Dal vivo",
|
||||
"recording": "Registrazione",
|
||||
"tap_to_view": "Tocca per vedere",
|
||||
"no_image_yet": "Ancora nessuna immagine"
|
||||
"no_image_yet": "Niente immagine"
|
||||
},
|
||||
"calibration": {
|
||||
"title": "Segui la calibrazione",
|
||||
|
||||
@@ -245,7 +245,7 @@
|
||||
"loading": "Beeld laden",
|
||||
"live": "Live",
|
||||
"recording": "Neemt op",
|
||||
"tap_to_view": "Tik om te bekijken",
|
||||
"tap_to_view": "Tik om te kijken",
|
||||
"no_image_yet": "Nog geen beeld"
|
||||
},
|
||||
"calibration": {
|
||||
|
||||
@@ -50,13 +50,13 @@
|
||||
"sob."
|
||||
],
|
||||
"weekdays_min": [
|
||||
"nie",
|
||||
"pon",
|
||||
"nd",
|
||||
"pn",
|
||||
"wt",
|
||||
"śr",
|
||||
"czw",
|
||||
"cz",
|
||||
"pt",
|
||||
"sob"
|
||||
"sb"
|
||||
],
|
||||
"months": [
|
||||
"stycznia",
|
||||
@@ -142,7 +142,7 @@
|
||||
"hours_minutes": "{h} godz. {m}"
|
||||
},
|
||||
"tile": {
|
||||
"tap_to_open": "Dotknij, aby otworzyć",
|
||||
"tap_to_open": "Otwórz",
|
||||
"page": "Strona {n}",
|
||||
"refused": "Odrzucono",
|
||||
"command_sent": "Wysłano polecenie...",
|
||||
@@ -235,7 +235,7 @@
|
||||
},
|
||||
"script": {
|
||||
"running": "Działa...",
|
||||
"never_run": "Nigdy nie uruchomiono",
|
||||
"never_run": "Nie uruchamiano",
|
||||
"last_time": "Ostatnio {time}",
|
||||
"yesterday_time": "Wczoraj {time}",
|
||||
"last_date": "Ostatnio {date}"
|
||||
@@ -245,7 +245,7 @@
|
||||
"loading": "Ładowanie obrazu",
|
||||
"live": "Na żywo",
|
||||
"recording": "Nagrywanie",
|
||||
"tap_to_view": "Dotknij, aby zobaczyć",
|
||||
"tap_to_view": "Zobacz",
|
||||
"no_image_yet": "Brak obrazu"
|
||||
},
|
||||
"calibration": {
|
||||
|
||||
@@ -50,13 +50,13 @@
|
||||
"sábado"
|
||||
],
|
||||
"weekdays_min": [
|
||||
"dom",
|
||||
"seg",
|
||||
"ter",
|
||||
"qua",
|
||||
"qui",
|
||||
"sex",
|
||||
"sáb"
|
||||
"do",
|
||||
"sg",
|
||||
"te",
|
||||
"qu",
|
||||
"qi",
|
||||
"sx",
|
||||
"sb"
|
||||
],
|
||||
"months": [
|
||||
"janeiro",
|
||||
@@ -214,7 +214,7 @@
|
||||
},
|
||||
"media": {
|
||||
"muted": "Sem som",
|
||||
"not_playing": "Nada a reproduzir",
|
||||
"not_playing": "Inativo",
|
||||
"loading": "A carregar"
|
||||
},
|
||||
"timer": {
|
||||
@@ -246,7 +246,7 @@
|
||||
"live": "Em direto",
|
||||
"recording": "A gravar",
|
||||
"tap_to_view": "Toque para ver",
|
||||
"no_image_yet": "Ainda sem imagem"
|
||||
"no_image_yet": "Sem imagem"
|
||||
},
|
||||
"calibration": {
|
||||
"title": "Siga a calibração",
|
||||
|
||||
@@ -69,7 +69,7 @@ const char *const screen_text::TABLE[] = {
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec",
|
||||
"{weekday} {day} {month}",
|
||||
"{weekday_min} {day} {month}",
|
||||
"{weekday} {day} {month}",
|
||||
"{day} {month}",
|
||||
"{weekday} {time}",
|
||||
|
||||
+49
-2
@@ -87,6 +87,9 @@ def check():
|
||||
problems, notes = [], []
|
||||
base = dict(gen.flatten({k: v for k, v in english.items() if k != '_meta'}))
|
||||
drawable = font_letters()
|
||||
width = text_width()
|
||||
if width is None:
|
||||
notes.append('Pillow is missing: tile texts were not measured')
|
||||
for code, data in langs.items():
|
||||
meta = data.get('_meta', {})
|
||||
for field in ('name', 'english', 'script', 'plural', 'checked'):
|
||||
@@ -105,7 +108,10 @@ def check():
|
||||
if key not in base or not isinstance(text, str):
|
||||
continue
|
||||
source = base[key]
|
||||
if set(PLACEHOLDER.findall(text)) != set(PLACEHOLDER.findall(source)):
|
||||
if key in EITHER_PLACEHOLDER:
|
||||
if not set(PLACEHOLDER.findall(text)) <= EITHER_PLACEHOLDER[key]:
|
||||
problems.append(f'{code}: {key} has placeholders beyond {sorted(EITHER_PLACEHOLDER[key])}')
|
||||
elif set(PLACEHOLDER.findall(text)) != set(PLACEHOLDER.findall(source)):
|
||||
problems.append(f'{code}: {key} has placeholders {sorted(set(PLACEHOLDER.findall(text)))}, '
|
||||
f'English {sorted(set(PLACEHOLDER.findall(source)))}')
|
||||
plural = ' | ' in source
|
||||
@@ -126,6 +132,14 @@ def check():
|
||||
ours = not key.startswith(('screen.ha.', 'screen.date.', 'screen.number.'))
|
||||
if ours and code != 'en' and len(text) > max(8, len(source) * 1.6) and not plural:
|
||||
notes.append(f'{code}: {key} is much longer than the English ({len(text)} vs {len(source)})')
|
||||
if width and key in TILE_LINES:
|
||||
for board, (size, room) in TILE_LINES[key].items():
|
||||
if width(size, text) > room:
|
||||
problems.append(f'{code}: {key} "{text}" is too wide for a tile on the {board} '
|
||||
f'({width(size, text):.0f} of {room} px); make it shorter')
|
||||
# The weather columns of the CYD hold a day of two letters beside its icon.
|
||||
if key.startswith('screen.date.weekdays_min.') and len(text) > 2:
|
||||
problems.append(f'{code}: {key} "{text}" is longer than two letters; the CYD\'s weather columns cut it')
|
||||
for line in notes:
|
||||
print('note:', line)
|
||||
for line in problems:
|
||||
@@ -134,6 +148,34 @@ def check():
|
||||
return 1 if problems else 0
|
||||
|
||||
|
||||
# One line under a tile's name, and the room it has there: Roboto 400 at the CYD's 11 px in about 88 px, at the
|
||||
# Guition's 16 px in about 128 px (packages/boards: TILE_W, FONT_SUBLABEL_SIZE). A longer text is cut; `check` fails.
|
||||
TILE_ROOM = {'CYD': (11, 88), 'Guition': (16, 128)}
|
||||
# Camera tiles are the Guition's alone.
|
||||
TILE_LINES = {'screen.tile.tap_to_open': TILE_ROOM, 'screen.script.never_run': TILE_ROOM, 'screen.script.running': TILE_ROOM,
|
||||
'screen.media.not_playing': TILE_ROOM, 'screen.timer.paused': TILE_ROOM,
|
||||
'screen.camera.tap_to_view': {'Guition': TILE_ROOM['Guition']},
|
||||
'screen.camera.no_image_yet': {'Guition': TILE_ROOM['Guition']}}
|
||||
|
||||
|
||||
def text_width():
|
||||
"""(size, text) -> pixels in the screens' Roboto 400, or None without Pillow (the check then skips widths)."""
|
||||
try:
|
||||
from PIL import ImageFont
|
||||
except ImportError:
|
||||
return None
|
||||
fonts = {}
|
||||
def width(size, text):
|
||||
if size not in fonts:
|
||||
fonts[size] = ImageFont.truetype(str(ROOT / 'fonts' / 'Roboto-400.ttf'), size)
|
||||
return fonts[size].getlength(text)
|
||||
return width
|
||||
|
||||
|
||||
# Texts whose placeholders a language picks from a set: the top bar's date takes the weekday's abbreviation ({weekday},
|
||||
# "sam.") or its two letters ({weekday_min}, "Sa" in English).
|
||||
EITHER_PLACEHOLDER = {'screen.date.top_bar': {'weekday', 'weekday_min', 'day', 'month'}}
|
||||
|
||||
# English that stays in the firmware on purpose, with why. Everything else a screen shows comes from the translations,
|
||||
# and `lint` fails on a new English text in the code, so it never slips back in.
|
||||
LINT_KEEP = {
|
||||
@@ -397,7 +439,12 @@ def cldr_dates(write, codes=None):
|
||||
before = json.dumps(data, ensure_ascii=False)
|
||||
data.setdefault('_meta', {})['clock'] = cldr['clock']
|
||||
number = {**cldr['number'], 'percent': ' %' if percent_space(code) else '%'}
|
||||
merge(data.setdefault('screen', {}), {'number': number, 'time': cldr['time'], 'date': cldr['date']})
|
||||
date = dict(cldr['date'])
|
||||
# The two letters of the weather columns are the language's own choice once it has them (the CLDR's short
|
||||
# width, which Node's Intl doesn't give): only a new language starts from the abbreviation.
|
||||
if data.get('screen', {}).get('date', {}).get('weekdays_min'):
|
||||
date.pop('weekdays_min')
|
||||
merge(data.setdefault('screen', {}), {'number': number, 'time': cldr['time'], 'date': date})
|
||||
if json.dumps(data, ensure_ascii=False) != before:
|
||||
print(f'{code}: {"wrote" if write else "would change"} the CLDR texts')
|
||||
if write:
|
||||
|
||||
@@ -9,7 +9,7 @@ import type { HeaderItem } from "../types";
|
||||
const query = ref("");
|
||||
const taken = computed(() => new Set(topbarItems().map(itemKey)));
|
||||
const samples = computed(() => ({
|
||||
clock: clockText(clock24.value, new Date(state.now)),
|
||||
clock: clockText(clock24.value, new Date(state.now), screenLanguage.value),
|
||||
analog: t("editor.topbar.analog_sample"),
|
||||
date: dateText(new Date(state.now), screenLanguage.value),
|
||||
} as Record<string, string>));
|
||||
|
||||
@@ -51,7 +51,7 @@ const liveNote = computed(() => {
|
||||
return !view.shown ? t("editor.topbar.live.hidden") : overflow.value.has(props.index) ? t("editor.topbar.live.overflow") : t("editor.topbar.live.looks");
|
||||
});
|
||||
const samples = computed(() => ({
|
||||
clock: clockText(clock24.value, new Date(state.now)),
|
||||
clock: clockText(clock24.value, new Date(state.now), screenLanguage.value),
|
||||
analog: t("editor.topbar.analog_sample"),
|
||||
date: dateText(new Date(state.now), screenLanguage.value),
|
||||
} as Record<string, string>));
|
||||
|
||||
+10
-6
@@ -12,14 +12,18 @@ export const BUILTIN_ICONS: Record<string, string> = { clock: "clock-outline", a
|
||||
export const itemKey = (item: HeaderItem) => JSON.stringify(item);
|
||||
export const glyph = (cp: string) => String.fromCodePoint(parseInt(cp, 16));
|
||||
|
||||
export function clockText(clock24: boolean, now = new Date()) {
|
||||
let hours = now.getHours();
|
||||
// The screen formats with %I:%M when the 24-hour clock is off.
|
||||
if (!clock24) hours = hours % 12 || 12;
|
||||
return `${String(hours).padStart(2, "0")}:${String(now.getMinutes()).padStart(2, "0")}`;
|
||||
// The time as the screens write it (screen_text::clock_text): "07:12" on 24 hours; on 12 "7:12 PM" in the top bar, with
|
||||
// the language's day periods, and "7:12" in the clock card's big digits, which have no letters.
|
||||
export function clockText(clock24: boolean, now = new Date(), locale?: string) {
|
||||
const minutes = String(now.getMinutes()).padStart(2, "0");
|
||||
if (clock24) return `${String(now.getHours()).padStart(2, "0")}:${minutes}`;
|
||||
const time = `${now.getHours() % 12 || 12}:${minutes}`;
|
||||
return locale ? `${time} ${t(`screen.time.${now.getHours() < 12 ? "am" : "pm"}`, {}, { locale })}` : time;
|
||||
}
|
||||
// "Sa 19 Sep", "za 19 sep", "sam. 19 sept.": the language's pattern with its abbreviation or its two letters.
|
||||
export const dateText = (now = new Date(), locale = "en") => t("screen.date.top_bar", {
|
||||
weekday: t(`screen.date.weekdays_min.${now.getDay()}`, {}, { locale }),
|
||||
weekday: t(`screen.date.weekdays_short.${now.getDay()}`, {}, { locale }),
|
||||
weekday_min: t(`screen.date.weekdays_min.${now.getDay()}`, {}, { locale }),
|
||||
day: now.getDate(),
|
||||
month: t(`screen.date.months_short.${now.getMonth()}`, {}, { locale }),
|
||||
}, { locale });
|
||||
|
||||
+1
-1
@@ -583,7 +583,7 @@ export function topbarLabel(item: HeaderItem) {
|
||||
// What the item shows right now: { icon, text, color, shown }. Entities wait for the add-on's preview.
|
||||
export function topbarView(item: HeaderItem): ItemView {
|
||||
const now = new Date(state.now);
|
||||
if (item.type === "clock") return { text: clockText(clock24.value, now), shown: true };
|
||||
if (item.type === "clock") return { text: clockText(clock24.value, now, screenLanguage.value), shown: true };
|
||||
if (item.type === "date") return { text: dateText(now, screenLanguage.value), shown: true };
|
||||
if (item.type === "analog") return { analog: true, shown: true };
|
||||
const p = state.topbarPreviews[itemKey(item)];
|
||||
|
||||
@@ -175,7 +175,8 @@ describe("the mockup speaks the screens' language", () => {
|
||||
ha: { unavailable: "Nicht verfügbar", on: "An", weather: { windy: "Windig" }, binary: { door_on: "Offen" }, button: { run: "Ausführen" } },
|
||||
tile: { page: "Seite {n}" },
|
||||
time: { hours_ago: "Vor 1 Stunde | Vor {n} Stunden", just_now: "Gerade eben" },
|
||||
date: { weekdays_min: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], months_short: ["Jan.", "Feb.", "März", "Apr.", "Mai", "Juni", "Juli", "Aug.", "Sept.", "Okt.", "Nov.", "Dez."], top_bar: "{weekday}., {day}. {month}" },
|
||||
date: { weekdays_min: ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], weekdays_short: ["So.", "Mo.", "Di.", "Mi.", "Do.", "Fr.", "Sa."],
|
||||
months_short: ["Jan.", "Feb.", "März", "Apr.", "Mai", "Juni", "Juli", "Aug.", "Sept.", "Okt.", "Nov.", "Dez."], top_bar: "{weekday}, {day}. {month}" },
|
||||
number: { decimal: ",", group: ".", group_min: "2" },
|
||||
},
|
||||
}, meta("one_other"));
|
||||
|
||||
@@ -28,8 +28,13 @@ describe("clock and date", () => {
|
||||
const evening = new Date(2026, 8, 15, 19, 5);
|
||||
it("formats the clock the way the screen does", () => {
|
||||
expect(clockText(true, evening)).toBe("19:05");
|
||||
expect(clockText(false, evening)).toBe("07:05");
|
||||
// The clock card's big digits: no leading zero, no day period (its font has no letters).
|
||||
expect(clockText(false, evening)).toBe("7:05");
|
||||
expect(clockText(false, new Date(2026, 8, 15, 0, 30))).toBe("12:30");
|
||||
// The top bar: with the language's day period, as screen_text::clock_text writes it.
|
||||
expect(clockText(false, evening, "en")).toBe("7:05 PM");
|
||||
expect(clockText(false, new Date(2026, 8, 15, 0, 30), "en")).toBe("12:30 AM");
|
||||
expect(clockText(true, evening, "en")).toBe("19:05");
|
||||
});
|
||||
it("writes the date short", () => {
|
||||
expect(dateText(evening)).toBe("Tu 15 Sep");
|
||||
|
||||
Reference in New Issue
Block a user