@jjlmoya/utils-diy 1.22.0 → 1.23.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 (89) hide show
  1. package/package.json +1 -1
  2. package/src/tests/seo_parity.test.ts +60 -0
  3. package/src/tests/translation_copy.test.ts +124 -0
  4. package/src/tool/epoxyCalculator/i18n/de.ts +2 -1
  5. package/src/tool/epoxyCalculator/i18n/id.ts +2 -1
  6. package/src/tool/epoxyCalculator/i18n/it.ts +2 -1
  7. package/src/tool/epoxyCalculator/i18n/ja.ts +2 -1
  8. package/src/tool/epoxyCalculator/i18n/ko.ts +2 -1
  9. package/src/tool/epoxyCalculator/i18n/nl.ts +2 -1
  10. package/src/tool/epoxyCalculator/i18n/pl.ts +2 -1
  11. package/src/tool/epoxyCalculator/i18n/pt.ts +2 -1
  12. package/src/tool/epoxyCalculator/i18n/ru.ts +2 -1
  13. package/src/tool/epoxyCalculator/i18n/sv.ts +2 -1
  14. package/src/tool/epoxyCalculator/i18n/tr.ts +2 -1
  15. package/src/tool/epoxyCalculator/i18n/zh.ts +2 -1
  16. package/src/tool/furnitureFit/i18n/de.ts +2 -1
  17. package/src/tool/furnitureFit/i18n/id.ts +2 -1
  18. package/src/tool/furnitureFit/i18n/it.ts +2 -1
  19. package/src/tool/furnitureFit/i18n/ja.ts +2 -1
  20. package/src/tool/furnitureFit/i18n/ko.ts +2 -1
  21. package/src/tool/furnitureFit/i18n/nl.ts +2 -1
  22. package/src/tool/furnitureFit/i18n/pl.ts +2 -1
  23. package/src/tool/furnitureFit/i18n/pt.ts +2 -1
  24. package/src/tool/furnitureFit/i18n/ru.ts +2 -1
  25. package/src/tool/furnitureFit/i18n/sv.ts +2 -1
  26. package/src/tool/furnitureFit/i18n/tr.ts +2 -1
  27. package/src/tool/furnitureFit/i18n/zh.ts +2 -1
  28. package/src/tool/mortarCalculator/i18n/de.ts +5 -1
  29. package/src/tool/mortarCalculator/i18n/es.ts +2 -6
  30. package/src/tool/mortarCalculator/i18n/id.ts +5 -1
  31. package/src/tool/mortarCalculator/i18n/it.ts +5 -1
  32. package/src/tool/mortarCalculator/i18n/ja.ts +5 -1
  33. package/src/tool/mortarCalculator/i18n/ko.ts +5 -1
  34. package/src/tool/mortarCalculator/i18n/nl.ts +5 -1
  35. package/src/tool/mortarCalculator/i18n/pl.ts +5 -1
  36. package/src/tool/mortarCalculator/i18n/pt.ts +5 -1
  37. package/src/tool/mortarCalculator/i18n/ru.ts +5 -1
  38. package/src/tool/mortarCalculator/i18n/sv.ts +5 -1
  39. package/src/tool/mortarCalculator/i18n/tr.ts +5 -1
  40. package/src/tool/mortarCalculator/i18n/zh.ts +5 -1
  41. package/src/tool/passepartoutCalculator/i18n/de.ts +5 -1
  42. package/src/tool/passepartoutCalculator/i18n/id.ts +5 -1
  43. package/src/tool/passepartoutCalculator/i18n/it.ts +5 -1
  44. package/src/tool/passepartoutCalculator/i18n/ja.ts +5 -1
  45. package/src/tool/passepartoutCalculator/i18n/ko.ts +5 -1
  46. package/src/tool/passepartoutCalculator/i18n/nl.ts +5 -1
  47. package/src/tool/passepartoutCalculator/i18n/pl.ts +5 -1
  48. package/src/tool/passepartoutCalculator/i18n/pt.ts +5 -1
  49. package/src/tool/passepartoutCalculator/i18n/ru.ts +5 -1
  50. package/src/tool/passepartoutCalculator/i18n/sv.ts +5 -1
  51. package/src/tool/passepartoutCalculator/i18n/tr.ts +5 -1
  52. package/src/tool/passepartoutCalculator/i18n/zh.ts +5 -1
  53. package/src/tool/stairCalculator/i18n/de.ts +3 -1
  54. package/src/tool/stairCalculator/i18n/id.ts +3 -1
  55. package/src/tool/stairCalculator/i18n/it.ts +3 -1
  56. package/src/tool/stairCalculator/i18n/ja.ts +3 -1
  57. package/src/tool/stairCalculator/i18n/ko.ts +3 -1
  58. package/src/tool/stairCalculator/i18n/nl.ts +3 -1
  59. package/src/tool/stairCalculator/i18n/pl.ts +3 -1
  60. package/src/tool/stairCalculator/i18n/pt.ts +3 -1
  61. package/src/tool/stairCalculator/i18n/ru.ts +3 -1
  62. package/src/tool/stairCalculator/i18n/sv.ts +3 -1
  63. package/src/tool/stairCalculator/i18n/tr.ts +3 -1
  64. package/src/tool/stairCalculator/i18n/zh.ts +3 -1
  65. package/src/tool/thermalExpansionCalculator/i18n/de.ts +5 -1
  66. package/src/tool/thermalExpansionCalculator/i18n/id.ts +7 -1
  67. package/src/tool/thermalExpansionCalculator/i18n/it.ts +7 -1
  68. package/src/tool/thermalExpansionCalculator/i18n/ja.ts +7 -1
  69. package/src/tool/thermalExpansionCalculator/i18n/ko.ts +7 -1
  70. package/src/tool/thermalExpansionCalculator/i18n/nl.ts +7 -1
  71. package/src/tool/thermalExpansionCalculator/i18n/pl.ts +7 -1
  72. package/src/tool/thermalExpansionCalculator/i18n/pt.ts +7 -1
  73. package/src/tool/thermalExpansionCalculator/i18n/ru.ts +7 -1
  74. package/src/tool/thermalExpansionCalculator/i18n/sv.ts +7 -1
  75. package/src/tool/thermalExpansionCalculator/i18n/tr.ts +7 -1
  76. package/src/tool/thermalExpansionCalculator/i18n/zh.ts +7 -1
  77. package/src/tool/voltageDropCalculator/i18n/de.ts +5 -1
  78. package/src/tool/voltageDropCalculator/i18n/fr.ts +3 -1
  79. package/src/tool/voltageDropCalculator/i18n/id.ts +7 -1
  80. package/src/tool/voltageDropCalculator/i18n/it.ts +7 -1
  81. package/src/tool/voltageDropCalculator/i18n/ja.ts +7 -1
  82. package/src/tool/voltageDropCalculator/i18n/ko.ts +7 -1
  83. package/src/tool/voltageDropCalculator/i18n/nl.ts +7 -1
  84. package/src/tool/voltageDropCalculator/i18n/pl.ts +7 -1
  85. package/src/tool/voltageDropCalculator/i18n/pt.ts +7 -1
  86. package/src/tool/voltageDropCalculator/i18n/ru.ts +7 -1
  87. package/src/tool/voltageDropCalculator/i18n/sv.ts +7 -1
  88. package/src/tool/voltageDropCalculator/i18n/tr.ts +7 -1
  89. package/src/tool/voltageDropCalculator/i18n/zh.ts +7 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jjlmoya/utils-diy",
