@jjlmoya/utils-textiles 1.14.0 → 1.15.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 (93) hide show
  1. package/package.json +1 -1
  2. package/src/category/i18n/de.ts +2 -2
  3. package/src/category/i18n/en.ts +2 -2
  4. package/src/category/i18n/es.ts +2 -2
  5. package/src/category/i18n/fr.ts +9 -9
  6. package/src/category/i18n/id.ts +2 -2
  7. package/src/category/i18n/it.ts +2 -2
  8. package/src/category/i18n/nl.ts +2 -2
  9. package/src/category/i18n/pl.ts +3 -3
  10. package/src/category/i18n/pt.ts +2 -2
  11. package/src/category/i18n/ru.ts +5 -5
  12. package/src/category/i18n/sv.ts +3 -3
  13. package/src/category/i18n/zh.ts +2 -2
  14. package/src/layouts/PreviewLayout.astro +1 -0
  15. package/src/tests/diacritics_density.test.ts +118 -0
  16. package/src/tests/inverted_punctuation.test.ts +84 -0
  17. package/src/tests/no_en_dash.test.ts +70 -0
  18. package/src/tests/script_density.test.ts +94 -0
  19. package/src/tool/burnTest/i18n/de.ts +3 -3
  20. package/src/tool/burnTest/i18n/fr.ts +3 -3
  21. package/src/tool/burnTest/i18n/pl.ts +3 -3
  22. package/src/tool/burnTest/i18n/ru.ts +6 -6
  23. package/src/tool/burnTest/i18n/zh.ts +3 -3
  24. package/src/tool/clothingSizeConverter/i18n/en.ts +1 -1
  25. package/src/tool/clothingSizeConverter/i18n/fr.ts +6 -6
  26. package/src/tool/clothingSizeConverter/i18n/pl.ts +1 -1
  27. package/src/tool/clothingSizeConverter/i18n/ru.ts +2 -2
  28. package/src/tool/clothingSizeConverter/i18n/zh.ts +1 -1
  29. package/src/tool/fabricProjectCalculator/component.astro +2 -3
  30. package/src/tool/fabricProjectCalculator/fabric-project-calculator.css +63 -1
  31. package/src/tool/fabricProjectCalculator/i18n/ru.ts +2 -2
  32. package/src/tool/fabricProjectCalculator/i18n/zh.ts +1 -1
  33. package/src/tool/fabricTruth/i18n/de.ts +1 -1
  34. package/src/tool/fabricTruth/i18n/en.ts +1 -1
  35. package/src/tool/fabricTruth/i18n/es.ts +1 -1
  36. package/src/tool/fabricTruth/i18n/fr.ts +13 -13
  37. package/src/tool/fabricTruth/i18n/id.ts +1 -1
  38. package/src/tool/fabricTruth/i18n/it.ts +1 -1
  39. package/src/tool/fabricTruth/i18n/ja.ts +1 -1
  40. package/src/tool/fabricTruth/i18n/ko.ts +1 -1
  41. package/src/tool/fabricTruth/i18n/nl.ts +1 -1
  42. package/src/tool/fabricTruth/i18n/pl.ts +1 -1
  43. package/src/tool/fabricTruth/i18n/pt.ts +1 -1
  44. package/src/tool/fabricTruth/i18n/ru.ts +11 -11
  45. package/src/tool/fabricTruth/i18n/sv.ts +1 -1
  46. package/src/tool/fabricTruth/i18n/tr.ts +1 -1
  47. package/src/tool/fabricTruth/i18n/zh.ts +9 -9
  48. package/src/tool/fiberPrep/fiber-preparation-natural-dyeing.css +130 -11
  49. package/src/tool/fiberPrep/i18n/fr.ts +4 -4
  50. package/src/tool/fiberPrep/i18n/ru.ts +3 -3
  51. package/src/tool/fiberPrep/i18n/zh.ts +2 -2
  52. package/src/tool/knittingGauge/i18n/ru.ts +6 -6
  53. package/src/tool/knittingGauge/i18n/zh.ts +1 -1
  54. package/src/tool/laundryGuide/i18n/de.ts +1 -1
  55. package/src/tool/laundryGuide/i18n/en.ts +1 -1
  56. package/src/tool/laundryGuide/i18n/es.ts +1 -1
  57. package/src/tool/laundryGuide/i18n/fr.ts +12 -12
  58. package/src/tool/laundryGuide/i18n/id.ts +1 -1
  59. package/src/tool/laundryGuide/i18n/it.ts +1 -1
  60. package/src/tool/laundryGuide/i18n/nl.ts +1 -1
  61. package/src/tool/laundryGuide/i18n/pl.ts +2 -2
  62. package/src/tool/laundryGuide/i18n/pt.ts +1 -1
  63. package/src/tool/laundryGuide/i18n/ru.ts +6 -6
  64. package/src/tool/laundryGuide/i18n/sv.ts +1 -1
  65. package/src/tool/laundryGuide/i18n/zh.ts +2 -2
  66. package/src/tool/needleConverter/i18n/fr.ts +5 -5
  67. package/src/tool/needleConverter/i18n/ru.ts +4 -4
  68. package/src/tool/sewingPatternScaler/i18n/fr.ts +2 -2
  69. package/src/tool/sewingPatternScaler/i18n/pl.ts +2 -2
  70. package/src/tool/sewingPatternScaler/i18n/ru.ts +7 -7
  71. package/src/tool/sewingPatternScaler/i18n/zh.ts +3 -3
  72. package/src/tool/shoeSizeConverter/i18n/fr.ts +1 -1
  73. package/src/tool/shoeSizeConverter/i18n/ru.ts +4 -4
  74. package/src/tool/shoeSizeConverter/i18n/zh.ts +3 -3
  75. package/src/tool/stainChemistry/bibliography.ts +2 -2
  76. package/src/tool/stainChemistry/i18n/de.ts +3 -3
  77. package/src/tool/stainChemistry/i18n/en.ts +3 -3
  78. package/src/tool/stainChemistry/i18n/es.ts +3 -3
  79. package/src/tool/stainChemistry/i18n/fr.ts +6 -6
  80. package/src/tool/stainChemistry/i18n/id.ts +3 -3
  81. package/src/tool/stainChemistry/i18n/it.ts +3 -3
  82. package/src/tool/stainChemistry/i18n/ja.ts +3 -3
  83. package/src/tool/stainChemistry/i18n/ko.ts +3 -3
  84. package/src/tool/stainChemistry/i18n/nl.ts +3 -3
  85. package/src/tool/stainChemistry/i18n/pl.ts +3 -3
  86. package/src/tool/stainChemistry/i18n/pt.ts +3 -3
  87. package/src/tool/stainChemistry/i18n/ru.ts +7 -7
  88. package/src/tool/stainChemistry/i18n/sv.ts +3 -3
  89. package/src/tool/stainChemistry/i18n/tr.ts +3 -3
  90. package/src/tool/stainChemistry/i18n/zh.ts +7 -7
  91. package/src/tool/yarnCalculator/i18n/fr.ts +4 -4
  92. package/src/tool/yarnCalculator/i18n/ru.ts +7 -7
  93. package/src/tool/yarnCalculator/i18n/zh.ts +5 -5
