@jjlmoya/utils-cooking 1.30.0 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -0
  3. package/src/entries.ts +3 -1
  4. package/src/index.ts +1 -0
  5. package/src/tests/i18n-titles.test.ts +3 -2
  6. package/src/tests/i18n_coverage.test.ts +1 -0
  7. package/src/tests/locale_completeness.test.ts +2 -2
  8. package/src/tests/tool_validation.test.ts +2 -2
  9. package/src/tool/botulism-canning-safety/bibliography.astro +6 -0
  10. package/src/tool/botulism-canning-safety/bibliography.ts +10 -0
  11. package/src/tool/botulism-canning-safety/botulism-canning-safety.css +545 -0
  12. package/src/tool/botulism-canning-safety/component.astro +296 -0
  13. package/src/tool/botulism-canning-safety/components/AutoclaveDisplay.astro +62 -0
  14. package/src/tool/botulism-canning-safety/components/SporeVisualizer.astro +48 -0
  15. package/src/tool/botulism-canning-safety/components/ThermalControls.astro +60 -0
  16. package/src/tool/botulism-canning-safety/entry.ts +26 -0
  17. package/src/tool/botulism-canning-safety/i18n/de.ts +188 -0
  18. package/src/tool/botulism-canning-safety/i18n/en.ts +188 -0
  19. package/src/tool/botulism-canning-safety/i18n/es.ts +188 -0
  20. package/src/tool/botulism-canning-safety/i18n/fr.ts +188 -0
  21. package/src/tool/botulism-canning-safety/i18n/id.ts +188 -0
  22. package/src/tool/botulism-canning-safety/i18n/it.ts +188 -0
  23. package/src/tool/botulism-canning-safety/i18n/ja.ts +188 -0
  24. package/src/tool/botulism-canning-safety/i18n/ko.ts +188 -0
  25. package/src/tool/botulism-canning-safety/i18n/nl.ts +188 -0
  26. package/src/tool/botulism-canning-safety/i18n/pl.ts +188 -0
  27. package/src/tool/botulism-canning-safety/i18n/pt.ts +188 -0
  28. package/src/tool/botulism-canning-safety/i18n/ru.ts +188 -0
  29. package/src/tool/botulism-canning-safety/i18n/sv.ts +188 -0
  30. package/src/tool/botulism-canning-safety/i18n/tr.ts +188 -0
  31. package/src/tool/botulism-canning-safety/i18n/zh.ts +188 -0
  32. package/src/tool/botulism-canning-safety/index.ts +11 -0
  33. package/src/tool/botulism-canning-safety/logic.ts +47 -0
  34. package/src/tool/botulism-canning-safety/seo.astro +15 -0
  35. package/src/tool/ice-cream-pac-pod/component.astro +39 -0
  36. package/src/tool/spherification-bath-calculator/component.astro +37 -0
  37. package/src/tools.ts +2 -0
