mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-17 19:36:28 +02:00
Add Dutch to the interface languages (issue #2891)
The translation was contributed as a file on the issue and needed three corrections before it could be wired up, all of which the parity gate found. The nine stats.timeframe.* entries had their keys translated along with their values -- 'today' had become 'vandaag'. Code resolves those by the English key, so the Statistics timeframe selector would have found nothing and rendered raw key names for every Dutch user. The values are kept and the keys restored. The file was translated against an older en.ts and was 84 leaves short: the Filament Track Switch feed prompts, the AI-detection status strings, the no-3MF internal-history banner, the batch-order stranded-plate notices, the Avery starting-position field, and the whole locationHaSensors section from #2824. Rather than splice those in, nl.ts is regenerated from the en.ts skeleton with the contributor's strings carried over by key, so its structure, key order and section comments match the reference exactly and a later diff against en.ts reads as content rather than as reordering. The generator fails rather than emit a key it has no translation for, so nothing fell back to English silently. 229 leaves are identical to English. Each was checked and all are kept: Dutch takes most technical UI vocabulary verbatim -- printer, filament, status, nozzle, timelapse, dashboard -- and Dutch slicer users use the English feature names untranslated, so support, ironing, prime tower and gap fill stay as they are. The 123 distinct values are enumerated in a NL_COGNATES list in check-i18n-parity.mjs, the same shape the other twelve locales use, so the exemption is a listed decision per string rather than a blanket skip for the locale. Backend app/i18n still carries English and German only, so push notification text falls back to English for Dutch. That is true of the eleven other non-German locales too and is left alone here. Parity green at 6264 leaves across 14 locales.
This commit is contained in:
@@ -12,6 +12,7 @@ All notable changes to Bambuddy will be documented in this file.
|
||||
- **Printer file downloads can be selected in ranges and print-history videos can be downloaded (#2850, requested and contributed by @logikal in #2853)** — The printer file browser's multi-select download now prepares large selections on the app data volume instead of buffering them in server and browser memory, uses per-file compression (videos stored, G-code/3MF compressed), reports partial results and preparation progress, supports cancellation, rejects over-large or under-space selections, and preserves the legacy API contract. Shift-click selects a contiguous visible range and hidden selections are discarded when navigating or filtering. Print History now offers attached timelapses, matching printer timelapses, and `/ipcam` chunks when available; offline or unreadable storage is distinguished from an empty directory. Download tokens are single-use and resource-bound, API-key printer allowlists are enforced, FTP short reads are rejected, and abandoned staging is pruned. Translated in all locales; wiki updated. Covered by backend and frontend regression tests.
|
||||
- **Bambuddy now asks a printer that refuses FTPS what it actually said (#2780, measured by @grolmus)** — When a printer's file service answers port 990 with something that is not TLS, Python reports `[SSL: WRONG_VERSION_NUMBER]` and the bytes that caused it are gone, consumed by the TLS layer before the error surfaces. That has left #2780 open on a theory rather than a finding. The client now opens one plain connection straight afterwards and reads what the printer says, so the log carries the printer's own words — an FTP refusal such as `421 Too many connections` would identify the fault outright — and the line is marked as the one to quote in a report. Reading nothing is informative too, and says so: a healthy implicit-FTPS service stays silent until it gets a handshake, so silence means the refusal had already passed. It asks once per cool-off window rather than once per attempt, which keeps it to one extra connection per printer per five minutes — the suspected fault is a printer running out of connections, so the diagnosis must not add to it. What made this worth doing is a measurement from a nine-printer farm, reproduced here: a cleartext banner on the TLS port produces exactly the error the field reports, a genuine TLS version mismatch produces a different one, and a client with no version cap reaches a TLS-1.2-only peer unaided. So this failure was never a TLS-version problem, and the per-model `cap_tls_v1_2` knob cannot affect it. Two of the three entries carrying that knob were added on the belief that it could; they are kept, since their reporters saw the symptom clear and nobody here has the hardware to re-test on, but they are now marked for re-test and the reasoning recorded next to them is what was measured rather than what was assumed. Both measurements are pinned by tests, so the explanation stays falsifiable.
|
||||
- **The K value is on the AMS slot itself, not only in the popover (#2532, requested and contributed by @gyrene2083)** — Reading back a slot's pressure-advance value meant hovering it: the K factor lived in the filament popover alone, so checking whether a calibration had actually taken across four slots was four hovers, and comparing two of them side by side was not possible at all. Every slot card now carries the value under the material name, the way Bambu Studio shows it per slot — on regular AMS units, on AMS-HT, and on the external spool of a dual-nozzle machine. Only a value the printer actually reported is shown: a loaded but never-calibrated slot stays blank rather than inheriting the 0.020 that fills the popover's own field, and a slot the firmware reports as exactly 0 counts as uncalibrated the same way the stored K-profiles do. The label is shortened to **K** with the full localized name on hover, because "K Factor", "K-Faktor" and "Facteur K" ate the value itself — the whole point of the line — on cards under about 350px, and the figure is set in tabular numerals so it measures the same in Safari as in Chromium. Where one slot of a unit is calibrated and its neighbours are not, the neighbours hold the same row open so the fill bars stay level across the card.
|
||||
- **Dutch (nl) is now a supported interface language (#2891, requested and contributed by @Igiegel)** — Adds `nl` as the fourteenth locale, listed as "Nederlands" in the language picker. The translation was contributed as a file on the issue and needed three corrections before it could be wired up, all of which the parity gate found. First, the nine `stats.timeframe.*` entries had their **keys** translated along with their values (`'today'` had become `'vandaag'`), which would have left the Statistics timeframe selector resolving nothing and rendering raw key names for every Dutch user — the values were kept and the keys restored. Second, the file was translated against an older `en.ts` and was 84 leaves short, missing the Filament Track Switch feed prompts, the AI-detection status strings, the no-3MF internal-history banner, the batch-order stranded-plate notices, the Avery starting-position field and the whole `locationHaSensors` section from #2824; those were translated and added. Rather than splice them in, `nl.ts` was regenerated from the `en.ts` skeleton with the contributor's strings carried over, so its structure, key order and section comments now match the reference locale exactly and a future diff against `en.ts` reads as content rather than as reordering. Third, 229 leaves were identical to English; each was checked individually and all were kept, because Dutch takes most technical UI vocabulary verbatim — printer, filament, status, nozzle, timelapse, dashboard — and Dutch slicer users use the English feature names (support, ironing, prime tower, gap fill) untranslated. Those 123 distinct values are now listed explicitly in a `NL_COGNATES` allow-list in `check-i18n-parity.mjs`, the same shape the other twelve locales use, so the exemption is an enumerated translator decision rather than a blanket skip. Parity green at 6264 leaves across all 14 locales.
|
||||
|
||||
### Changed
|
||||
- **Home Assistant sensors moved out of the Smart Plugs settings tab into their own (#2824)** — Sensors are things you read and plugs are things you switch, and with storage-location bindings joining the printer ones the two no longer belong on one page. Both now live under **Settings → Sensors**; nothing about the printer bindings themselves changed, only where they are. The template that carried the printer alert is renamed from "Home Assistant Sensor Alert" to "Printer Sensor Alert", along with the toggle and badge labels that name it, because once a storage-location alert existed beside it the old name no longer said which one it was; the rename only touches templates still holding the old default name, so one that was edited keeps whatever it was called. A battery-class printer sensor now draws a battery icon instead of the generic gauge — the printer map never had an entry for it and the shared one does, which reads as the omission it was rather than a choice worth preserving.
|
||||
|
||||
@@ -415,6 +415,45 @@ const UK_COGNATES = [
|
||||
'(25%, 50%, 75%)',
|
||||
];
|
||||
|
||||
// Dutch cognates. Dutch shares most technical UI vocabulary with English
|
||||
// verbatim -- printer, filament, status, nozzle, timelapse, dashboard --
|
||||
// and the slicer feature names (support, ironing, prime tower, gap fill)
|
||||
// are used untranslated by Dutch slicer users. Each entry below was
|
||||
// checked individually against the Dutch translation in #2891.
|
||||
const NL_COGNATES = [
|
||||
'1 week', '(25%, 50%, 75%)', 'Accent', 'AMS Filament Backup',
|
||||
'{{ams}} Slot {{slot}}', 'Auto', 'Auto Home', 'Bambu Cloud',
|
||||
'Batch', 'Batches', 'Branch', 'Budget',
|
||||
'Camera', 'China', 'Client Secret', 'Cloud',
|
||||
'Commit', 'Compact', '({{count}}/8)', '{{count}} downloads',
|
||||
'{{count}} filament', '({{count}} item)', '{{count}} item', '({{count}} items)',
|
||||
'{{count}} items', '{{count}} object', 'Dashboard', 'Diagnose',
|
||||
'Diameter', 'EC984C,#6CD4BC,A66EB9,D87694', 'Effect', 'email',
|
||||
'ETA {{minutes}} min', 'Expert', 'Extruder', 'Extruders',
|
||||
'Factor', 'Filament', 'Filament {{index}} ({{type}})', 'Filament {{n}}',
|
||||
'{{filament}} @ {{temp}}°C', 'Filters', 'Firmware', 'Flow',
|
||||
'Galaxy', 'Gap fill', 'Hex', 'Hex: #{{hex}}',
|
||||
'Host', 'In browser', 'Interval', 'Interval (min)',
|
||||
'Interval ({{type}})', 'Ironing', 'Jade White, Fire Red...', 'Label',
|
||||
'Label...', 'LAN Developer Mode', 'Live', 'Long-Lived Access Token',
|
||||
'Ludicrous (166%)', 'MakerWorld: {{designer}}', 'Metadata', 'Min',
|
||||
'Model', '{{name}} — {{stage}} ({{percent}}%) — {{elapsed}}', '{{name}} - Timelapse', 'Nozzle',
|
||||
'Nozzle 2', '{{n}} run', '{{n}} runs', 'Offline',
|
||||
'Online', 'Open', 'Orca Cloud', 'parallel',
|
||||
'Personal Access Token', 'Pipeline', 'Pipelines', 'Platform',
|
||||
'Pressure Advance', 'Prime tower', 'Printer', 'Printer:',
|
||||
'{{printer}}: {{error}}', '{{printer}} is offline', 'Printer is offline', 'Printer offline',
|
||||
'Printers', 'Project', 'Project: {{name}}', 'Protocol',
|
||||
'Providers', 'Provider: {{type}}', 'Proxy', 'Recent',
|
||||
'Records', 'round robin', 'Scopes', 'Score',
|
||||
'sets', 'Skirt / brim', 'Slicer', 'SpoolBuddy is offline',
|
||||
'Sport (124%)', 'Start', 'Status', 'Subtype',
|
||||
'Support', 'Tag', 'Tags', 'Temp',
|
||||
'Timelapse', 'Topic', 'Trend', 'Type',
|
||||
'Type:', 'Updates', 'Uptime', 'Urgent',
|
||||
'Warm', '{{weight}}g', 'Workflow',
|
||||
];
|
||||
|
||||
const IDENTICAL_TO_EN_ALLOWED = {
|
||||
de: new Set(DE_COGNATES),
|
||||
fr: new Set(FR_COGNATES),
|
||||
@@ -428,6 +467,7 @@ const IDENTICAL_TO_EN_ALLOWED = {
|
||||
tr: new Set(TR_COGNATES),
|
||||
ru: new Set(RU_COGNATES),
|
||||
uk: new Set(UK_COGNATES),
|
||||
nl: new Set(NL_COGNATES),
|
||||
};
|
||||
|
||||
// Pure comparison logic, exported so tests can verify each failure mode
|
||||
|
||||
@@ -9,6 +9,7 @@ import es from './locales/es';
|
||||
import fr from './locales/fr';
|
||||
import ja from './locales/ja';
|
||||
import it from './locales/it';
|
||||
import nl from './locales/nl';
|
||||
import ko from './locales/ko';
|
||||
import ptBR from './locales/pt-BR';
|
||||
import zhCN from './locales/zh-CN';
|
||||
@@ -24,6 +25,7 @@ const resources = {
|
||||
fr: { translation: fr },
|
||||
ja: { translation: ja },
|
||||
it: { translation: it },
|
||||
nl: { translation: nl },
|
||||
ko: { translation: ko },
|
||||
'pt-BR': { translation: ptBR },
|
||||
'zh-CN': { translation: zhCN },
|
||||
@@ -33,7 +35,7 @@ const resources = {
|
||||
uk: { translation: uk },
|
||||
};
|
||||
|
||||
const SUPPORTED_LNGS = ['en', 'de', 'es', 'fr', 'ja', 'it', 'ko', 'pt-BR', 'ru', 'tr', 'uk', 'zh-CN', 'zh-TW'];
|
||||
const SUPPORTED_LNGS = ['en', 'de', 'es', 'fr', 'ja', 'it', 'ko', 'nl', 'pt-BR', 'ru', 'tr', 'uk', 'zh-CN', 'zh-TW'];
|
||||
const APPLIANCE_CONSUMED_KEY = 'bambuddy_appliance_locale_consumed';
|
||||
|
||||
i18n
|
||||
@@ -107,6 +109,7 @@ export const availableLanguages = [
|
||||
{ code: 'ja', name: 'Japanese', nativeName: '日本語' },
|
||||
{ code: 'it', name: 'Italian', nativeName: 'Italiano' },
|
||||
{ code: 'ko', name: 'Korean', nativeName: '한국어' },
|
||||
{ code: 'nl', name: 'Dutch', nativeName: 'Nederlands' },
|
||||
{ code: 'pt-BR', name: 'Portuguese (Brazil)', nativeName: 'Português (Brasil)' },
|
||||
{ code: 'zh-CN', name: 'Chinese (Simplified)', nativeName: '简体中文' },
|
||||
{ code: 'zh-TW', name: 'Chinese (Traditional)', nativeName: '繁體中文' },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+1
-1
@@ -26,7 +26,7 @@
|
||||
|
||||
<!-- Splash screens for iOS -->
|
||||
<link rel="apple-touch-startup-image" href="/img/android-chrome-512x512.png" />
|
||||
<script type="module" crossorigin src="/assets/index-DL1B9Y3L.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DFcvtgAy.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BzJRM4M1.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user