3
- "version": "1.22.0",
3
+ "version": "1.23.0",
4
4
  "type": "module",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -0,0 +1,60 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { ALL_ENTRIES } from '../entries';
3
+ import type { KnownLocale } from '../types';
4
+
5
+ interface ExpectedCounts {
6
+ seo: number;
7
+ faq: number;
8
+ howTo: number;
9
+ }
10
+
11
+ function countItems(arr: unknown[] | undefined): number {
12
+ return arr?.length ?? 0;
13
+ }
14
+
15
+ async function verifyLocaleParity(
16
+ entry: typeof ALL_ENTRIES[number],
17
+ loc: KnownLocale,
18
+ expected: ExpectedCounts,
19
+ ): Promise<void> {
20
+ const locContent = await entry.i18n[loc]?.();
21
+ expect(locContent, `Locale ${loc} missing content`).toBeDefined();
22
+
23
+ const locSeoCount = countItems(locContent?.seo);
24
+ const locFaqCount = countItems(locContent?.faq);
25
+ const locHowToCount = countItems(locContent?.howTo);
26
+
27
+ expect(
28
+ locSeoCount,
29
+ `Locale ${loc} SEO sections count (${locSeoCount}) must match EN (${expected.seo})`,
30
+ ).toBe(expected.seo);
31
+ expect(
32
+ locFaqCount,
33
+ `Locale ${loc} FAQ items count (${locFaqCount}) must match EN (${expected.faq})`,
34
+ ).toBe(expected.faq);
35
+ expect(
36
+ locHowToCount,
37
+ `Locale ${loc} HowTo steps count (${locHowToCount}) must match EN (${expected.howTo})`,
38
+ ).toBe(expected.howTo);
39
+ }
40
+
41
+ describe('SEO & i18n Structural Parity Suite', () => {
42
+ ALL_ENTRIES.forEach((entry) => {
43
+ describe(`Tool: ${entry.id}`, () => {
44
+ it('all 15 locales should have identical SEO section counts and types as English', async () => {
45
+ const enContent = await entry.i18n.en?.();
46
+ expect(enContent).toBeDefined();
47
+ const expected: ExpectedCounts = {
48
+ seo: countItems(enContent?.seo),
49
+ faq: countItems(enContent?.faq),
50
+ howTo: countItems(enContent?.howTo),
51
+ };
52
+
53
+ const locales = Object.keys(entry.i18n) as KnownLocale[];
54
+ for (const loc of locales) {
55
+ await verifyLocaleParity(entry, loc, expected);
56
+ }
57
+ });
58
+ });
59
+ });
60
+ });
@@ -0,0 +1,124 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ALL_ENTRIES } from '../entries';
3
+
4
+ const COPY_THRESHOLD = 0.9;
5
+
6
+ const STRUCTURAL_KEYS = new Set([
7
+ '@context',
8
+ '@type',
9
+ 'applicationCategory',
10
+ 'columns',
11
+ 'highlight',
12
+ 'icon',
13
+ 'level',
14
+ 'operatingSystem',
15
+ 'position',
16
+ 'positive',
17
+ 'price',
18
+ 'priceCurrency',
19
+ 'slug',
20
+ 'trend',
21
+ 'type',
22
+ 'url',
23
+ 'value',
24
+ 'variant',
25
+ ]);
26
+
27
+ function normalizeText(value: string): string {
28
+ return value
29
+ .replace(/<[^>]*>/g, ' ')
30
+ .replace(/&(?:amp|lt|gt|quot|apos|nbsp);/gi, ' ')
31
+ .replace(/[\u2018\u2019]/g, "'")
32
+ .replace(/[\u201c\u201d]/g, '"')
33
+ .replace(/\s+/g, ' ')
34
+ .trim()
35
+ .toLocaleLowerCase();
36
+ }
37
+
38
+ function collectText(value: unknown, path: string, parts: string[]): void {
39
+ if (typeof value === 'string') {
40
+ const normalized = normalizeText(value);
41
+ if (normalized.length >= 2) parts.push(normalized);
42
+ return;
43
+ }
44
+
45
+ if (Array.isArray(value)) {
46
+ value.forEach((item, index) => collectText(item, `${path}[${index}]`, parts));
47
+ return;
48
+ }
49
+
50
+ if (!value || typeof value !== 'object') return;
51
+
52
+ Object.entries(value).forEach(([key, child]) => {
53
+ if (STRUCTURAL_KEYS.has(key)) return;
54
+ collectText(child, `${path}.${key}`, parts);
55
+ });
56
+ }
57
+
58
+ function localeCorpus(content: unknown): string {
59
+ if (!content || typeof content !== 'object') return '';
60
+
61
+ const record = content as Record<string, unknown>;
62
+ const parts: string[] = [];
63
+ collectText(record.title, 'title', parts);
64
+ collectText(record.description, 'description', parts);
65
+ collectText(record.faqTitle, 'faqTitle', parts);
66
+ collectText(record.faq, 'faq', parts);
67
+ collectText(record.seo, 'seo', parts);
68
+ collectText(record.schemas, 'schemas', parts);
69
+ return parts.join(' ');
70
+ }
71
+
72
+ function tokenCounts(text: string): Map<string, number> {
73
+ const counts = new Map<string, number>();
74
+ for (const token of text.match(/[\p{L}\p{N}]+/gu) ?? []) {
75
+ counts.set(token, (counts.get(token) ?? 0) + 1);
76
+ }
77
+ return counts;
78
+ }
79
+
80
+ function copySimilarity(left: string, right: string): number {
81
+ const leftCounts = tokenCounts(left);
82
+ const rightCounts = tokenCounts(right);
83
+ const leftTotal = [...leftCounts.values()].reduce((sum, count) => sum + count, 0);
84
+ const rightTotal = [...rightCounts.values()].reduce((sum, count) => sum + count, 0);
85
+ if (leftTotal === 0 || rightTotal === 0) return 0;
86
+
87
+ let shared = 0;
88
+ for (const [token, count] of leftCounts) {
89
+ shared += Math.min(count, rightCounts.get(token) ?? 0);
90
+ }
91
+ return (2 * shared) / (leftTotal + rightTotal);
92
+ }
93
+
94
+ describe('Locales must not copy another locale wholesale', () => {
95
+ ALL_ENTRIES.forEach((entry) => {
96
+ it(`${entry.id} is not at least ${COPY_THRESHOLD * 100}% identical to another locale`, async () => {
97
+ const corpora = new Map<string, string>();
98
+
99
+ for (const [locale, loader] of Object.entries(entry.i18n)) {
100
+ if (!loader) continue;
101
+ corpora.set(locale, localeCorpus(await loader()));
102
+ }
103
+
104
+ const locales = [...corpora.keys()];
105
+ const violations: string[] = [];
106
+
107
+ for (let leftIndex = 0; leftIndex < locales.length; leftIndex += 1) {
108
+ for (let rightIndex = leftIndex + 1; rightIndex < locales.length; rightIndex += 1) {
109
+ const left = locales[leftIndex];
110
+ const right = locales[rightIndex];
111
+ const similarity = copySimilarity(corpora.get(left) ?? '', corpora.get(right) ?? '');
112
+
113
+ if (similarity >= COPY_THRESHOLD) {
114
+ violations.push(`${left} ↔ ${right}: ${(similarity * 100).toFixed(1)}%`);
115
+ }
116
+ }
117
+ }
118
+
119
+ expect(violations, `Locale copy threshold exceeded in ${entry.id}`).toEqual([]);
120
+ });
121
+ });
122
+ });
123
+
124
+
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Überlebenswichtige Temperatur', html: '<p>Arbeiten Sie immer zwischen <strong>21°C und 25°C</strong>. Kälte kann die Reaktion stoppen und das Teil trüb machen. Übermäßige Hitze beschleunigt die exotherme Reaktion gefährlich ("Flash Cure").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Zwei Becher Methode', html: '<p>Vertrauen Sie nicht auf eine einzige Mischung. Kratzen Sie die Seiten und den Boden gut ab, gießen Sie die Mischung in einen <strong>zweiten sauberen Becher</strong> und mischen Sie erneut. Dies stellt sicher, dass kein unkatalysiertes Material zurückbleibt.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Deuten Sie das Ergebnis gemeinsam mit den angezeigten Annahmen, bevor Sie es verwenden." },],
93
94
  ui: {
94
95
  shapeRect: 'Rechteckig',
95
96
  shapeCylinder: 'Zylindrisch',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Suhu Vital', html: '<p>Bekerjalah selalu antara <strong>21°C hingga 25°C</strong>. Suhu dingin dapat menghentikan reaksi, membuat benda menjadi keruh. Panas berlebih mempercepat reaksi eksotermik secara berbahaya ("flash cure").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Teknik Dua Wadah', html: '<p>Jangan mengandalkan satu pengadukan. Bersihkan sisi dan dasar wadah dengan baik, tuang campuran ke <strong>wadah bersih kedua</strong> dan aduk kembali. Ini memastikan tidak ada bahan yang tidak terkatalis tertinggal.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Tafsirkan hasil bersama asumsi yang ditampilkan kalkulator sebelum menggunakannya." },],
93
94
  ui: {
94
95
  shapeRect: 'Persegi Panjang',
95
96
  shapeCylinder: 'Silinder',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Temperatura Vitale', html: '<p>Lavora sempre tra <strong>21°C e 25°C</strong>. Il freddo può fermare la reazione, lasciando il pezzo torbido. Il calore eccessivo accelera pericolosamente la reazione esotermica ("flash cure").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Tecnica del Doppio Bicchiere', html: '<p>Non fidarti di una sola miscelazione. Raschia bene i lati e il fondo, versa la miscela in un <strong>secondo bicchiere pulito</strong> e mescola di nuovo. Questo assicura che non rimanga materiale non catalizzato.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Interpreta il risultato insieme alle ipotesi mostrate dal calcolatore prima di utilizzarlo." },],
93
94
  ui: {
94
95
  shapeRect: 'Rettangolare',
95
96
  shapeCylinder: 'Cilindrico',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: '重要な温度', html: '<p>常に <strong>21°C から 25°C</strong> の間で作業してください。寒さは反応を止め、作品を白濁させることがあります。過度の熱は放熱反応を危険なほど加速させます(フラッシュキュア)。</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'ダブルカップ法', html: '<p>一度の混合を過信しないでください。カップの側面と底をよく削り、混合物を<strong>2つ目の清潔なカップ</strong>に移して再度混ぜます。これにより、未反応の材料が残るのを防ぎます。</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "利用する前に、計算機が示す前提条件と結果を一緒に確認してください。" },],
93
94
  ui: {
94
95
  shapeRect: '長方形',
95
96
  shapeCylinder: '円柱形',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: '중요 온도', html: '<p>항상 <strong>21°C에서 25°C</strong> 사이에서 작업하세요. 추위는 반응을 멈추게 하여 결과물을 탁하게 만들 수 있습니다. 과도한 열은 방열 반응을 위험할 정도로 가속화합니다(플래시 큐어).</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: '더블 컵 기법', html: '<p>한 번의 혼합을 너무 믿지 마세요. 벽면과 바닥을 잘 긁어낸 뒤 혼합물을 <strong>두 번째 깨끗한 컵</strong>에 옮겨 닮아 다시 섞어주세요. 이렇게 하면 촉매가 섞이지 않은 재료가 남지 않습니다.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "사용하기 전에 계산기가 표시한 가정과 결과를 함께 확인하세요." },],