@@ -0,0 +1,296 @@
1
+ ---
2
+ import ThermalControls from './components/ThermalControls.astro';
3
+ import AutoclaveDisplay from './components/AutoclaveDisplay.astro';
4
+ import SporeVisualizer from './components/SporeVisualizer.astro';
5
+
6
+ interface Props {
7
+ ui: Record<string, string>;
8
+ }
9
+
10
+ const { ui } = Astro.props;
11
+ ---
12
+
13
+ <div class="botulism-container">
14
+ <div class="botulism-console">
15
+ <ThermalControls ui={ui} />
16
+ <AutoclaveDisplay ui={ui} />
17
+ <SporeVisualizer ui={ui} />
18
+ </div>
19
+ </div>
20
+
21
+ <script is:inline define:vars={{ ui }}>
22
+ const waterBathBtn = document.getElementById('toggle-water-bath-btn');
23
+ const pressureCannerBtn = document.getElementById('toggle-pressure-canner-btn');
24
+
25
+ const celsiusBtn = document.getElementById('toggle-celsius-btn');
26
+ const fahrenheitBtn = document.getElementById('toggle-fahrenheit-btn');
27
+ const tempUnitDisplay = document.getElementById('temp-unit-display');
28
+
29
+ const tempInput = document.getElementById('temp-input');
30
+ const tempSlider = document.getElementById('temp-slider');
31
+
32
+ const timeInput = document.getElementById('time-input');
33
+ const timeSlider = document.getElementById('time-slider');
34
+
35
+ const phInput = document.getElementById('ph-input');
36
+ const phSlider = document.getElementById('ph-slider');
37
+
38
+ const f0ValueDisplay = document.getElementById('f0-value-display');
39
+ const f0GaugeBar = document.getElementById('f0-gauge-bar');
40
+
41
+ const dValueDisplay = document.getElementById('d-value-display');
42
+ const dGaugeBar = document.getElementById('d-gauge-bar');
43
+
44
+ const chamberSteamLevel = document.getElementById('chamber-steam-level');
45
+ const pressureReadout = document.getElementById('pressure-readout');
46
+ const autoclaveChamberBox = document.getElementById('autoclave-chamber-box');
47
+
48
+ const logReductionValueDisplay = document.getElementById('log-reduction-value-display');
49
+ const canningStatusBadge = document.getElementById('canning-status-badge');
50
+ const canningStatusBadgeText = document.getElementById('canning-status-badge-text');
51
+ const canningStatusDescription = document.getElementById('canning-status-description');
52
+
53
+ let activeMethod = 'water-bath';
54
+ let activeTempUnit = 'celsius';
55
+
56
+ function computeThermal(temp, time) {
57
+ const exponent = (temp - 121.11) / 10;
58
+ const lethalityRate = Math.pow(10, exponent);
59
+ const f0Value = parseFloat((lethalityRate * time).toFixed(3));
60
+
61
+ const dValue = parseFloat((0.21 * Math.pow(10, (121.11 - temp) / 10)).toFixed(3));
62
+ const logReduction = dValue > 0 ? parseFloat((time / dValue).toFixed(2)) : 0;
63
+ return { dValue, f0Value, logReduction };
64
+ }
65
+
66
+ function computeSafety(input) {
67
+ const { ph, method, f0Value, temp, time } = input;
68
+ if (ph < 4.6) {
69
+ const minTemp = method === 'water-bath' ? 95 : 100;
70
+ return temp >= minTemp && time >= 10 ? 'safe' : 'marginal';
71
+ }
72
+ if (method === 'water-bath') return 'unsafe';
73
+ if (f0Value >= 3.0) return 'safe';
74
+ if (f0Value >= 1.5) return 'marginal';
75
+ return 'unsafe';
76
+ }
77
+
78
+ function calculateResults(temp, time, ph, method) {
79
+ const thermal = computeThermal(temp, time);
80
+ return {
81
+ dValue: thermal.dValue,
82
+ f0Value: thermal.f0Value,
83
+ logReduction: thermal.logReduction,
84
+ safetyStatus: computeSafety({ ph, method, f0Value: thermal.f0Value, temp, time }),
85
+ };
86
+ }
87
+
88
+ function updateChamber(temp) {
89
+ const steamOpacity = Math.max(0, Math.min(0.8, (temp - 90) / 40));
90
+ chamberSteamLevel.style.opacity = steamOpacity.toString();
91
+
92
+ if (activeMethod === 'water-bath') {
93
+ autoclaveChamberBox.style.display = 'none';
94
+ pressureReadout.textContent = '0.0 PSI';
95
+ } else {
96
+ autoclaveChamberBox.style.display = 'flex';
97
+ const psi = Math.max(0, (temp - 100) * 0.73);
98
+ pressureReadout.textContent = `${psi.toFixed(1)} PSI`;
99
+ }
100
+ }
101
+
102
+ function updateStatus(status) {
103
+ canningStatusBadge.className = 'canning-status-badge';
104
+
105
+ if (status === 'safe') {
106
+ canningStatusBadge.classList.add('safety-safe');
107
+ canningStatusBadgeText.textContent = ui.statusSafe;
108
+ canningStatusDescription.textContent = ui.statusSafeDesc;
109
+ } else if (status === 'marginal') {
110
+ canningStatusBadge.classList.add('safety-marginal');
111
+ canningStatusBadgeText.textContent = ui.statusMarginal;
112
+ canningStatusDescription.textContent = ui.statusMarginalDesc;
113
+ } else {
114
+ canningStatusBadge.classList.add('safety-unsafe');
115
+ canningStatusBadgeText.textContent = ui.statusUnsafe;
116
+ canningStatusDescription.textContent = ui.statusUnsafeDesc;
117
+ }
118
+ }
119
+
120
+ function updateSporeCells(logReduction) {
121
+ const floorReduction = Math.floor(logReduction);
122
+ for (let i = 1; i <= 12; i++) {
123
+ const cell = document.getElementById(`spore-cell-${i}`);
124
+ if (cell) {
125
+ if (i > floorReduction) {
126
+ cell.classList.add('active');
127
+ } else {
128
+ cell.classList.remove('active');
129
+ }
130
+ }
131
+ }
132
+ }
133
+
134
+ function saveState() {
135
+ const state = { activeMethod, activeTempUnit, temp: tempInput.value, time: timeInput.value, ph: phInput.value };
136
+ localStorage.setItem('cooking-botulism-state', JSON.stringify(state));
137
+ }
138
+
139
+ function loadState() {
140
+ try {
141
+ const state = JSON.parse(localStorage.getItem('cooking-botulism-state') || '{}');
142
+ if (state.activeMethod) {
143
+ activeMethod = state.activeMethod;
144
+ waterBathBtn.classList.toggle('active', state.activeMethod === 'water-bath');
145
+ pressureCannerBtn.classList.toggle('active', state.activeMethod === 'pressure-canner');
146
+ }
147
+ if (state.activeTempUnit) {
148
+ activeTempUnit = state.activeTempUnit;
149
+ celsiusBtn.classList.toggle('active', state.activeTempUnit === 'celsius');
150
+ fahrenheitBtn.classList.toggle('active', state.activeTempUnit === 'fahrenheit');
151
+ }
152
+ updateTempLimits(true);
153
+ if (state.temp) syncInputs(state.temp, tempSlider, tempInput);
154
+ if (state.time) syncInputs(state.time, timeSlider, timeInput);
155
+ if (state.ph) { phInput.value = state.ph; phSlider.value = state.ph; }
156
+ } catch {}
157
+ }
158
+
159
+ function render() {
160
+ const tempUI = parseFloat(tempInput.value) || 0;
161
+ const time = parseFloat(timeInput.value) || 0;
162
+ const ph = parseFloat(phInput.value) || 0;
163
+ const tempCelsius = activeTempUnit === 'fahrenheit' ? (tempUI - 32) * 5 / 9 : tempUI;
164
+ const results = calculateResults(tempCelsius, time, ph, activeMethod);
165
+
166
+ f0ValueDisplay.textContent = results.f0Value.toFixed(3);
167
+ f0GaugeBar.style.width = `${Math.min(100, (results.f0Value / 6) * 100)}%`;
168
+ dValueDisplay.textContent = results.dValue.toFixed(3);
169
+ dGaugeBar.style.width = `${Math.min(100, (results.dValue / 5.0) * 100)}%`;
170
+ logReductionValueDisplay.textContent = results.logReduction.toFixed(2);
171
+ updateChamber(tempCelsius);
172
+ updateStatus(results.safetyStatus);
173
+ updateSporeCells(results.logReduction);
174
+ saveState();
175
+ }
176
+
177
+ function syncInputs(val, slider, numInput) {
178
+ slider.value = val;
179
+ numInput.value = val;
180
+ }
181
+
182
+ function setTempRange() {
183
+ const isCelsius = activeTempUnit === 'celsius';
184
+ const isBath = activeMethod === 'water-bath';
185
+
186
+ if (isCelsius) {
187
+ tempSlider.min = '90'; tempInput.min = '90';
188
+ tempSlider.max = isBath ? '100' : '130';
189
+ tempInput.max = isBath ? '100' : '130';
190
+ tempUnitDisplay.textContent = '°C';
191
+ } else {
192
+ tempSlider.min = '194'; tempInput.min = '194';
193
+ tempSlider.max = isBath ? '212' : '266';
194
+ tempInput.max = isBath ? '212' : '266';
195
+ tempUnitDisplay.textContent = '°F';
196
+ }
197
+ }
198
+
199
+ function updateTempLimits(keepVal) {
200
+ const currentVal = parseFloat(tempInput.value) || 0;
201
+ let newVal = currentVal;
202
+
203
+ if (!keepVal) {
204
+ newVal = activeTempUnit === 'celsius'
205
+ ? Math.round((currentVal - 32) * 5 / 9)
206
+ : Math.round(currentVal * 9 / 5 + 32);
207
+ }
208
+
209
+ setTempRange();
210
+ newVal = Math.max(parseFloat(tempInput.min), Math.min(parseFloat(tempInput.max), newVal));
211
+ syncInputs(newVal, tempSlider, tempInput);
212
+ }
213
+
214
+ tempInput.addEventListener('input', (e) => {
215
+ syncInputs(e.target.value, tempSlider, tempInput);
216
+ render();
217
+ });
218
+
219
+ tempSlider.addEventListener('input', (e) => {
220
+ syncInputs(e.target.value, tempSlider, tempInput);
221
+ render();
222
+ });
223
+
224
+ timeInput.addEventListener('input', (e) => {
225
+ syncInputs(e.target.value, timeSlider, timeInput);
226
+ render();
227
+ });
228
+
229
+ timeSlider.addEventListener('input', (e) => {
230
+ syncInputs(e.target.value, timeSlider, timeInput);
231
+ render();
232
+ });
233
+
234
+ phInput.addEventListener('input', (e) => {
235
+ const cleanVal = e.target.value.replace(',', '.');
236
+ let val = parseFloat(cleanVal) || 0;
237
+ if (val < 2.0) val = 2.0;
238
+ if (val > 7.0) val = 7.0;
239
+ phSlider.value = val.toString();
240
+ render();
241
+ });
242
+
243
+ phInput.addEventListener('blur', (e) => {
244
+ const cleanVal = e.target.value.replace(',', '.');
245
+ let val = parseFloat(cleanVal) || 0;
246
+ if (val < 2.0) val = 2.0;
247
+ if (val > 7.0) val = 7.0;
248
+ phInput.value = val.toFixed(1);
249
+ phSlider.value = val.toString();
250
+ render();
251
+ });
252
+
253
+ phSlider.addEventListener('input', (e) => {
254
+ phInput.value = parseFloat(e.target.value).toFixed(1);
255
+ render();
256
+ });
257
+
258
+ celsiusBtn.addEventListener('click', () => {
259
+ if (activeTempUnit === 'celsius') return;
260
+ activeTempUnit = 'celsius';
261
+ celsiusBtn.classList.add('active');
262
+ fahrenheitBtn.classList.remove('active');
263
+ updateTempLimits(false);
264
+ render();
265
+ });
266
+
267
+ fahrenheitBtn.addEventListener('click', () => {
268
+ if (activeTempUnit === 'fahrenheit') return;
269
+ activeTempUnit = 'fahrenheit';
270
+ fahrenheitBtn.classList.add('active');
271
+ celsiusBtn.classList.remove('active');
272
+ updateTempLimits(false);
273
+ render();
274
+ });
275
+
276
+ waterBathBtn.addEventListener('click', () => {
277
+ if (activeMethod === 'water-bath') return;
278
+ activeMethod = 'water-bath';
279
+ waterBathBtn.classList.add('active');
280
+ pressureCannerBtn.classList.remove('active');
281
+ updateTempLimits(true);
282
+ render();
283
+ });
284
+
285
+ pressureCannerBtn.addEventListener('click', () => {
286
+ if (activeMethod === 'pressure-canner') return;
287
+ activeMethod = 'pressure-canner';
288
+ pressureCannerBtn.classList.add('active');
289
+ waterBathBtn.classList.remove('active');
290
+ updateTempLimits(true);
291
+ render();
292
+ });
293
+
294
+ loadState();
295
+ render();
296
+ </script>
@@ -0,0 +1,62 @@
1
+ ---
2
+ interface Props {
3
+ ui: Record<string, string>;
4
+ }
5
+
6
+ const { ui } = Astro.props;
7
+ ---
8
+
9
+ <div class="autoclave-diagnostics">
10
+ <div class="diagnostic-title">{ui.indicatorSectionTitle}</div>
11
+
12
+ <div class="gauges-flex-row">
13
+ <div class="gauge-display-panel f0-panel">
14
+ <div class="gauge-label-row">
15
+ <span class="gauge-label-text">{ui.f0Label}</span>
16
+ <div class="info-tooltip-container">
17
+ <svg viewBox="0 0 24 24" class="info-icon-svg" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
18
+ <circle cx="12" cy="12" r="10"></circle>
19
+ <line x1="12" y1="16" x2="12" y2="12"></line>
20
+ <line x1="12" y1="8" x2="12.01" y2="8"></line>
21
+ </svg>
22
+ <span class="info-tooltip-text">{ui.f0Tooltip}</span>
23
+ </div>
24
+ </div>
25
+ <div class="f0-digital-value" id="f0-value-display">0.00</div>
26
+ <div class="gauge-bar-track">
27
+ <div id="f0-gauge-bar" class="gauge-bar-fill f0-fill"></div>
28
+ </div>
29
+ </div>
30
+
31
+ <div class="gauge-display-panel d-panel">
32
+ <div class="gauge-label-row">
33
+ <span class="gauge-label-text">{ui.dLabel}</span>
34
+ <div class="info-tooltip-container">
35
+ <svg viewBox="0 0 24 24" class="info-icon-svg" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
36
+ <circle cx="12" cy="12" r="10"></circle>
37
+ <line x1="12" y1="16" x2="12" y2="12"></line>
38
+ <line x1="12" y1="8" x2="12.01" y2="8"></line>
39
+ </svg>
40
+ <span class="info-tooltip-text">{ui.dTooltip}</span>
41
+ </div>
42
+ </div>
43
+ <div class="d-digital-value">
44
+ <span id="d-value-display">0.21</span>
45
+ <span class="d-unit">{ui.dValueUnit}</span>
46
+ </div>
47
+ <div class="gauge-bar-track">
48
+ <div id="d-gauge-bar" class="gauge-bar-fill d-fill"></div>
49
+ </div>
50
+ </div>
51
+ </div>
52
+
53
+ <div class="autoclave-chamber-box" id="autoclave-chamber-box">
54
+ <svg viewBox="0 0 200 120" class="chamber-svg">
55
+ <rect x="20" y="10" width="160" height="100" rx="10" ry="10" class="chamber-metal-bg"></rect>
56
+ <rect x="25" y="15" width="150" height="90" rx="8" ry="8" class="chamber-window"></rect>
57
+ <rect id="chamber-steam-level" x="25" y="15" width="150" height="90" rx="8" ry="8" class="chamber-steam"></rect>
58
+ <line x1="25" y1="60" x2="175" y2="60" class="chamber-grid-line"></line>
59
+ <text x="100" y="65" text-anchor="middle" class="chamber-pressure-readout" id="pressure-readout">0.0 PSI</text>
60
+ </svg>
61
+ </div>
62
+ </div>
@@ -0,0 +1,48 @@
1
+ ---
2
+ interface Props {
3
+ ui: Record<string, string>;
4
+ }
5
+
6
+ const { ui } = Astro.props;
7
+ ---
8
+
9
+ <div class="spore-deactivation-visualizer">
10
+ <div class="visualizer-header-title">{ui.visualizerSectionTitle}</div>
11
+
12
+ <div class="spore-reduction-grid">
13
+ <div id="spore-cell-1" class="spore-cell active"></div>
14
+ <div id="spore-cell-2" class="spore-cell active"></div>
15
+ <div id="spore-cell-3" class="spore-cell active"></div>
16
+ <div id="spore-cell-4" class="spore-cell active"></div>
17
+ <div id="spore-cell-5" class="spore-cell active"></div>
18
+ <div id="spore-cell-6" class="spore-cell active"></div>
19
+ <div id="spore-cell-7" class="spore-cell active"></div>
20
+ <div id="spore-cell-8" class="spore-cell active"></div>
21
+ <div id="spore-cell-9" class="spore-cell active"></div>
22
+ <div id="spore-cell-10" class="spore-cell active"></div>
23
+ <div id="spore-cell-11" class="spore-cell active"></div>
24
+ <div id="spore-cell-12" class="spore-cell active"></div>
25
+ </div>
26
+
27
+ <div class="spore-reduction-log-readout">
28
+ <span class="log-reduction-num" id="log-reduction-value-display">0.0</span>
29
+ <div class="log-reduction-label-row">
30
+ <span class="log-reduction-label">{ui.logReductionLabel} (D)</span>
31
+ <div class="info-tooltip-container">
32
+ <svg viewBox="0 0 24 24" class="info-icon-svg" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
33
+ <circle cx="12" cy="12" r="10"></circle>
34
+ <line x1="12" y1="16" x2="12" y2="12"></line>
35
+ <line x1="12" y1="8" x2="12.01" y2="8"></line>
36
+ </svg>
37
+ <span class="info-tooltip-text">{ui.logReductionTooltip}</span>
38
+ </div>
39
+ </div>
40
+ </div>
41
+
42
+ <div class="safety-indicator-card">
43
+ <div id="canning-status-badge" class="canning-status-badge safety-unsafe">
44
+ <span id="canning-status-badge-text">{ui.statusUnsafe}</span>
45
+ </div>
46
+ <p id="canning-status-description" class="canning-status-desc">{ui.statusUnsafeDesc}</p>
47
+ </div>
48
+ </div>
@@ -0,0 +1,60 @@
1
+ ---
2
+ interface Props {
3
+ ui: Record<string, string>;
4
+ }
5
+
6
+ const { ui } = Astro.props;
7
+ ---
8
+
9
+ <div class="canning-controller-panel">
10
+ <div class="controller-section">
11
+ <div class="controller-title">{ui.methodLabel}</div>
12
+ <div class="method-toggle-group">
13
+ <button type="button" id="toggle-water-bath-btn" class="method-select-btn active">{ui.waterBath}</button>
14
+ <button type="button" id="toggle-pressure-canner-btn" class="method-select-btn">{ui.pressureCanner}</button>
15
+ </div>
16
+ </div>
17
+
18
+ <div class="controller-section">
19
+ <div class="controller-title">Temperature Unit</div>
20
+ <div class="method-toggle-group">
21
+ <button type="button" id="toggle-celsius-btn" class="method-select-btn active">°C</button>
22
+ <button type="button" id="toggle-fahrenheit-btn" class="method-select-btn">°F</button>
23
+ </div>
24
+ </div>
25
+
26
+ <div class="controller-section parameters-box">
27
+ <div class="parameter-row">
28
+ <div class="param-header-label">
29
+ <label for="temp-input">{ui.tempLabel}</label>
30
+ <div class="param-input-wrapper">
31
+ <input type="number" id="temp-input" value="100" min="90" max="130" step="1" class="param-number" />
32
+ <span class="param-unit" id="temp-unit-display">{ui.cLabel}</span>
33
+ </div>
34
+ </div>
35
+ <input type="range" id="temp-slider" min="90" max="130" step="1" value="100" class="autoclave-slider" />
36
+ </div>
37
+
38
+ <div class="parameter-row">
39
+ <div class="param-header-label">
40
+ <label for="time-input">{ui.timeLabel}</label>
41
+ <div class="param-input-wrapper">
42
+ <input type="number" id="time-input" value="30" min="1" max="180" step="1" class="param-number" />
43
+ <span class="param-unit">{ui.minLabel}</span>
44
+ </div>
45
+ </div>
46
+ <input type="range" id="time-slider" min="1" max="180" step="1" value="30" class="autoclave-slider" />
47
+ </div>
48
+
49
+ <div class="parameter-row">
50
+ <div class="param-header-label">
51
+ <label for="ph-input">{ui.phLabel}</label>
52
+ <div class="param-input-wrapper">
53
+ <input type="text" id="ph-input" value="5.0" class="param-number" inputmode="decimal" />
54
+ <span class="param-unit">pH</span>
55
+ </div>
56
+ </div>
57
+ <input type="range" id="ph-slider" min="2.0" max="7.0" step="0.1" value="5.0" class="autoclave-slider" />
58
+ </div>
59
+ </div>
60
+ </div>
@@ -0,0 +1,26 @@
1
+ import type { CookingToolEntry } from '../../types';
2
+
3
+ export const botulismCanningSafety: CookingToolEntry = {
4
+ id: 'botulism-canning-safety',
5
+ icons: {
6
+ bg: 'mdi:alert-decagram',
7
+ fg: 'mdi:flask-round-bottom',
8
+ },
9
+ i18n: {
10
+ en: () => import('./i18n/en').then((m) => m.content),
11
+ de: () => import('./i18n/de').then((m) => m.content),
12
+ es: () => import('./i18n/es').then((m) => m.content),
13
+ fr: () => import('./i18n/fr').then((m) => m.content),
14
+ id: () => import('./i18n/id').then((m) => m.content),
15
+ it: () => import('./i18n/it').then((m) => m.content),
16
+ ja: () => import('./i18n/ja').then((m) => m.content),
17
+ ko: () => import('./i18n/ko').then((m) => m.content),
18
+ nl: () => import('./i18n/nl').then((m) => m.content),
19
+ pl: () => import('./i18n/pl').then((m) => m.content),
20
+ pt: () => import('./i18n/pt').then((m) => m.content),
21
+ ru: () => import('./i18n/ru').then((m) => m.content),
22
+ sv: () => import('./i18n/sv').then((m) => m.content),
23
+ tr: () => import('./i18n/tr').then((m) => m.content),
24
+ zh: () => import('./i18n/zh').then((m) => m.content),
25
+ },
26
+ };