@@ -0,0 +1,94 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ALL_TOOLS } from '../tools';
3
+
4
+ type ScriptLocale = keyof typeof SCRIPT_RULES;
5
+
6
+ const SCRIPT_RULES = {
7
+ ja: {
8
+ language: 'Japanese',
9
+ scriptName: 'kana/kanji',
10
+ scriptCharacters: /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}]/gu,
11
+ minScriptRatio: 0.45,
12
+ },
13
+ ko: {
14
+ language: 'Korean',
15
+ scriptName: 'hangul',
16
+ scriptCharacters: /\p{Script=Hangul}/gu,
17
+ minScriptRatio: 0.55,
18
+ },
19
+ ru: {
20
+ language: 'Russian',
21
+ scriptName: 'cyrillic',
22
+ scriptCharacters: /\p{Script=Cyrillic}/gu,
23
+ minScriptRatio: 0.65,
24
+ },
25
+ zh: {
26
+ language: 'Chinese',
27
+ scriptName: 'han',
28
+ scriptCharacters: /\p{Script=Han}/gu,
29
+ minScriptRatio: 0.45,
30
+ },
31
+ } as const;
32
+
33
+ const LETTERS = /\p{L}/gu;
34
+ const TRANSLATABLE_KEYS = ['title', 'description', 'ui', 'seo', 'faq', 'howTo'] as const;
35
+
36
+ function collectStrings(value: unknown): string[] {
37
+ if (typeof value === 'string') return [value];
38
+ if (!value || typeof value !== 'object') return [];
39
+ if (Array.isArray(value)) return value.flatMap(collectStrings);
40
+ return Object.values(value).flatMap(collectStrings);
41
+ }
42
+
43
+ function normalizeText(value: unknown): string {
44
+ return collectStrings(value).join(' ').normalize('NFC');
45
+ }
46
+
47
+ function translatableContent(content: Record<string, unknown>) {
48
+ return TRANSLATABLE_KEYS.map((key) => content[key]);
49
+ }
50
+
51
+ function letterCount(text: string): number {
52
+ return text.match(LETTERS)?.length ?? 0;
53
+ }
54
+
55
+ function scriptCount(text: string, locale: ScriptLocale): number {
56
+ return text.match(SCRIPT_RULES[locale].scriptCharacters)?.length ?? 0;
57
+ }
58
+
59
+ function scriptRatio(text: string, locale: ScriptLocale): number {
60
+ const letters = letterCount(text);
61
+ if (letters === 0) return 0;
62
+ return scriptCount(text, locale) / letters;
63
+ }
64
+
65
+ describe('Native script density validation', () => {
66
+ ALL_TOOLS.forEach((tool) => {
67
+ describe(`Tool: ${tool.entry.id}`, () => {
68
+ Object.keys(SCRIPT_RULES).forEach((locale) => {
69
+ it(`${locale} keeps most translated text in its native script`, async () => {
70
+ const typedLocale = locale as ScriptLocale;
71
+ const loader = tool.entry.i18n[typedLocale];
72
+ if (!loader) return;
73
+
74
+ const content = await loader();
75
+ const rule = SCRIPT_RULES[typedLocale];
76
+ const text = normalizeText(translatableContent(content as Record<string, unknown>));
77
+ const letters = letterCount(text);
78
+ const matches = scriptCount(text, typedLocale);
79
+ const ratio = scriptRatio(text, typedLocale);
80
+
81
+ expect(
82
+ ratio,
83
+ [
84
+ `Possible broken translation detected in ${tool.entry.id}/${typedLocale} (${rule.language}).`,
85
+ `The text has ${matches} ${rule.scriptName} characters out of ${letters} analyzed letters (${(ratio * 100).toFixed(1)}%).`,
86
+ `Most translatable content should be written in ${rule.scriptName} script.`,
87
+ 'Non-translatable fields such as slug, bibliography, and schemas are ignored to avoid false positives.',
88
+ ].join(' '),
89
+ ).toBeGreaterThanOrEqual(rule.minScriptRatio);
90
+ });
91
+ });
92
+ });
93
+ });
94
+ });
@@ -154,7 +154,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
154
154
  },
155
155
  {
156
156
  type: 'paragraph',
157
- html: 'Eine präzise Analyse erfordert den Abgleich von mindestens drei Beweisstücken. Der Geruch ist der zuverlässigste Indikator zur Identifizierung von Mischgeweben: Wenn ein Leinen“-Stoff ein leichtes Kunststoffaroma verströmt und harte Rückstände hinterlässt, deutet dies auf eine nicht deklarierte Polyestermischung hin.',
157
+ html: 'Eine präzise Analyse erfordert den Abgleich von mindestens drei Beweisstücken. Der Geruch ist der zuverlässigste Indikator zur Identifizierung von Mischgeweben: Wenn ein "Leinen"-Stoff ein leichtes Kunststoffaroma verströmt und harte Rückstände hinterlässt, deutet dies auf eine nicht deklarierte Polyestermischung hin.',
158
158
  },