93
94
  ui: {
94
95
  shapeRect: '직사각형',
95
96
  shapeCylinder: '원기둥',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Vitale Temperatuur', html: '<p>Werk altijd tussen de <strong>21°C en 25°C</strong>. Kou kan de reactie stoppen, waardoor het werkstuk troebel wordt. Overmatige hitte versnelt de exotherme reactie gevaarlijk ("flash cure").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Dubbele Beker Techniek', html: '<p>Vertrouw niet op één enkele menging. Schraap de zijkanten en bodem goed af, giet het mengsel in een <strong>tweede schone beker</strong> en meng opnieuw. Dit zorgt ervoor dat er geen ongekatalyseerd materiaal achterblijft.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Interpreteer het resultaat samen met de aannames van de calculator voordat u het gebruikt." },],
93
94
  ui: {
94
95
  shapeRect: 'Rechthoekig',
95
96
  shapeCylinder: 'Cilindrisch',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Kluczowa Temperatura', html: '<p>Zawsze pracuj w temperaturze między <strong>21°C a 25°C</strong>. Zimno może zatrzymać reakcję, sprawiając, że element będzie mętny. Nadmierne ciepło niebezpiecznie przyspiesza reakcję egzotermiczną ("flash cure").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Technika Dwóch Kubków', html: '<p>Nie ufaj jednokrotnemu wymieszaniu. Dobrze zeskrob boki i dno naczynia, przelej mieszankę do <strong>drugiego czystego kubka</strong> i wymieszaj ponownie. Zapewnia to, że nie pozostanie żaden nieskatalizowany materiał.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Przed użyciem zinterpretuj wynik razem z założeniami pokazanymi przez kalkulator." },],
93
94
  ui: {
94
95
  shapeRect: 'Prostokątny',
95
96
  shapeCylinder: 'Cylindryczny',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Temperatura Vital', html: '<p>Trabalhe sempre entre <strong>21°C e 25°C</strong>. O frio pode parar a reação, deixando a peça turva. O calor excessivo acelera a reação exotérmica perigosamente ("flash cure").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Técnica do Copo Duplo', html: '<p>Não confie numa única mistura. Raspe bem os lados e o fundo, verta a mistura num <strong>segundo copo limpo</strong> e volte a misturar. Isto assegura que não resta material sem catalisar.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Interprete o resultado juntamente com as premissas apresentadas pela calculadora antes de o utilizar." },],
93
94
  ui: {
94
95
  shapeRect: 'Retangular',
95
96
  shapeCylinder: 'Cilíndrico',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Важность температуры', html: '<p>Всегда работайте при температуре от <strong>21°C до 25°C</strong>. Холод может остановить реакцию, сделав изделие мутным. Чрезмерное тепло опасно ускоряет экзотермическую реакцию ("вспышка").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Техника "двойного стакана"', html: '<p>Не полагайтесь на одно смешивание. Тщательно соскребите смолу со стенок и дна, перелейте смесь во <strong>второй чистый стакан</strong> и перемешайте снова. Это гарантирует отсутствие остатков непрореагировавшего материала.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Перед использованием интерпретируйте результат вместе с допущениями, указанными калькулятором." },],
93
94
  ui: {
94
95
  shapeRect: 'Прямоугольная',
95
96
  shapeCylinder: 'Цилиндрическая',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Livsviktig temperatur', html: '<p>Arbeta alltid mellan <strong>21°C och 25°C</strong>. Kyla kan stoppa reaktionen och göra biten grumlig. Överdriven värme accelererar den exoterma reaktionen farligt mycket ("flash cure").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Dubbelbägarmetoden', html: '<p>Lita inte på en enda blandning. Skrapa noga sidorna och botten, häll blandningen i en <strong>andra ren bägare</strong> und blanda igen. Detta säkerställer att inget okatalyserat material blir kvar.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Tolka resultatet tillsammans med kalkylatorns antaganden innan du använder det." },],
93
94
  ui: {
94
95
  shapeRect: 'Rektangulär',
95
96
  shapeCylinder: 'Cylindrisk',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: 'Hayati Sıcaklık', html: '<p>Daima <strong>21°C ile 25°C</strong> arasında çalışın. Soğuk reaksiyonu durdurarak parçanın bulanık kalmasına neden olabilir. Aşırı ısı ekzotermik reaksiyonu tehlikeli bir şekilde hızlandırır ("flash cure").</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: 'Çift Bardak Tekniği', html: '<p>Tek bir karıştırmaya güvenmeyin. Kenarları ve tabanı iyice sıyırın, karışımı <strong>ikinci temiz bir bardağa</strong> dökün ve tekrar karıştırın. Bu, katalize olmamış hiçbir malzemenin kalmamasını sağlar.</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "Kullanmadan önce sonucu hesaplayıcının gösterdiği varsayımlarla birlikte yorumlayın." },],
93
94
  ui: {
94
95
  shapeRect: 'Dikdörtgen',
95
96
  shapeCylinder: 'Silindirik',
@@ -89,7 +89,8 @@ export const content: ToolLocaleContent<EpoxyCalculatorUI> = {
89
89
  { type: 'card', icon: 'mdi:thermometer', title: '关键温度', html: '<p>始终在 <strong>21°C 至 25°C</strong> 之间操作。寒冷会中止反应,使作品变得混浊。热量过高会危险地加速放热反应(爆聚)。</p>' },
90
90
  { type: 'card', icon: 'mdi:cup-outline', title: '双杯混合法', html: '<p>不要依赖单次混合。彻底刮净杯壁和杯底,将混合物倒入<strong>第二个干净的杯子</strong>中再次搅拌。这可以确保没有未反应的材料残留。</p>' },
91
91
  ]},
92
- ],
92
+
93
+ { type: 'paragraph', html: "使用前请结合计算器显示的假设一起解读结果。" },],
93
94
  ui: {
94
95
  shapeRect: '矩形',
95
96
  shapeCylinder: '圆柱形',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Manövrierspielraum', html: '<p>Ein häufiger Fehler ist die Annahme, dass das Möbelstück passt, wenn es 80 cm misst und die Öffnung ebenfalls 80 cm beträgt. Das ist nicht der Fall. Die Hände der Träger, die Elastizität des Stoffes und Unebenheiten der Wände erfordern eine Mindestmarge von <strong>2 bis 5 cm</strong>. Ohne diese Marge wird das Möbelstück zerkratzt oder verkeilt sich.</p>' },
86
86
  { type: 'title', text: '3 Fehler, die einen Umzug ruinieren', level: 3 },
87
87
  { type: 'paragraph', html: 'Selbst mit korrekten Maßen verursachen diese unsichtbaren Faktoren oft Katastrophen: <strong>Die Deckenlampe</strong> - oft vergessen bei diagonalen Drehungen; <strong>Der Schwenkradius</strong> - ein starres Möbelstück biegt sich nicht; <strong>Die Verpackung</strong> - Luftpolsterfolie kann auf jeder Seite 1 bis 3 cm hinzufügen.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Nutzen Sie das Ergebnis zur Planung und zum Szenarienvergleich; es ersetzt keine offizielle Berechnung oder Fachberatung." },],
89
90
  ui: {
90
91
  conTitle: 'Abmessungen des Raums',
91
92
  conHint: 'Z.B. Standardaufzug, Türrahmen oder Lieferwagen.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Margin Manuver', html: '<p>Kesalahan umum adalah mengasumsikan jika furnitur berukuran 80cm dan celahnya 80cm, maka akan muat. Tidak seperti itu. Tangan pengangkut, elastisitas kain, dan ketidaksempurnaan dinding memerlukan margin minimal <strong>2 hingga 5 cm</strong>. Tanpa margin ini, furnitur akan tergores atau terjepit karena tekanan.</p>' },
86
86
  { type: 'title', text: '3 Kesalahan yang Merusak Pindahan', level: 3 },
87
87
  { type: 'paragraph', html: 'Meskipun dengan ukuran yang benar, faktor tak kasat mata ini sering menyebabkan bencana: <strong>Lampu Langit-langit</strong> - terlupakan saat pemutaran diagonal; <strong>Radius Putar Furnitur</strong> - furnitur yang kaku tidak bisa ditekuk; <strong>Kemasan</strong> - bubble wrap dan kardus pelindung dapat menambah 1 hingga 3 cm di setiap sisi.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Gunakan hasil untuk perencanaan dan perbandingan skenario; hasil ini bukan pengganti perhitungan resmi atau nasihat ahli." },],
89
90
  ui: {
90
91
  conTitle: 'Dimensi Ruang',
91
92
  conHint: 'Contoh: Lift standar, kusen pintu, atau mobil boks.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Margine di Manovra', html: '<p>Un errore comune è assumere che se il mobile misura 80cm e il vano 80cm, passerà. Non è così. Le mani dei trasportatori, l\'elasticità del tessuto e le imperfezioni delle pareti richiedono un margine minimo di <strong>2-5 cm</strong>. Senza questo margine, il mobile si graffierà o rimarrà incastrato per pressione.</p>' },
86
86
  { type: 'title', text: 'I 3 Errori che Rovinano un Traslocco', level: 3 },
87
87
  { type: 'paragraph', html: 'Anche con misure corrette, questi fattori invisibili causano spesso disastri: <strong>La Lampada a Soffitto</strong> - dimenticata durante la rotazione diagonale; <strong>Il Raggio di Rotazione del Mobile</strong> - un mobile rigido non si piega; <strong>L\'Imballaggio</strong> - il pluriball può aggiungere da 1 a 3 cm per lato.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Usa il risultato per pianificare e confrontare scenari; non sostituisce un calcolo ufficiale o una consulenza professionale." },],
89
90
  ui: {
90
91
  conTitle: 'Dimensioni dello Spazio',
91
92
  conHint: 'Es: Ascensore standard, telaio porta o furgone.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: '操作の余裕', html: '<p>家具が80cmで開口部が80cmなら通ると思い込むのはよくある間違いです。そうではありません。作業員の手、生地の弾力性、壁の凹凸などを考慮すると、最低 <strong>2〜5 cm</strong> の余裕が必要です。この余裕がないと、家具が傷ついたり圧迫されて動かなくなったりします。</p>' },
86
86
  { type: 'title', text: '引越しを台無しにする3つの間違い', level: 3 },
87
87
  { type: 'paragraph', html: '正しい採寸をしていても、これら見えない要因が災いをもたらすことがあります:<strong>天井の照明</strong> - 対角線回転中に忘れられがちです。<strong>家具の回転半径</strong> - 固い家具は曲がりません。<strong>梱包</strong> - プチプチや保護用ダンボールは各辺に1〜3cm加わります。' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "結果は計画や条件比較に使えますが、公式計算や専門家の助言の代わりにはなりません。" },],
89
90
  ui: {
90
91
  conTitle: 'スペースの寸法',
91
92
  conHint: '例:標準エレベーター、ドア枠、トラックなど。',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: '조작 여유 공간', html: '<p>가구가 80cm이고 입구가 80cm라면 들어갈 것이라고 생각하는 것은 흔한 실수입니다. 그렇지 않습니다. 작업자의 손, 원단의 탄성, 벽의 미세한 굴곡 등을 고려하면 최소 <strong>2~5cm</strong>의 여유가 필요합니다. 이 여유가 없으면 가구가 긁히거나 끼어버릴 수 있습니다.</p>' },
86
86
  { type: 'title', text: '이사를 망치는 3가지 실수', level: 3 },
87
87
  { type: 'paragraph', html: '치수를 정확히 쟀더라도 이러한 보이지 않는 요인이 종종 문제를 일으킵니다: <strong>천장 조명</strong> - 대각선 회전 중에 잊어버리기 쉽습니다. <strong>가구의 회전 반경</strong> - 딱딱한 가구는 구부러지지 않습니다. <strong>포장</strong> - 뽁뽁이(에어캡)나 보호용 박스는 각 면에 1~3cm를 추가합니다.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "결과는 계획과 시나리오 비교에 사용할 수 있지만 공식 계산이나 전문가 조언을 대신하지 않습니다." },],
89
90
  ui: {
90
91
  conTitle: '공간 치수',
91
92
  conHint: '예: 표준 엘리베이터, 문틀 또는 트럭.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Manoeuvreerruimte', html: '<p>Een veelvoorkomende fout is aan te nemen dat als het meubel 80cm breed is en de opening ook 80cm, het zal passen. Dat is niet zo. De handen van verhuizers, de elasticiteit van de stof en oneffenheden van de muren vereisen een minimale marge van <strong>2 tot 5 cm</strong>. Zonder deze marge wordt het meubel bekrast of raakt het klem.</p>' },
86
86
  { type: 'title', text: '3 Fouten die een Verhuizing Verpesten', level: 3 },
87
87
  { type: 'paragraph', html: 'Zelfs met de juiste maten veroorzaken deze onzichtbare factoren vaak rampen: <strong>De Plafondlamp</strong> - vaak vergeten tijdens het schuin draaien. <strong>De Draaicirkel van het Meubel</strong> - een stijf meubel buigt niet. <strong>De Verpakking</strong> - bubbeltjesplastic kan aan elke kant 1 tot 3 cm toevoegen.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Gebruik het resultaat voor planning en scenariokeuze; het vervangt geen officiële berekening of professioneel advies." },],
89
90
  ui: {
90
91
  conTitle: 'Afmetingen van de Ruimte',
91
92
  conHint: 'Bijv: Standaard lift, deurkozijn of bestelbus.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Margines Manewru', html: '<p>Częstym błędem jest zakładanie, że jeśli mebel ma 80 cm, a otwór 80 cm, to przejdzie. Tak nie jest. Ręce tragarzy, elastyczność tkaniny i nierówności ścian wymagają minimalnego marginesu <strong>od 2 do 5 cm</strong>. Bez tego marginesu mebel zostanie porysowany lub zaklinuje się pod naciskiem.</p>' },
86
86
  { type: 'title', text: '3 Błędy, które Ruinują Przeprowadzkę', level: 3 },
87
87
  { type: 'paragraph', html: 'Nawet przy poprawnych wymiarach, te niewidoczne czynniki często powodują katastrofy: <strong>Lampa Sufitowa</strong> - często pomijana podczas obracania po skosie. <strong>Promień Skrętu Mebla</strong> - sztywny mebel się nie zgina. <strong>Opakowanie</strong> - folia bąbelkowa i tektura ochronna mogą dodać od 1 do 3 cm z każdej strony.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Używaj wyniku do planowania i porównywania scenariuszy; nie zastępuje obliczeń urzędowych ani porady specjalisty." },],
89
90
  ui: {
90
91
  conTitle: 'Wymiary Przestrzeni',
91
92
  conHint: 'Np. standardowa winda, ościeżnica drzwi lub furgonetka.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Margem de Manobra', html: '<p>Um erro comum é assumir que se o móvel mede 80cm e o vão 80cm, passará. Não é assim. As mãos dos transportadores, a elasticidade do tecido e as imperfeições das paredes requerem uma margem mínima de <strong>2 a 5 cm</strong>. Sem esta margem, o móvel ficará riscado ou encravado por pressão.</p>' },
86
86
  { type: 'title', text: 'Os 3 Erros que Arruínam uma Mudança', level: 3 },
87
87
  { type: 'paragraph', html: 'Mesmo com medidas corretas, estes fatores invisíveis costumam causar desastres: <strong>O Candeeiro do Teto</strong> - esquecido durante a rotação diagonal. <strong>O Raio de Rotação do Móvel</strong> - um móvel rígido não se dobra. <strong>A Embalagem</strong> - o plástico de bolhas pode adicionar de 1 a 3 cm a cada lado.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Use o resultado para planear e comparar cenários; não substitui um cálculo oficial nem aconselhamento profissional." },],
89
90
  ui: {
90
91
  conTitle: 'Dimensões do Espaço',
91
92
  conHint: 'Ex: Elevador padrão, ombreira de porta ou furgão.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Запас для маневра', html: '<p>Распространенная ошибка - полагать, что если мебель 80 см и проем 80 см, то она пройдет. Это не так. Руки грузчиков, эластичность ткани и неровности стен требуют минимального запаса от <strong>2 до 5 см</strong>. Без этого запаса мебель поцарапается или намертво застрянет.</p>' },
86
86
  { type: 'title', text: '3 ошибки, которые портят переезд', level: 3 },
87
87
  { type: 'paragraph', html: 'Даже при правильных замерах эти невидимые факторы часто приводят к катастрофам: <strong>Потолочный светильник</strong> - забытый во время диагонального поворота; <strong>Радиус поворота мебели</strong> - жесткая мебель не гнется; <strong>Упаковка</strong> - пузырчатая пленка может добавить по 1-3 см с каждой стороны.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Используйте результат для планирования и сравнения сценариев; он не заменяет официальный расчёт или консультацию специалиста." },],
89
90
  ui: {
90
91
  conTitle: 'Размеры пространства',
91
92
  conHint: 'Напр.: стандартный лифт, дверной проем или фургон.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Manövreringsutrymme', html: '<p>Ett vanligt misstag är att anta att om möbeln mäter 80 cm och öppningen är 80 cm, så går den igenom. Så är det inte. Flyttkarlarnas händer, tygets elasticitet och väggarnas ojämnheter kräver en minsta marginal på <strong>2 till 5 cm</strong>. Utan denna marginal blir möbeln repad eller fastnar genom tryck.</p>' },
86
86
  { type: 'title', text: '3 fel som förstör en flytt', level: 3 },
87
87
  { type: 'paragraph', html: 'Även med korrekta mått orsakar dessa osynliga faktorer ofta katastrofer: <strong>Taklampan</strong> - ofta bortglömd vid diagonal rotation. <strong>Möbelns svängradie</strong> - en stel möbel böjer sig inte. <strong>Förpackningen</strong> - bubbelplast och skyddskartong kan lägga till 1 till 3 cm på varje sida.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Använd resultatet för planering och scenariejämförelser; det ersätter inte en officiell beräkning eller professionell rådgivning." },],
89
90
  ui: {
90
91
  conTitle: 'Utrymmets dimensioner',
91
92
  conHint: 'T.ex: Standardhiss, dörrkarm eller skåpbil.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: 'Manevra Payı', html: '<p>Mobilya 80 cm ve boşluk 80 cm ise geçeceğini varsaymak yaygın bir hatadır. Öyle değildir. Taşıyıcıların elleri, kumaşın esnekliği ve duvarlardaki kusurlar en az <strong>2 ila 5 cm</strong> pay gerektirir. Bu pay olmadan mobilya çizilir veya baskı nedeniyle sıkışıp kalır.</p>' },
86
86
  { type: 'title', text: 'Taşınmayı Mahveden 3 Hata', level: 3 },
87
87
  { type: 'paragraph', html: 'Doğru ölçümlerle bile bu görünmez faktörler felaketlere yol açar: <strong>Tavan Lambası</strong> - diyagonal dönüş sırasında unutulur; <strong>Mobilya Dönüş Yarıçapı</strong> - sert mobilyalar bükülmez; <strong>Paketleme</strong> - balonlu naylon her iki tarafa da 1-3 cm ekleyebilir.' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "Sonucu planlama ve senaryo karşılaştırması için kullanın; resmî hesabın veya uzman görüşünün yerine geçmez." },],
89
90
  ui: {
90
91
  conTitle: 'Alan Boyutları',
91
92
  conHint: 'Örn: Standart asansör, kapı kasası veya kamyonet.',
@@ -85,7 +85,8 @@ export const content: ToolLocaleContent<FurnitureFitUI> = {
85
85
  { type: 'card', icon: 'mdi:sofa', title: '操作余量', html: '<p>一个常见的错误是假设如果家具宽 80 厘米,门洞宽 80 厘米,就能通过。并非如此。工人的手、织物的弹性以及墙面的不平整都需要至少 <strong>2 到 5 厘米</strong> 的余量。如果没有这个余量,家具会被刮花或被挤住。</p>' },
86
86
  { type: 'title', text: '毁掉搬家的 3 个错误', level: 3 },
87
87
  { type: 'paragraph', html: '即使尺寸正确,这些看不见的因素也常会导致灾难:<strong>吸顶灯</strong> - 在对角线旋转期间常被遗忘;<strong>家具的转弯半径</strong> - 硬家具不会弯曲;<strong>包装</strong> - 气泡膜和保护纸板会在每边增加 1 到 3 厘米。' },
88
- ],
88
+
89
+ { type: 'paragraph', html: "结果可用于规划和比较方案,但不能替代官方计算或专业建议。" },],
89
90
  ui: {
90
91
  conTitle: '空间尺寸',
91
92
  conHint: '例如:标准电梯、门框或货车。',
@@ -83,7 +83,11 @@ export const content: ToolLocaleContent<MortarCalculatorUI> = {
83
83
  { type: 'paragraph', html: 'Die Qualität eines Kalkmörtels hängt maßgeblich von der Korngröße des Zuschlags ab. Für das <strong>Trullissatio</strong> (Grundputz) wird grober Flusssand von 2-5 mm verwendet. Für das <strong>Arenato</strong> (Zwischenputz) gewaschener Mittelsand von 0,5-2 mm. Für das <strong>Marmorato</strong> (Feinputz) Marmormehl unter 0,5 mm.' },
84
84
  { type: 'title', text: 'Der Reiz der mechanischen Haftung', level: 3 },
85
85
  { type: 'paragraph', html: 'Die Haftung ist nicht chemisch, sondern <strong>mechanisch</strong>. Stellen Sie sich Millionen mikroskopisch kleiner Wurzeln vor. Der Mörtel muss in die Poren des Ziegels eindringen, um eine physikalische "Verzahnung" zu schaffen. Ohne Porosität gibt es keine Verankerung.' },
86
- ],
86
+
87
+ { type: 'paragraph', html: "Deuten Sie das Ergebnis gemeinsam mit den angezeigten Annahmen, bevor Sie es verwenden." },
88
+ { type: 'paragraph', html: "Prüfen Sie Eingaben, Einheiten, Rundung, Datum und Recht, weil jedes Element die Schätzung verändern kann." },
89
+ { type: 'paragraph', html: "Nutzen Sie das Ergebnis zur Planung und zum Szenarienvergleich; es ersetzt keine offizielle Berechnung oder Fachberatung." },
90
+ { type: 'paragraph', html: "Deuten Sie das Ergebnis gemeinsam mit den angezeigten Annahmen, bevor Sie es verwenden." },],
87
91
  ui: {
88
92
  leftTitle: 'Vitruvianisches System',
89
93
  centerTitle: 'Verfügbare Materialien',
@@ -133,12 +133,8 @@ export const content: ToolLocaleContent<MortarCalculatorUI> = {
133
133
  html: '<p>El fratasado no es solo alisar; es preparar el futuro. El uso del <strong>fratás de madera</strong> es crucial en las capas base porque "abre el poro", dejando una textura rugosa ideal para que la siguiente capa se agarre. La llana de acero cierra el poro y saca el agua a la superficie ("quemar" el mortero), técnica reservada solo para el enlucido final o estucos.</p><p>El secreto está en el <em>tempo</em>: saber esperar a que el mortero haya "tirado" (endurecido ligeramente) pero siga húmedo. Es un diálogo silencioso entre la herramienta y la cal.</p>',
134
134
  },
135
135
  {
136
- type: 'title',
137
- text: 'El Ciclo de la Cal: Un Material Vivo',
138
- level: 3,
139
- },
140
- {
141
- type: 'paragraph',
136
+ type: 'card',
137
+ title: 'El Ciclo de la Cal: Un Material Vivo',
142
138
  html: 'A diferencia del cemento moderno, la cal es un material "vivo". Fragua lentamente mediante <strong>carbonatación</strong>: absorbe el CO₂ del aire para volver a convertirse en piedra caliza. Es un ciclo eterno: de la piedra venimos y a la piedra volvemos. Esta respiración permite que el edificio se adapte a los movimientos sin agrietarse, sanando sus propias heridas con el tiempo.',
143
139
  },
144
140
  {
@@ -83,7 +83,11 @@ export const content: ToolLocaleContent<MortarCalculatorUI> = {
83
83
  { type: 'paragraph', html: 'Kualitas mortir kapur sangat bergantung pada granulometri agregat. Untuk <strong>Trullissatio</strong> (plester dasar), digunakan pasir sungai kasar 2-5 mm. Untuk <strong>Arenato</strong> (plester menengah), pasir sedang dicuci 0,5-2 mm. Untuk <strong>Marmorato</strong> (acian halus), bubuk marmer kurang dari 0,5 mm.' },
84
84
  { type: 'title', text: 'Misteri Ikatan Mekanis', level: 3 },
85
85
  { type: 'paragraph', html: 'Ikatan ini bukan kimia, melainkan <strong>mekanis</strong>. Bayangkan jutaan akar mikroskopis. Mortir harus menembus ke dalam pori-pori bata untuk menciptakan "kunci" fisik. Tanpa porositas, tidak ada jangkar.' },
86
- ],
86
+
87
+ { type: 'paragraph', html: "Tafsirkan hasil bersama asumsi yang ditampilkan kalkulator sebelum menggunakannya." },
88
+ { type: 'paragraph', html: "Periksa input, satuan, pembulatan, tanggal, dan yurisdiksi karena semuanya dapat mengubah estimasi." },
89
+ { type: 'paragraph', html: "Gunakan hasil untuk perencanaan dan perbandingan skenario; hasil ini bukan pengganti perhitungan resmi atau nasihat ahli." },
90
+ { type: 'paragraph', html: "Tafsirkan hasil bersama asumsi yang ditampilkan kalkulator sebelum menggunakannya." },],
87
91
  ui: {
88
92
  leftTitle: 'Sistem Vitruvius',
89
93
  centerTitle: 'Bahan Tersedia',
@@ -83,7 +83,11 @@ export const content: ToolLocaleContent<MortarCalculatorUI> = {
83
83
  { type: 'paragraph', html: 'La qualità di una malta di calce dipende in gran parte dalla granulometria dell\'inerte. Per il <strong>Trullissatio</strong> (rinzaffo), si usa sabbia grossa di fiume da 2-5 mm. Per l\'<strong>Arenato</strong> (arriccio), sabbia media lavata da 0,5-2 mm. Per il <strong>Marmorato</strong> (lastra fine), polvere di marmo minore di 0,5 mm.' },
84
84
  { type: 'title', text: 'Il Mistero della Presa Meccanica', level: 3 },
85
85
  { type: 'paragraph', html: 'L\'aggancio non è chimico, è <strong>meccanico</strong>. Immagina milioni di radici microscopiche. La malta deve penetrare nei pori del mattone per creare una "chiave" fisica. Senza porosità, non c\'è ancoraggio.' },
86
- ],
86
+
87
+ { type: 'paragraph', html: "Interpreta il risultato insieme alle ipotesi mostrate dal calcolatore prima di utilizzarlo." },
88
+ { type: 'paragraph', html: "Controlla dati, unità, arrotondamento, data e giurisdizione, perché ciascun elemento può cambiare la stima." },
89
+ { type: 'paragraph', html: "Usa il risultato per pianificare e confrontare scenari; non sostituisce un calcolo ufficiale o una consulenza professionale." },
90
+ { type: 'paragraph', html: "Interpreta il risultato insieme alle ipotesi mostrate dal calcolatore prima di utilizzarlo." },],
87
91
  ui: {
88
92
  leftTitle: 'Sistema Vitruviano',
89
93
  centerTitle: 'Materiali Disponibili',
@@ -83,7 +83,11 @@ export const content: ToolLocaleContent<MortarCalculatorUI> = {
83
83
  { type: 'paragraph', html: '石灰モルタルの品質は、骨材の粒度に大きく依存します。<strong>Trullissatio</strong>(下地)には、2-5mmの粗い川砂が使用されます。<strong>Arenato</strong>(中塗り)には、0.5-2mmの洗浄された中砂。<strong>Marmorato</strong>(仕上げ)には、0.5mm以下の大理石粉が使用されます。' },
84
84
  { type: 'title', text: '機械的接着の謎', level: 3 },
85
85
  { type: 'paragraph', html: '接着は化学的ではなく、<strong>機械的</strong>なものです。何百万もの微細な根を想像してください。モルタルはレンガの孔に浸透して、物理的な「鍵」を作る必要があります。多孔性がなければ、定着は望めません。' },
86
- ],
86
+
87
+ { type: 'paragraph', html: "利用する前に、計算機が示す前提条件と結果を一緒に確認してください。" },
88
+ { type: 'paragraph', html: "入力値、単位、丸め、日付、地域を確認してください。どれも推定結果を変える可能性があります。" },
89
+ { type: 'paragraph', html: "結果は計画や条件比較に使えますが、公式計算や専門家の助言の代わりにはなりません。" },
90
+ { type: 'paragraph', html: "利用する前に、計算機が示す前提条件と結果を一緒に確認してください。" },],
87
91
  ui: {
88
92
  leftTitle: 'ヴィトルウィウス方式',
89
93
  centerTitle: '利用可能な材料',
@@ -83,7 +83,11 @@ export const content: ToolLocaleContent<MortarCalculatorUI> = {
83
83
  { type: 'paragraph', html: '석회 모르타르의 품질은 골재의 입도에 크게 좌우됩니다. <strong>Trullissatio</strong>(초벌)에는 2-5mm의 굵은 강모래가 사용됩니다. <strong>Arenato</strong>(중벌)에는 세척된 0.5-2mm의 중간 모래가 사용됩니다. <strong>Marmorato</strong>(정벌)에는 0.5mm 이하의 대리석 가루가 사용됩니다.' },
84
84
  { type: 'title', text: '기계적 접착의 신비', level: 3 },
85
85
  { type: 'paragraph', html: '접착은 화학적인 것이 아니라 <strong>기계적</strong>인 것입니다. 수백만 개의 미세한 뿌리를 상상해 보세요. 모르타르는 벽돌의 기공으로 침투하여 물리적인 "열쇠" 역할을 해야 합니다. 다공성이 없으면 정착이 불가능합니다.' },
86
- ],
86
+
87
+ { type: 'paragraph', html: "사용하기 전에 계산기가 표시한 가정과 결과를 함께 확인하세요." },
88
+ { type: 'paragraph', html: "입력값, 단위, 반올림, 날짜와 관할을 확인하세요. 모두 추정값을 바꿀 수 있습니다." },
89
+ { type: 'paragraph', html: "결과는 계획과 시나리오 비교에 사용할 수 있지만 공식 계산이나 전문가 조언을 대신하지 않습니다." },
90
+ { type: 'paragraph', html: "사용하기 전에 계산기가 표시한 가정과 결과를 함께 확인하세요." },],
87
91
  ui: {
88
92
  leftTitle: '비트루비우스 시스템',
89
93
  centerTitle: '사용 가능한 재료',
@@ -83,7 +83,11 @@ export const content: ToolLocaleContent<MortarCalculatorUI> = {
83
83
  { type: 'paragraph', html: 'De kwaliteit van een kalkmortel hangt grotendeels af van de korrelgrootte van de toeslag. Voor het <strong>Trullissatio</strong> (basis raapwerk) wordt grof rivierzand van 2-5 mm gebruikt. Voor de <strong>Arenato</strong> (tussenlaag), gewassen medium zand van 0,5-2 mm. Voor de <strong>Marmorato</strong> (fijnpleister), marmerpoeder kleiner dan 0,5 mm.' },
84
84
  { type: 'title', text: 'Het Mysterie van de Mechanische Hechting', level: 3 },
85
85
  { type: 'paragraph', html: 'De hechting is niet chemisch, maar <strong>mechanisch</strong>. Stel je miljoenen microscopisch kleine wortels voor. De mortel moet diep in de poriën van de baksteen dringen om een fysieke "sleutel" te creëren. Zonder porositeit is er geen verankering.' },
86
- ],
86
+
87
+ { type: 'paragraph', html: "Interpreteer het resultaat samen met de aannames van de calculator voordat u het gebruikt." },
88
+ { type: 'paragraph', html: "Controleer invoer, eenheden, afronding, datum en jurisdictie, want elk onderdeel kan de schatting wijzigen." },
89
+ { type: 'paragraph', html: "Gebruik het resultaat voor planning en scenariokeuze; het vervangt geen officiële berekening of professioneel advies." },
90
+ { type: 'paragraph', html: "Interpreteer het resultaat samen met de aannames van de calculator voordat u het gebruikt." },],
87
91
  ui: {
88
92
  leftTitle: 'Vitruviaans Systeem',
89
93
  centerTitle: 'Beschikbare Materialen',
@@ -83,7 +83,11 @@ export const content: ToolLocaleContent<MortarCalculatorUI> = {
83
83
  { type: 'paragraph', html: 'Jakość zaprawy wapiennej zależy w dużej mierze od granulacji kruszywa. Dla <strong>Trullissatio</strong> (tynk podkładowy) stosuje się gruby piasek rzeczny 2-5 mm. Dla <strong>Arenato</strong> (narzut pośredni) piasek średni płukany 0,5-2 mm. Dla <strong>Marmorato</strong> (gładź cienka) pył marmurowy poniżej 0,5 mm.' },
84
84
  { type: 'title', text: 'Tajemnica Przyczepności Mechanicznej', level: 3 },
85
85
  { type: 'paragraph', html: 'Przyczepność nie jest chemiczna, lecz <strong>mechaniczna</strong>. Wyobraź sobie miliony mikroskopijnych korzeni. Zaprawa musi wniknąć w pory cegły, aby stworzyć fizyczny "klucz". Bez porowatości nie ma zakotwiczenia.' },
86
- ],
86
+
87
+ { type: 'paragraph', html: "Przed użyciem zinterpretuj wynik razem z założeniami pokazanymi przez kalkulator." },
88
+ { type: 'paragraph', html: "Sprawdź dane, jednostki, zaokrąglenie, datę i jurysdykcję, ponieważ każdy element może zmienić szacunek." },
89
+ { type: 'paragraph', html: "Używaj wyniku do planowania i porównywania scenariuszy; nie zastępuje obliczeń urzędowych ani porady specjalisty." },
90
+ { type: 'paragraph', html: "Przed użyciem zinterpretuj wynik razem z założeniami pokazanymi przez kalkulator." },],
87
91
  ui: {
88
92
  leftTitle: 'System Witruwiański',
89
93
  centerTitle: 'Dostępne Materiały',