159
159
  {
160
160
  type: 'tip',
@@ -187,8 +187,8 @@ export const content: ToolLocaleContent<BurnTestUI> = {
187
187
  wool: { name: 'Wolle / Merino', icon: 'mdi:sheep', color: '#FCD34D', description: 'Tierische Proteinfaser, hervorragender Wärmeisolator und elastisch.' },
188
188
  silk: { name: 'Seide', icon: 'mdi:ticket-percent', color: '#F472B6', description: 'Tierische Endlosfaser. Natürlicher Glanz und trockener Griff.' },
189
189
  cashmere: { name: 'Kaschmir', icon: 'mdi:crown', color: '#F59E0B', description: 'Luxuriöse Kaschmirziegenfaser. Extrem weich, leicht und warm.' },
190
- mohair: { name: 'Mohair', icon: 'mdi:shimmer', color: '#14B8A6', description: 'Die Diamantfaser der Angora-Ziege. Natürlicher Glanz, sehr widerstandsfähig.' },
191
- angora: { name: 'Angora', icon: 'mdi:rabbit', color: '#F9FAFB', description: 'Haar des Angora-Kaninchens. Bekannt für seinen flauschigen Halo“-Effekt und extreme Leichtigkeit.' },
190
+ mohair: { name: 'Mohair', icon: 'mdi:shimmer', color: '#14B8A6', description: 'Die "Diamantfaser" der Angora-Ziege. Natürlicher Glanz, sehr widerstandsfähig.' },
191
+ angora: { name: 'Angora', icon: 'mdi:rabbit', color: '#F9FAFB', description: 'Haar des Angora-Kaninchens. Bekannt für seinen flauschigen "Halo"-Effekt und extreme Leichtigkeit.' },
192
192
  alpaca: { name: 'Alpaka', icon: 'mdi:image-filter-hdr', color: '#9F7AEA', description: 'Schatz der Anden. Hohle, thermische, hypoallergene und seidige Faser.' },
193
193
  polyester: { name: 'Polyester', icon: 'mdi:oil', color: '#94A3B8', description: 'Synthetische Faser auf Erdölbasis. Widerstandsfähig, knitterfrei, nicht atmungsaktiv.' },
194
194
  nylon: { name: 'Nylon (Polyamid)', icon: 'mdi:parachute', color: '#2DD4BF', description: 'Hochwiderstandsfähige Kunstfaser für Zugkraft und Abrieb.' },
@@ -12,7 +12,7 @@ const faqData = [
12
12
  {
13
13
  question: 'Est-il sûr d\'effectuer un test de combustion à la maison?',
14
14
  answer:
15
- "Oui, à condition de prendre des précautions extrêmes : utilisez des pinces métalliques, travaillez sur une surface ignifuge (céramique ou métal), gardez de l'eau à portée et effectuez le test dans un endroit ventilé. Vous n'avez besoin que d'un petit échantillon de 1x1 cm ou de quelques fils.",
15
+ "Oui, à condition de prendre des précautions extrêmes: utilisez des pinces métalliques, travaillez sur une surface ignifuge (céramique ou métal), gardez de l'eau à portée et effectuez le test dans un endroit ventilé. Vous n'avez besoin que d'un petit échantillon de 1x1 cm ou de quelques fils.",
16
16
  },
17
17
  {
18
18
  question: 'Comment sent le coton quand il brûle?',
@@ -127,7 +127,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
127
127
  },
128
128
  {
129
129
  type: 'paragraph',
130
- html: "Le test de combustion est la méthode analytique la plus rapide et précise pour différencier les polymères naturels des synthétiques sans recourir au microscope électronique. En soumettant une fibre à la chaleur, son comportement moléculaire révèle son origine : depuis la cellulose végétale jusqu'aux protéines animales ou aux dérivés du pétrole.",
130
+ html: "Le test de combustion est la méthode analytique la plus rapide et précise pour différencier les polymères naturels des synthétiques sans recourir au microscope électronique. En soumettant une fibre à la chaleur, son comportement moléculaire révèle son origine: depuis la cellulose végétale jusqu'aux protéines animales ou aux dérivés du pétrole.",
131
131
  },
132
132
  {
133
133
  type: 'card',
@@ -154,7 +154,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
154
154
  },
155
155
  {
156
156
  type: 'paragraph',
157
- html: "Une analyse précise nécessite de croiser au moins trois preuves. L'odeur est l'indicateur le plus fiable pour identifier les mélanges : si un tissu de \"lin\" dégage un léger arôme plastique et laisse des résidus durs, cela indique un mélange polyester non déclaré.",
157
+ html: "Une analyse précise nécessite de croiser au moins trois preuves. L'odeur est l'indicateur le plus fiable pour identifier les mélanges: si un tissu de \"lin\" dégage un léger arôme plastique et laisse des résidus durs, cela indique un mélange polyester non déclaré.",
158
158
  },
159
159
  {
160
160
  type: 'tip',
@@ -154,7 +154,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
154
154
  },
155
155
  {
156
156
  type: 'paragraph',
157
- html: 'Precyzyjna analiza wymaga zestawienia co najmniej trzech dowodów. Zapach jest najbardziej wiarygodnym wskaźnikiem przy identyfikacji mieszanek: jeśli lniana tkanina wydziela lekki plastikowy aromat i pozostawia twarde resztki, oznacza to niezadeklarowaną domieszkę poliestru.',
157
+ html: 'Precyzyjna analiza wymaga zestawienia co najmniej trzech dowodów. Zapach jest najbardziej wiarygodnym wskaźnikiem przy identyfikacji mieszanek: jeśli "lniana" tkanina wydziela lekki plastikowy aromat i pozostawia twarde resztki, oznacza to niezadeklarowaną domieszkę poliestru.',
158
158
  },
159
159
  {
160
160
  type: 'tip',
@@ -187,8 +187,8 @@ export const content: ToolLocaleContent<BurnTestUI> = {
187
187
  wool: { name: 'Wełna / Merino', icon: 'mdi:sheep', color: '#FCD34D', description: 'Białkowe włókno zwierzęce, doskonały izolator termiczny i elastyczne.' },
188
188
  silk: { name: 'Jedwab', icon: 'mdi:ticket-percent', color: '#F472B6', description: 'Zwierzęce włókno ciągłe. Naturalny połysk i suchy chwyt.' },
189
189
  cashmere: { name: 'Kaszmir', icon: 'mdi:crown', color: '#F59E0B', description: 'Luksusowe włókno z kóz kaszmirskich. Ekstremalnie miękkie, lekkie i ciepłe.' },
190
- mohair: { name: 'Mohair', icon: 'mdi:shimmer', color: '#14B8A6', description: 'Diamentowe włókno z kóz angorskich. Naturalny połysk, bardzo wytrzymałe.' },
191
- angora: { name: 'Angora', icon: 'mdi:rabbit', color: '#F9FAFB', description: 'Sierść krolika angorskiego. Znana z puszystego efektu halo i ekstremalnej lekkości.' },
190
+ mohair: { name: 'Mohair', icon: 'mdi:shimmer', color: '#14B8A6', description: '"Diamentowe włókno" z kóz angorskich. Naturalny połysk, bardzo wytrzymałe.' },
191
+ angora: { name: 'Angora', icon: 'mdi:rabbit', color: '#F9FAFB', description: 'Sierść krolika angorskiego. Znana z puszystego efektu "halo" i ekstremalnej lekkości.' },
192
192
  alpaca: { name: 'Alpaka', icon: 'mdi:image-filter-hdr', color: '#9F7AEA', description: 'Skarb Andów. Włókno puste w środku, termiczne, hipoalergiczne i jedwabiste.' },
193
193
  polyester: { name: 'Poliester', icon: 'mdi:oil', color: '#94A3B8', description: 'Syntetyczne włókno na bazie ropy naftowej. Wytrzymałe, nie gniecie się, nie oddycha.' },
194
194
  nylon: { name: 'Nylon (Poliamid)', icon: 'mdi:parachute', color: '#2DD4BF', description: 'Bardzo wytrzymałe włókno syntetyczne na rozciąganie i ścieranie.' },
@@ -17,7 +17,7 @@ const faqData = [
17
17
  {
18
18
  question: 'Как пахнет хлопок при горении?',
19
19
  answer:
20
- 'Хлопокэто чистая целлюлоза. При горении он пахнет точно так же, как жженая бумага или сухие листья. Образующаяся зола серая, очень мелкая и рассыпается при прикосновении.',
20
+ 'Хлопок - это чистая целлюлоза. При горении он пахнет точно так же, как жженая бумага или сухие листья. Образующаяся зола серая, очень мелкая и рассыпается при прикосновении.',
21
21
  },
22
22
  {
23
23
  question: 'Что означает твердый черный шарик на конце волокна?',
@@ -27,7 +27,7 @@ const faqData = [
27
27
  {
28
28
  question: 'Почему шерсть плохо пахнет при горении?',
29
29
  answer:
30
- 'Шерсть и шелкэто животные белки, содержащие серу. При контакте с огнем они издают резкий запах паленой шерсти или перьев. Это самый простой способ отличить их от растительных волокон.',
30
+ 'Шерсть и шелк - это животные белки, содержащие серу. При контакте с огнем они издают резкий запах паленой шерсти или перьев. Это самый простой способ отличить их от растительных волокон.',
31
31
  },
32
32
  ];
33
33
 
@@ -127,7 +127,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
127
127
  },
128
128
  {
129
129
  type: 'paragraph',
130
- html: 'Тест на горениеэто самый быстрый и точный аналитический метод дифференциации натуральных полимеров от синтетических без использования электронного микроскопа. При воздействии тепла на волокно его молекулярное поведение раскрывает его происхождение: от растительной целлюлозы до животных белков или производных нефти.',
130
+ html: 'Тест на горение - это самый быстрый и точный аналитический метод дифференциации натуральных полимеров от синтетических без использования электронного микроскопа. При воздействии тепла на волокно его молекулярное поведение раскрывает его происхождение: от растительной целлюлозы до животных белков или производных нефти.',
131
131
  },
132
132
  {
133
133
  type: 'card',
@@ -145,7 +145,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
145
145
  type: 'card',
146
146
  title: 'Синтетические волокна',
147
147
  icon: 'mdi:bottle-soda-classic',
148
- html: '<strong>Полиэстер</strong> и <strong>Нейлон</strong>это, по сути, пластик. Они плавятся, образуя горячую каплю, которая застывает в стеклянную бусину, которую невозможно сломать, с резким химическим запахом.',
148
+ html: '<strong>Полиэстер</strong> и <strong>Нейлон</strong> - это, по сути, пластик. Они плавятся, образуя горячую каплю, которая застывает в стеклянную бусину, которую невозможно сломать, с резким химическим запахом.',
149
149
  },
150
150
  {
151
151
  type: 'title',
@@ -154,7 +154,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
154
154
  },
155
155
  {
156
156
  type: 'paragraph',
157
- html: 'Точный анализ требует сопоставления как минимум трех улик. Запахсамый надежный индикатор для определения смешанных составов: если «льняная» ткань издает легкий пластиковый аромат и оставляет твердые остатки, это указывает на незаявленную примесь полиэстера.',
157
+ html: 'Точный анализ требует сопоставления как минимум трех улик. Запах - самый надежный индикатор для определения смешанных составов: если "льняная" ткань издает легкий пластиковый аромат и оставляет твердые остатки, это указывает на незаявленную примесь полиэстера.',
158
158
  },
159
159
  {
160
160
  type: 'tip',
@@ -187,7 +187,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
187
187
  wool: { name: 'Шерсть / Меринос', icon: 'mdi:sheep', color: '#FCD34D', description: 'Белковое животное волокно, отличный термоизолятор, эластичное.' },
188
188
  silk: { name: 'Шелк', icon: 'mdi:ticket-percent', color: '#F472B6', description: 'Животное волокно в виде непрерывной нити. Естественный блеск и приятная сухость.' },
189
189
  cashmere: { name: 'Кашемир', icon: 'mdi:crown', color: '#F59E0B', description: 'Роскошное волокно из подшерстка кашемировых коз. Невероятно мягкое, легкое и теплое.' },
190
- mohair: { name: 'Мохер', icon: 'mdi:shimmer', color: '#14B8A6', description: '«Алмазное волокно» из шерсти ангорской козы. Естественный блеск, очень прочное.' },
190
+ mohair: { name: 'Мохер', icon: 'mdi:shimmer', color: '#14B8A6', description: '"Алмазное волокно" из шерсти ангорской козы. Естественный блеск, очень прочное.' },
191
191
  angora: { name: 'Ангора', icon: 'mdi:rabbit', color: '#F9FAFB', description: 'Пух ангорского кролика. Известен своим пушистым эффектом и экстремальной легкостью.' },
192
192
  alpaca: { name: 'Альпака', icon: 'mdi:image-filter-hdr', color: '#9F7AEA', description: 'Сокровище Анд. Полое, теплое, гипоаллергенное и шелковистое волокно.' },
193
193
  polyester: { name: 'Полиэстер', icon: 'mdi:oil', color: '#94A3B8', description: 'Синтетическое волокно на основе нефти. Прочное, не мнется, не дышит.' },
@@ -154,7 +154,7 @@ export const content: ToolLocaleContent<BurnTestUI> = {
154
154
  },
155
155
  {
156
156
  type: 'paragraph',
157
- html: '精确的分析需要交叉验证至少三个证据。气味是识别混纺最可靠的指标:如果一种“亚麻”织物散发出轻微的塑料香味并留下坚硬的残留物,这表明其含有未声明的聚酯成分。',
157
+ html: '精确的分析需要交叉验证至少三个证据。气味是识别混纺最可靠的指标:如果一种"亚麻"织物散发出轻微的塑料香味并留下坚硬的残留物,这表明其含有未声明的聚酯成分。',
158
158
  },
159
159
  {
160
160
  type: 'tip',
@@ -187,8 +187,8 @@ export const content: ToolLocaleContent<BurnTestUI> = {
187
187
  wool: { name: '羊毛 / 羊绒', icon: 'mdi:sheep', color: '#FCD34D', description: '动物蛋白质纤维,优异的绝热体,具有弹性。' },
188
188
  silk: { name: '丝绸 (真丝)', icon: 'mdi:ticket-percent', color: '#F472B6', description: '动物长丝纤维。天然光泽,手感干爽。' },
189
189
  cashmere: { name: '山羊绒', icon: 'mdi:crown', color: '#F59E0B', description: '昂贵的克什米尔山羊纤维。极其柔软、轻盈、保暖。' },
190
- mohair: { name: '马海毛', icon: 'mdi:shimmer', color: '#14B8A6', description: '安哥拉山羊的“钻石纤维”。天然光泽,非常耐磨。' },
191
- angora: { name: '安哥拉兔毛', icon: 'mdi:rabbit', color: '#F9FAFB', description: '安哥拉兔的毛。以其蓬松的“光环”效果和极致轻盈著称。' },
190
+ mohair: { name: '马海毛', icon: 'mdi:shimmer', color: '#14B8A6', description: '安哥拉山羊的"钻石纤维"。天然光泽,非常耐磨。' },
191
+ angora: { name: '安哥拉兔毛', icon: 'mdi:rabbit', color: '#F9FAFB', description: '安哥拉兔的毛。以其蓬松的"光环"效果和极致轻盈著称。' },
192
192
  alpaca: { name: '阿尔パカ (羊驼毛)', icon: 'mdi:image-filter-hdr', color: '#9F7AEA', description: '安第斯山的珍宝。中空纤维,保暖、防过敏、丝滑。' },
193
193
  polyester: { name: '聚酯纤维 (涤纶)', icon: 'mdi:oil', color: '#94A3B8', description: '石油基合成纤维。耐用、抗皱、不透气。' },
194
194
  nylon: { name: '尼龙 (锦纶)', icon: 'mdi:parachute', color: '#2DD4BF', description: '抗拉和耐磨性极强的合成纤维。' },
@@ -32,7 +32,7 @@ const faqData = [
32
32
  {
33
33
  question: 'Do clothes shrink after washing?',
34
34
  answer:
35
- '100% cotton can shrink 510% if washed in hot water and tumble dried. Synthetic materials hold their shape better. Always check the care label instructions.',
35
+ '100% cotton can shrink 5-10% if washed in hot water and tumble dried. Synthetic materials hold their shape better. Always check the care label instructions.',
36
36
  },
37
37
  ];
38
38
 
@@ -22,7 +22,7 @@ const faqData = [
22
22
  {
23
23
  question: 'Comment savoir si je dois prendre une taille au-dessus ou en dessous ?',
24
24
  answer:
25
- 'Le meilleur moyen est de lire les avis d\'autres clients. Des expressions comme « taille petit » ou « taille grand » sont très utiles. Consultez aussi le guide des tailles spécifique de la marque.',
25
+ 'Le meilleur moyen est de lire les avis d\'autres clients. Des expressions comme " taille petit " ou " taille grand " sont très utiles. Consultez aussi le guide des tailles spécifique de la marque.',
26
26
  },
27
27
  {
28
28
  question: 'La table de conversion des tailles est-elle exacte ?',
@@ -43,7 +43,7 @@ const howToData = [
43
43
  },
44
44
  {
45
45
  name: 'Choisir votre Système de Taille',
46
- text: 'Sélectionnez le système que vous connaissez : EU, US, UK ou IT.',
46
+ text: 'Sélectionnez le système que vous connaissez: EU, US, UK ou IT.',
47
47
  },
48
48
  {
49
49
  name: 'Sélectionner votre Taille',
@@ -214,7 +214,7 @@ export const content: ToolLocaleContent<ClothingSizeConverterUI> = {
214
214
  seo: [
215
215
  {
216
216
  type: 'title',
217
- text: 'Convertisseur de Tailles : Guide International Complet',
217
+ text: 'Convertisseur de Tailles: Guide International Complet',
218
218
  level: 2,
219
219
  },
220
220
  {
@@ -304,9 +304,9 @@ export const content: ToolLocaleContent<ClothingSizeConverterUI> = {
304
304
  chestLabel: 'Poitrine (cm)',
305
305
  waistLabel: 'Taille (cm)',
306
306
  hipLabel: 'Hanches (cm)',
307
- chestPlaceholder: 'Ex. : 95',
308
- waistPlaceholder: 'Ex. : 85',
309
- hipPlaceholder: 'Ex. : 95',
307
+ chestPlaceholder: 'Ex.: 95',
308
+ waistPlaceholder: 'Ex.: 85',
309
+ hipPlaceholder: 'Ex.: 95',
310
310
  recommendBtnLabel: 'Recommander une Taille',
311
311
  tipsTitle: 'Conseils de Mesure',
312
312
  tipOverClothes: 'Par-dessus les vêtements',
@@ -22,7 +22,7 @@ const faqData = [
22
22
  {
23
23
  question: 'Skąd mam wiedzieć, czy w danej marce powinienem wziąć rozmiar większy czy mniejszy?',
24
24
  answer:
25
- 'Najlepszym sposobem jest sprawdzenie opinii innych klientów. Zdania typu było na mnie za małe lub duży krój są bardzo pomocne. Sprawdź również konkretną tabelę wymiarów danej marki.',
25
+ 'Najlepszym sposobem jest sprawdzenie opinii innych klientów. Zdania typu "było na mnie za małe" lub "duży krój" są bardzo pomocne. Sprawdź również konkretną tabelę wymiarów danej marki.',
26
26
  },
27
27
  {
28
28
  question: 'Jak dokładna jest tabela konwersji rozmiarów?',
@@ -17,12 +17,12 @@ const faqData = [
17
17
  {
18
18
  question: 'Меняются ли размеры для мужской и женской одежды?',
19
19
  answer:
20
- 'Да, безусловно. Даже в одной стране мужской размер 40это не то же самое, что женский размер 40. У мужчин другие пропорции (более широкие плечи), поэтому расчет размера варьируется.',
20
+ 'Да, безусловно. Даже в одной стране мужской размер 40 - это не то же самое, что женский размер 40. У мужчин другие пропорции (более широкие плечи), поэтому расчет размера варьируется.',
21
21
  },
22
22
  {
23
23
  question: 'Как узнать, стоит ли мне брать размер больше или меньше в конкретном бренде?',
24
24
  answer:
25
- 'Лучший способпроверить отзывы других покупателей. Фразы типа «маломерит» или «большемерит» очень полезны. Также сверяйтесь с конкретной таблицей измерений этого бренда.',
25
+ 'Лучший способ - проверить отзывы других покупателей. Фразы типа "маломерит" или "большемерит" очень полезны. Также сверяйтесь с конкретной таблицей измерений этого бренда.',
26
26
  },
27
27
  {
28
28
  question: 'Насколько точна таблица соответствия размеров?',
@@ -22,7 +22,7 @@ const faqData = [
22
22
  {
23
23
  question: '我如何知道在某个品牌中应该买大一码还是买小一码?',
24
24
  answer:
25
- '最好的方法是查看其他顾客的评价。诸如“我觉得偏小”或“版型偏大”之类的短语非常有帮助。同时请参考该品牌的具体尺寸测量表。',
25
+ '最好的方法是查看其他顾客的评价。诸如"我觉得偏小"或"版型偏大"之类的短语非常有帮助。同时请参考该品牌的具体尺寸测量表。',
26
26
  },
27
27
  {
28
28
  question: '此尺码换算表准确吗?',
@@ -10,7 +10,7 @@ const calcUI = ui as FabricProjectCalculatorUI;
10
10
  ---
11
11
 
12
12
  <div class="fabric-calculator-card" id="fabric-calc-app">
13
- <aside class="fabric-sidebar">
13
+ <div class="fabric-sidebar">
14
14
  <div class="config-group">
15
15
  <h3>{calcUI.sectionProject}</h3>
16
16
  <div class="fabric-field">
@@ -59,7 +59,7 @@ const calcUI = ui as FabricProjectCalculatorUI;
59
59
  <button id="btn-clear-f" class="f-btn f-seco">{calcUI.btnClear}</button>
60
60
  <button id="btn-share-f" class="f-btn f-prim">{calcUI.btnShare}</button>
61
61
  </div>
62
- </aside>
62
+ </div>
63
63
 
64
64
  <main class="fabric-main">
65
65
  <div id="warning-msg" class="warning-banner"></div>
@@ -371,4 +371,3 @@ const calcUI = ui as FabricProjectCalculatorUI;
371
371
  document.addEventListener('astro:page-load', init);
372
372
  init();
373
373
  </script>
374
-
@@ -470,10 +470,13 @@
470
470
 
471
471
  @media (max-width: 1100px) {
472
472
  .fabric-calculator-card {
473
+ display: flex;
474
+ flex-direction: column;
473
475
  grid-template-columns: 1fr;
474
476
  width: 100%;
475
477
  border-radius: 1rem;
476
478
  margin: 0;
479
+ overflow: visible;
477
480
  }
478
481
 
479
482
  .fabric-sidebar {
@@ -498,13 +501,69 @@
498
501
  }
499
502
 
500
503
  @media (max-width: 600px) {
504
+ .fabric-calculator-card {
505
+ background: transparent;
506
+ border: 0;
507
+ box-shadow: none;
508
+ gap: 1rem;
509
+ }
510
+
501
511
  .fabric-sidebar {
512
+ background: var(--bg-surface);
513
+ border: 1px solid var(--border-color);
514
+ border-radius: 1rem;
502
515
  padding: 1.25rem;
516
+ gap: 1.5rem;
517
+ min-width: 0;
518
+ }
519
+
520
+ .config-group {
521
+ gap: 1rem;
522
+ min-width: 0;
523
+ }
524
+
525
+ .fabric-field {
526
+ min-width: 0;
527
+ }
528
+
529
+ .fabric-select,
530
+ .fabric-input {
531
+ display: block;
532
+ min-width: 0;
533
+ min-height: 48px;
534
+ color: var(--text-main);
535
+ }
536
+
537
+ .fabric-select {
538
+ background-color: var(--bg-surface);
539
+ }
540
+
541
+ .shop-stepper {
542
+ width: 100%;
543
+ max-width: none;
544
+ grid-template-columns: 48px minmax(0, 1fr) 48px;
545
+ }
546
+
547
+ .preset-group {
548
+ grid-template-columns: 1fr;
549
+ }
550
+
551
+ .preset-pill {
552
+ min-height: 44px;
553
+ padding: 0.75rem;
554
+ }
555
+
556
+ .btn-actions {
557
+ grid-template-columns: 1fr;
503
558
  }
504
559
 
505
560
  .fabric-main {
561
+ background: var(--bg-surface);
562
+ border: 1px solid var(--border-color);
563
+ border-radius: 1rem;
506
564
  padding: 1.25rem;
507
565
  gap: 1.5rem;
566
+ min-width: 0;
508
567
  }
509
568
 
510
569
  .magic-result-area {
@@ -524,15 +583,18 @@
524
583
  .advice-tag {
525
584
  font-size: 0.875rem;
526
585
  padding: 0.7rem 1.25rem;
586
+ max-width: 100%;
587
+ overflow-wrap: anywhere;
527
588
  }
528
589
 
529
590
  .canvas-wrapper {
530
591
  padding: 14px 14px 10px 8px;
531
592
  border-radius: 16px;
593
+ min-width: 0;
532
594
  }
533
595
 
534
596
  .fabric-board {
535
597
  height: 220px;
536
598
  padding-bottom: 20px;
537
599
  }
538
- }
600
+ }
@@ -99,7 +99,7 @@ export const content: ToolLocaleContent<FabricProjectCalculatorUI> = {
99
99
  },
100
100
  {
101
101
  type: 'paragraph',
102
- html: 'Один из самых частых вопросов в швейной мастерскойсколько ткани купить для конкретного проекта. Расход ткани радикально зависит от трех факторов: модели изделия, размера человека и, прежде всего, ширины отреза ткани (которая обычно варьируется от 90 см до 150 см). Этот технический калькулятор систематизирует расчет, чтобы вы не купили лишнего и вам не не хватило материала в середине раскроя.',
102
+ html: 'Один из самых частых вопросов в швейной мастерской - сколько ткани купить для конкретного проекта. Расход ткани радикально зависит от трех факторов: модели изделия, размера человека и, прежде всего, ширины отреза ткани (которая обычно варьируется от 90 см до 150 см). Этот технический калькулятор систематизирует расчет, чтобы вы не купили лишнего и вам не не хватило материала в середине раскроя.',
103
103
  },
104
104
  {
105
105
  type: 'title',
@@ -167,7 +167,7 @@ export const content: ToolLocaleContent<FabricProjectCalculatorUI> = {
167
167
  type: 'card',
168
168
  title: 'Припуск на шов',
169
169
  icon: 'mdi:tape-measure',
170
- html: 'Расстояние между краем выкройки и <strong>линией финального шва</strong>. Стандартное значение1,5 см для швов одежды.',
170
+ html: 'Расстояние между краем выкройки и <strong>линией финального шва</strong>. Стандартное значение - 1,5 см для швов одежды.',
171
171
  },
172
172
  {
173
173
  type: 'card',
@@ -99,7 +99,7 @@ export const content: ToolLocaleContent<FabricProjectCalculatorUI> = {
99
99
  },
100
100
  {
101
101
  type: 'paragraph',
102
- html: '在缝纫工作室中,最常见的疑问之一是确定为一个特定项目购买多少布料。布料消耗量主要取决于三个因素:服装模型、个人尺寸,以及最核心的——布料幅宽(通常在 90 厘米到 150 厘米之间)。这款技术计算器使计算系统化,让您既不会买得太多,也不会在裁剪到一半时发现面料不够。',
102
+ html: '在缝纫工作室中,最常见的疑问之一是确定为一个特定项目购买多少布料。布料消耗量主要取决于三个因素:服装模型、个人尺寸,以及最核心的 - - 布料幅宽(通常在 90 厘米到 150 厘米之间)。这款技术计算器使计算系统化,让您既不会买得太多,也不会在裁剪到一半时发现面料不够。',
103
103
  },
104
104
  {
105
105
  type: 'title',
@@ -259,7 +259,7 @@ export const content: ToolLocaleContent<FabricTruthUI> = {
259
259
  { type: 'tip', title: 'Weniger ist mehr (Waschmittel)', html: 'Zu viel Seife hinterlässt Rückstände, die Schmutz anziehen und die Kleidung steif machen.' },
260
260
  { type: 'tip', title: 'Trockner: Der subtile Feind', html: 'Die Flusen, die Sie im Trocknerfilter sehen, sind Teile Ihrer Kleidung, die sich durch Reibung und Hitze gelöst haben.' },
261
261
  { type: 'tip', title: 'Auf links waschen', html: 'Schützt Farben und Stickereien vor der Reibung mit der Trommel und anderen Kleidungsstücken.' },
262
- { type: 'paragraph', html: '"Weniger kaufen, besser wählen und langlebig machen."Dieser Analysator ist Ihr erster Schritt zu einem bewussten und hochwertigen Kleiderschrank.' },
262
+ { type: 'paragraph', html: '"Weniger kaufen, besser wählen und langlebig machen." - Dieser Analysator ist Ihr erster Schritt zu einem bewussten und hochwertigen Kleiderschrank.' },
263
263
  ],
264
264
  faq: faqData,
265
265
  bibliography: bibliography,
@@ -259,7 +259,7 @@ export const content: ToolLocaleContent<FabricTruthUI> = {
259
259
  { type: 'tip', title: 'Less is More (Detergent)', html: 'Excess soap leaves residue that attracts dirt and makes clothes feel stiff.' },
260
260
  { type: 'tip', title: 'Dryer: The Subtle Enemy', html: 'The lint you see in the dryer filter is pieces of your clothes that have come off due to friction and heat.' },
261
261
  { type: 'tip', title: 'Inside Out Washing', html: 'Protects color and embroidery from rubbing against the drum and other garments.' },
262
- { type: 'paragraph', html: '"Buy less, choose better, and make it last."This calculator is your first step towards a conscious and high-quality wardrobe.' },
262
+ { type: 'paragraph', html: '"Buy less, choose better, and make it last." - This calculator is your first step towards a conscious and high-quality wardrobe.' },
263
263
  ],
264
264
  faq: faqData,
265
265
  bibliography: bibliography,
@@ -259,7 +259,7 @@ export const content: ToolLocaleContent<FabricTruthUI> = {
259
259
  { type: 'tip', title: 'Menos es Más (Detergente)', html: 'El exceso de jabón deja residuos que atraen suciedad y hacen que la ropa se sienta rígida.' },
260
260
  { type: 'tip', title: 'Secadora: El Enemigo Sutil', html: 'La pelusa que ves en el filtro de la secadora son trozos de tu ropa que se han desprendido por la fricción y el calor.' },
261
261
  { type: 'tip', title: 'Lavado del Revés', html: 'Protege el color y los bordados del roce con el tambor y otras prendas.' },
262
- { type: 'paragraph', html: '"Comprar menos, elegir mejor y hacerlo durar."Esta calculadora es tu primer paso hacia un armario consciente y de alta calidad.' },
262
+ { type: 'paragraph', html: '"Comprar menos, elegir mejor y hacerlo durar." - Esta calculadora es tu primer paso hacia un armario consciente y de alta calidad.' },
263
263
  ],
264
264
  faq: [
265
265
  {
@@ -93,17 +93,17 @@ export const content: ToolLocaleContent<FabricTruthUI> = {
93
93
  durability: 'Durabilité',
94
94
  warmth: 'Chaleur',
95
95
  careWarning: 'Avertissement de Soins Spéciaux',
96
- specialCareWarning: 'LAVAGE STANDARD : Suivez toujours les instructions de l\'étiquette physique.',
96
+ specialCareWarning: 'LAVAGE STANDARD: Suivez toujours les instructions de l\'étiquette physique.',
97
97
  validationError: 'La composition doit totaliser exactement 100 % pour voir le verdict',
98
98
  actualTotal: 'Actuel',
99
99
  missingLabel: 'manquant',
100
100
  disclaimer: 'Les données de respirabilité, durabilité et chaleur sont des estimations basées sur les moyennes de l\'industrie pour chaque type de fibre.',
101
101
  careWarnings: {
102
- delicate: 'TRÈS DÉLICAT : Lavage à la main à froid. Ne pas utiliser de sèche-linge. Éviter d\'essorer.',
103
- wool: 'LAINE / POILS NOBLES : Laver à froid avec un programme spécial. Sécher à plat pour éviter les déformations. Ne pas utiliser de sèche-linge.',
104
- linen: 'LIN : A tendance à beaucoup se froisser. Repasser légèrement humide pour de meilleurs résultats.',
105
- semisynthetic: 'SEMI-SYNTHÉTIQUES : Se fragilise lorsqu\'il est mouillé. Manipuler avec soin et ne pas essorer fort.',
106
- standard: 'LAVAGE STANDARD : Suivez toujours les instructions de l\'étiquette physique.',
102
+ delicate: 'TRÈS DÉLICAT: Lavage à la main à froid. Ne pas utiliser de sèche-linge. Éviter d\'essorer.',
103
+ wool: 'LAINE / POILS NOBLES: Laver à froid avec un programme spécial. Sécher à plat pour éviter les déformations. Ne pas utiliser de sèche-linge.',
104
+ linen: 'LIN: A tendance à beaucoup se froisser. Repasser légèrement humide pour de meilleurs résultats.',
105
+ semisynthetic: 'SEMI-SYNTHÉTIQUES: Se fragilise lorsqu\'il est mouillé. Manipuler avec soin et ne pas essorer fort.',
106
+ standard: 'LAVAGE STANDARD: Suivez toujours les instructions de l\'étiquette physique.',
107
107
  },
108
108
  fiberData: {
109
109
  cotton: {
@@ -214,7 +214,7 @@ export const content: ToolLocaleContent<FabricTruthUI> = {
214
214
  },
215
215
  fragile: {
216
216
  label: 'Doux mais Fragile',
217
- description: 'Très agréable au toucher, mais attention au lavage : a tendance à se déformer et à rétrécir facilement.',
217
+ description: 'Très agréable au toucher, mais attention au lavage: a tendance à se déformer et à rétrécir facilement.',
218
218
  },
219
219
  natural: {
220
220
  label: 'Qualité Naturelle',
@@ -235,13 +235,13 @@ export const content: ToolLocaleContent<FabricTruthUI> = {
235
235
  },
236
236
  },
237
237
  seo: [
238
- { type: 'title', text: 'La Vérité Derrière l\'Étiquette : Guide Maître de la Composition Textile', level: 2 },
238
+ { type: 'title', text: 'La Vérité Derrière l\'Étiquette: Guide Maître de la Composition Textile', level: 2 },
239
239
  { type: 'paragraph', html: 'Vous êtes-vous déjà demandé pourquoi ce t-shirt de marque vous fait tant transpirer, ou pourquoi ce pull "en laine" gratte insupportablement ? La réponse n\'est pas dans le design, mais dans la chimie de ses fibres.' },
240
240
  { type: 'paragraph', html: 'Dans un monde dominé par la <strong>Fast Fashion</strong>, la qualité des tissus est passée au second plan derrière l\'esthétique éphémère. Cependant, comprendre la composition textile est le seul moyen de faire un achat intelligent, durable et respectueux de votre peau. Notre outil de <strong>Vérité Textile</strong> analyse les pourcentages officiels pour vous révéler si vous êtes face à un vêtement de qualité ou simplement à un bloc de plastique traité.' },
241
241
  { type: 'title', text: 'Notre Méthodologie', level: 2 },
242
242
  { type: 'paragraph', html: 'Nous utilisons un algorithme pondéré basé sur trois piliers fondamentaux tirés des normes industrielles européennes et nord-américaines :' },
243
243
  { type: 'list', items: ['<strong>Respirabilité :</strong> Capacité de la fibre à laisser passer la vapeur d\'eau et l\'air.', '<strong>Durabilité :</strong> Résistance à l\'abrasion, à la traction et à la formation de <strong>pilling</strong> (bouloches).', '<strong>Efficacité Thermique :</strong> Capacité de rétention de chaleur ou de fraîcheur mécanique.'] },
244
- { type: 'tip', title: 'Important', html: 'La loi exige que tous les vêtements vendus dans l\'UE et aux États-Unis listent leurs composants par ordre décroissant de pourcentage. Si un vêtement n\'a pas d\'étiquette ou si celle-ci est illisible, méfiez-vous : il ne répond probablement pas aux normes minimales de sécurité textile.' },
244
+ { type: 'tip', title: 'Important', html: 'La loi exige que tous les vêtements vendus dans l\'UE et aux États-Unis listent leurs composants par ordre décroissant de pourcentage. Si un vêtement n\'a pas d\'étiquette ou si celle-ci est illisible, méfiez-vous: il ne répond probablement pas aux normes minimales de sécurité textile.' },
245
245
  { type: 'title', text: 'Les "Tromperies" Communes dans le Commerce', level: 2 },
246
246
  { type: 'paragraph', html: 'Il existe des techniques de marketing sophistiquées conçues pour élever la valeur perçue d\'un vêtement médiocre. Voici comment les repérer :' },
247
247
  { type: 'card', title: 'L\'Accroche de la Fibre Noble', icon: 'mdi:alert', html: 'Vous verrez des étiquettes indiquant "AVEC CACHEMIRE" ou "AVEC SOIE" en grosses lettres. En regardant la composition, vous découvrez 3 % de soie et 97 % de polyester. Ces 3 % n\'apportent ni douceur, ni brillance, ni chaleur ; ils ne servent qu\'à permettre à la marque d\'augmenter le prix de 20 %.' },
@@ -250,16 +250,16 @@ export const content: ToolLocaleContent<FabricTruthUI> = {
250
250
  { type: 'title', text: '1. Fibres Naturelles (Fièrement Organiques)', level: 3 },
251
251
  { type: 'paragraph', html: 'Ce sont la référence absolue. Le coton à fibres longues (comme le Pima ou l\'Égyptien) offre une douceur éternelle. Le lin est scientifiquement la meilleure fibre pour la chaleur en raison de sa structure moléculaire qui repousse la chaleur et absorbe l\'humidité. La laine et le chanvre sont des antibactériens naturels ; ils n\'ont pas besoin de lavages fréquents car ils ne retiennent pas les odeurs.' },
252
252
  { type: 'title', text: '2. Fibres Semi-Synthétiques (L\'Hybride)', level: 3 },
253
- { type: 'paragraph', html: 'On trouve ici la viscose, la rayonne et le modal. Ils ressemblent à de la soie mais coûtent comme du coton. Ils sont excellents pour les vêtements avec beaucoup de drapé, mais ils sont "assoiffés" : ils absorbent beaucoup d\'eau et mettent longtemps à sécher, ce qui peut favoriser la moisissure s\'ils ne sont pas soignés. Le Lyocell (Tencel) est la version premium et durable de ce groupe, avec un cycle de production fermé et une plus grande résistance.' },
253
+ { type: 'paragraph', html: 'On trouve ici la viscose, la rayonne et le modal. Ils ressemblent à de la soie mais coûtent comme du coton. Ils sont excellents pour les vêtements avec beaucoup de drapé, mais ils sont "assoiffés": ils absorbent beaucoup d\'eau et mettent longtemps à sécher, ce qui peut favoriser la moisissure s\'ils ne sont pas soignés. Le Lyocell (Tencel) est la version premium et durable de ce groupe, avec un cycle de production fermé et une plus grande résistance.' },
254
254
  { type: 'title', text: '3. Fibres Synthétiques (Plastiques Filés)', level: 3 },
255
- { type: 'paragraph', html: 'Le polyester est le roi du marché. Il est bon marché, ne se froisse pas et est éternel (littéralement, il mettra 200 ans à se décomposer). Le problème est qu\'il ne respire pas. Il crée un microclimat humide entre le tissu et votre peau, le terrain fertile idéal pour les bactéries. L\'acrylique est l\'imitation bon marché de la laine : il réchauffe, mais génère beaucoup d\'électricité statique et se couvre de bouloches en deux lavages.' },
255
+ { type: 'paragraph', html: 'Le polyester est le roi du marché. Il est bon marché, ne se froisse pas et est éternel (littéralement, il mettra 200 ans à se décomposer). Le problème est qu\'il ne respire pas. Il crée un microclimat humide entre le tissu et votre peau, le terrain fertile idéal pour les bactéries. L\'acrylique est l\'imitation bon marché de la laine: il réchauffe, mais génère beaucoup d\'électricité statique et se couvre de bouloches en deux lavages.' },
256
256
  { type: 'title', text: 'Conseils de Survie Textile', level: 2 },
257
257
  { type: 'paragraph', html: 'Même le meilleur vêtement au monde peut être ruiné par un seul lavage inapproprié. Voici les règles d\'or universelles :' },
258
258
  { type: 'tip', title: 'L\'Eau Froide est Votre Amie', html: '90 % des vêtements n\'ont pas besoin de plus de 30°C. La chaleur dégrade les fibres élastiques et rétrécit les fibres naturelles.' },
259
259
  { type: 'tip', title: 'Moins, c\'est Mieux (Detergent)', html: 'L\'excès de savon laisse des résidus qui attirent la saleté et rendent les vêtements raides.' },
260
- { type: 'tip', title: 'Seche linge : LEnnemi Subtil', html: 'Les peluches que vous voyez dans le filtre du sèche-linge sont des morceaux de vos vêtements qui se sont détachés par friction et chaleur.' },
260
+ { type: 'tip', title: 'Seche linge: LEnnemi Subtil', html: 'Les peluches que vous voyez dans le filtre du sèche-linge sont des morceaux de vos vêtements qui se sont détachés par friction et chaleur.' },
261
261
  { type: 'tip', title: 'Lavage à l\'envers', html: 'Protège la couleur et les broderies du frottement avec le tambour et d\'autres vêtements.' },
262
- { type: 'paragraph', html: '"Acheter moins, choisir mieux et faire durer."Ce calculateur est votre première étape vers une garde-robe consciente et de haute qualité.' },
262
+ { type: 'paragraph', html: '"Acheter moins, choisir mieux et faire durer." - Ce calculateur est votre première étape vers une garde-robe consciente et de haute qualité.' },
263
263
  ],
264
264
  faq: faqData,
265
265
  bibliography: bibliography,
@@ -259,7 +259,7 @@ export const content: ToolLocaleContent<FabricTruthUI> = {
259
259
  { type: 'tip', title: 'Sedikit Lebih Baik (Deterjen)', html: 'Kelebihan sabun meninggalkan residu yang menarik kotoran dan membuat pakaian terasa kaku.' },
260
260
  { type: 'tip', title: 'Pengering Mesin: Musuh yang Halus', html: 'Serat halus yang Anda lihat di filter pengering adalah bagian dari pakaian Anda yang terlepas karena gesekan dan panas.' },
261
261
  { type: 'tip', title: 'Cuci dengan Posisi Terbalik', html: 'Melindungi warna dan sulaman dari gesekan dengan drum mesin cuci dan pakaian lainnya.' },
262
- { type: 'paragraph', html: '"Beli lebih sedikit, pilih lebih baik, dan buat bertahan lama."Alat analisis ini adalah langkah pertama Anda menuju lemari pakaian yang sadar dan berkualitas tinggi.' },
262
+ { type: 'paragraph', html: '"Beli lebih sedikit, pilih lebih baik, dan buat bertahan lama." - Alat analisis ini adalah langkah pertama Anda menuju lemari pakaian yang sadar dan berkualitas tinggi.' },
263
263
  ],
264
264
  faq: faqData,
265
265
  bibliography: bibliography,