@jjlmoya/utils-home 1.16.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 (174) hide show
  1. package/package.json +1 -1
  2. package/src/category/i18n/de.ts +10 -10
  3. package/src/category/i18n/en.ts +8 -8
  4. package/src/category/i18n/es.ts +2 -2
  5. package/src/category/i18n/fr.ts +15 -15
  6. package/src/category/i18n/id.ts +8 -8
  7. package/src/category/i18n/it.ts +7 -7
  8. package/src/category/i18n/nl.ts +8 -8
  9. package/src/category/i18n/pl.ts +10 -10
  10. package/src/category/i18n/pt.ts +8 -8
  11. package/src/category/i18n/ru.ts +10 -10
  12. package/src/category/i18n/sv.ts +8 -8
  13. package/src/category/i18n/tr.ts +4 -4
  14. package/src/category/i18n/zh.ts +8 -8
  15. package/src/entries.ts +4 -1
  16. package/src/pages/[locale]/[slug].astro +28 -12
  17. package/src/tests/locale_completeness.test.ts +4 -22
  18. package/src/tests/no_en_dash.test.ts +70 -0
  19. package/src/tests/shared-test-helpers.ts +56 -0
  20. package/src/tests/tool_exports.test.ts +34 -0
  21. package/src/tests/tool_validation.test.ts +2 -2
  22. package/src/tool/dewPointCalculator/bibliography.ts +10 -0
  23. package/src/tool/dewPointCalculator/i18n/de.ts +7 -17
  24. package/src/tool/dewPointCalculator/i18n/en.ts +8 -18
  25. package/src/tool/dewPointCalculator/i18n/es.ts +7 -17
  26. package/src/tool/dewPointCalculator/i18n/fr.ts +8 -18
  27. package/src/tool/dewPointCalculator/i18n/id.ts +7 -17
  28. package/src/tool/dewPointCalculator/i18n/it.ts +7 -17
  29. package/src/tool/dewPointCalculator/i18n/ja.ts +6 -16
  30. package/src/tool/dewPointCalculator/i18n/ko.ts +6 -16
  31. package/src/tool/dewPointCalculator/i18n/nl.ts +7 -17
  32. package/src/tool/dewPointCalculator/i18n/pl.ts +7 -17
  33. package/src/tool/dewPointCalculator/i18n/pt.ts +7 -17
  34. package/src/tool/dewPointCalculator/i18n/ru.ts +13 -23
  35. package/src/tool/dewPointCalculator/i18n/sv.ts +7 -17
  36. package/src/tool/dewPointCalculator/i18n/tr.ts +6 -16
  37. package/src/tool/dewPointCalculator/i18n/zh.ts +7 -17
  38. package/src/tool/dewPointCalculator/seo.astro +2 -1
  39. package/src/tool/heatingComparator/bibliography.ts +14 -0
  40. package/src/tool/heatingComparator/i18n/de.ts +10 -24
  41. package/src/tool/heatingComparator/i18n/en.ts +3 -13
  42. package/src/tool/heatingComparator/i18n/es.ts +3 -17
  43. package/src/tool/heatingComparator/i18n/fr.ts +9 -19
  44. package/src/tool/heatingComparator/i18n/id.ts +3 -17
  45. package/src/tool/heatingComparator/i18n/it.ts +3 -17
  46. package/src/tool/heatingComparator/i18n/ja.ts +296 -310
  47. package/src/tool/heatingComparator/i18n/ko.ts +296 -306
  48. package/src/tool/heatingComparator/i18n/nl.ts +3 -17
  49. package/src/tool/heatingComparator/i18n/pl.ts +3 -17
  50. package/src/tool/heatingComparator/i18n/pt.ts +3 -17
  51. package/src/tool/heatingComparator/i18n/ru.ts +14 -24
  52. package/src/tool/heatingComparator/i18n/sv.ts +6 -20
  53. package/src/tool/heatingComparator/i18n/tr.ts +2 -16
  54. package/src/tool/heatingComparator/i18n/zh.ts +296 -306
  55. package/src/tool/heatingComparator/seo.astro +3 -3
  56. package/src/tool/ledSavingCalculator/bibliography.ts +14 -0
  57. package/src/tool/ledSavingCalculator/i18n/de.ts +6 -16
  58. package/src/tool/ledSavingCalculator/i18n/en.ts +6 -20
  59. package/src/tool/ledSavingCalculator/i18n/es.ts +6 -20
  60. package/src/tool/ledSavingCalculator/i18n/fr.ts +10 -24
  61. package/src/tool/ledSavingCalculator/i18n/id.ts +5 -15
  62. package/src/tool/ledSavingCalculator/i18n/it.ts +6 -16
  63. package/src/tool/ledSavingCalculator/i18n/ja.ts +5 -15
  64. package/src/tool/ledSavingCalculator/i18n/ko.ts +4 -14
  65. package/src/tool/ledSavingCalculator/i18n/nl.ts +5 -15
  66. package/src/tool/ledSavingCalculator/i18n/pl.ts +5 -15
  67. package/src/tool/ledSavingCalculator/i18n/pt.ts +5 -15
  68. package/src/tool/ledSavingCalculator/i18n/ru.ts +8 -18
  69. package/src/tool/ledSavingCalculator/i18n/sv.ts +5 -15
  70. package/src/tool/ledSavingCalculator/i18n/tr.ts +5 -15
  71. package/src/tool/ledSavingCalculator/i18n/zh.ts +6 -16
  72. package/src/tool/ledSavingCalculator/seo.astro +2 -1
  73. package/src/tool/projectorCalculator/bibliography.ts +5 -0
  74. package/src/tool/projectorCalculator/i18n/de.ts +4 -8
  75. package/src/tool/projectorCalculator/i18n/en.ts +3 -8
  76. package/src/tool/projectorCalculator/i18n/es.ts +4 -9
  77. package/src/tool/projectorCalculator/i18n/fr.ts +6 -11
  78. package/src/tool/projectorCalculator/i18n/id.ts +4 -9
  79. package/src/tool/projectorCalculator/i18n/it.ts +4 -8
  80. package/src/tool/projectorCalculator/i18n/ja.ts +175 -179
  81. package/src/tool/projectorCalculator/i18n/ko.ts +175 -179
  82. package/src/tool/projectorCalculator/i18n/nl.ts +4 -8
  83. package/src/tool/projectorCalculator/i18n/pl.ts +5 -9
  84. package/src/tool/projectorCalculator/i18n/pt.ts +4 -8
  85. package/src/tool/projectorCalculator/i18n/ru.ts +7 -11
  86. package/src/tool/projectorCalculator/i18n/sv.ts +4 -8
  87. package/src/tool/projectorCalculator/i18n/tr.ts +4 -8
  88. package/src/tool/projectorCalculator/i18n/zh.ts +175 -179
  89. package/src/tool/projectorCalculator/seo.astro +2 -1
  90. package/src/tool/qrGenerator/bibliography.ts +14 -0
  91. package/src/tool/qrGenerator/i18n/de.ts +192 -202
  92. package/src/tool/qrGenerator/i18n/en.ts +3 -17
  93. package/src/tool/qrGenerator/i18n/es.ts +2 -16
  94. package/src/tool/qrGenerator/i18n/fr.ts +3 -17
  95. package/src/tool/qrGenerator/i18n/id.ts +146 -150
  96. package/src/tool/qrGenerator/i18n/it.ts +169 -173
  97. package/src/tool/qrGenerator/i18n/ja.ts +146 -150
  98. package/src/tool/qrGenerator/i18n/ko.ts +146 -150
  99. package/src/tool/qrGenerator/i18n/nl.ts +146 -150
  100. package/src/tool/qrGenerator/i18n/pl.ts +146 -150
  101. package/src/tool/qrGenerator/i18n/pt.ts +146 -150
  102. package/src/tool/qrGenerator/i18n/ru.ts +146 -150
  103. package/src/tool/qrGenerator/i18n/sv.ts +146 -150
  104. package/src/tool/qrGenerator/i18n/tr.ts +146 -150
  105. package/src/tool/qrGenerator/i18n/zh.ts +146 -150
  106. package/src/tool/qrGenerator/seo.astro +2 -1
  107. package/src/tool/solarCalculator/bibliography.ts +5 -0
  108. package/src/tool/solarCalculator/i18n/de.ts +141 -145
  109. package/src/tool/solarCalculator/i18n/en.ts +7 -12
  110. package/src/tool/solarCalculator/i18n/es.ts +5 -10
  111. package/src/tool/solarCalculator/i18n/fr.ts +8 -13
  112. package/src/tool/solarCalculator/i18n/id.ts +4 -8
  113. package/src/tool/solarCalculator/i18n/it.ts +4 -8
  114. package/src/tool/solarCalculator/i18n/ja.ts +121 -125
  115. package/src/tool/solarCalculator/i18n/ko.ts +116 -120
  116. package/src/tool/solarCalculator/i18n/nl.ts +4 -7
  117. package/src/tool/solarCalculator/i18n/pl.ts +5 -9
  118. package/src/tool/solarCalculator/i18n/pt.ts +4 -8
  119. package/src/tool/solarCalculator/i18n/ru.ts +7 -10
  120. package/src/tool/solarCalculator/i18n/sv.ts +4 -7
  121. package/src/tool/solarCalculator/i18n/tr.ts +4 -7
  122. package/src/tool/solarCalculator/i18n/zh.ts +116 -120
  123. package/src/tool/solarCalculator/seo.astro +2 -1
  124. package/src/tool/tariffComparator/bibliography.ts +7 -0
  125. package/src/tool/tariffComparator/i18n/de.ts +129 -132
  126. package/src/tool/tariffComparator/i18n/en.ts +5 -12
  127. package/src/tool/tariffComparator/i18n/es.ts +5 -12
  128. package/src/tool/tariffComparator/i18n/fr.ts +8 -15
  129. package/src/tool/tariffComparator/i18n/id.ts +2 -5
  130. package/src/tool/tariffComparator/i18n/it.ts +2 -5
  131. package/src/tool/tariffComparator/i18n/ja.ts +129 -132
  132. package/src/tool/tariffComparator/i18n/ko.ts +129 -132
  133. package/src/tool/tariffComparator/i18n/nl.ts +2 -5
  134. package/src/tool/tariffComparator/i18n/pl.ts +3 -6
  135. package/src/tool/tariffComparator/i18n/pt.ts +2 -5
  136. package/src/tool/tariffComparator/i18n/ru.ts +2 -5
  137. package/src/tool/tariffComparator/i18n/sv.ts +2 -5
  138. package/src/tool/tariffComparator/i18n/tr.ts +2 -5
  139. package/src/tool/tariffComparator/i18n/zh.ts +129 -132
  140. package/src/tool/tariffComparator/seo.astro +2 -1
  141. package/src/tool/wifiRangeSimulator/bibliography.astro +14 -0
  142. package/src/tool/wifiRangeSimulator/bibliography.ts +14 -0
  143. package/src/tool/wifiRangeSimulator/component.astro +170 -0
  144. package/src/tool/wifiRangeSimulator/entry.ts +29 -0
  145. package/src/tool/wifiRangeSimulator/i18n/de.ts +477 -0
  146. package/src/tool/wifiRangeSimulator/i18n/en.ts +477 -0
  147. package/src/tool/wifiRangeSimulator/i18n/es.ts +477 -0
  148. package/src/tool/wifiRangeSimulator/i18n/fr.ts +477 -0
  149. package/src/tool/wifiRangeSimulator/i18n/id.ts +477 -0
  150. package/src/tool/wifiRangeSimulator/i18n/it.ts +477 -0
  151. package/src/tool/wifiRangeSimulator/i18n/ja.ts +477 -0
  152. package/src/tool/wifiRangeSimulator/i18n/ko.ts +477 -0
  153. package/src/tool/wifiRangeSimulator/i18n/nl.ts +477 -0
  154. package/src/tool/wifiRangeSimulator/i18n/pl.ts +477 -0
  155. package/src/tool/wifiRangeSimulator/i18n/pt.ts +477 -0
  156. package/src/tool/wifiRangeSimulator/i18n/ru.ts +477 -0
  157. package/src/tool/wifiRangeSimulator/i18n/sv.ts +477 -0
  158. package/src/tool/wifiRangeSimulator/i18n/tr.ts +477 -0
  159. package/src/tool/wifiRangeSimulator/i18n/zh.ts +477 -0
  160. package/src/tool/wifiRangeSimulator/i18n-utils.ts +14 -0
  161. package/src/tool/wifiRangeSimulator/index.ts +8 -0
  162. package/src/tool/wifiRangeSimulator/logic.ts +220 -0
  163. package/src/tool/wifiRangeSimulator/seo.astro +15 -0
  164. package/src/tool/wifiRangeSimulator/sketch-actions.ts +168 -0
  165. package/src/tool/wifiRangeSimulator/sketch-events.ts +138 -0
  166. package/src/tool/wifiRangeSimulator/sketch-render-dash.ts +170 -0
  167. package/src/tool/wifiRangeSimulator/sketch-render-device.ts +42 -0
  168. package/src/tool/wifiRangeSimulator/sketch-render.ts +155 -0
  169. package/src/tool/wifiRangeSimulator/sketch-state.ts +186 -0
  170. package/src/tool/wifiRangeSimulator/sketch.ts +100 -0
  171. package/src/tool/wifiRangeSimulator/ui.ts +69 -0
  172. package/src/tool/wifiRangeSimulator/wifi-range-simulator.css +583 -0
  173. package/src/tools.ts +2 -0
  174. package/src/types.ts +0 -2
@@ -16,7 +16,7 @@ export const content: CategoryLocaleContent = {
16
16
  },
17
17
  {
18
18
  type: 'paragraph',
19
- html: 'Uma casa eficiente não é um luxo é uma decisão técnica. A diferença entre um agregado familiar com uma fatura de eletricidade descontrolada e um com consumo monitorizado raramente reside no preço da tarifa: reside em saber exatamente quanto consome cada dispositivo, quando faz sentido autogerar energia e onde ocorrem as perdas.',
19
+ html: 'Uma casa eficiente não é um luxo: é uma decisão técnica. A diferença entre um agregado familiar com uma fatura de eletricidade descontrolada e um com consumo monitorizado raramente reside no preço da tarifa: reside em saber exatamente quanto consome cada dispositivo, quando faz sentido autogerar energia e onde ocorrem as perdas.',
20
20
  },
21
21
  {
22
22
  type: 'title',
@@ -25,7 +25,7 @@ export const content: CategoryLocaleContent = {
25
25
  },
26
26
  {
27
27
  type: 'paragraph',
28
- html: 'As instalações fotovoltaicas residenciais têm um retorno real do investimento que depende de três variáveis: a irradiação no seu local, o ângulo de inclinação dos painéis e o seu consumo horário. Um painel inclinado 10° abaixo do ideal pode perder <strong>1520% da produção anual</strong>. A nossa calculadora solar indica-lhe o ângulo exato e a estimativa de geração mensal.',
28
+ html: 'As instalações fotovoltaicas residenciais têm um retorno real do investimento que depende de três variáveis: a irradiação no seu local, o ângulo de inclinação dos painéis e o seu consumo horário. Um painel inclinado 10° abaixo do ideal pode perder <strong>15-20% da produção anual</strong>. A nossa calculadora solar indica-lhe o ângulo exato e a estimativa de geração mensal.',
29
29
  },
30
30
  {
31
31
  type: 'paragraph',
@@ -42,7 +42,7 @@ export const content: CategoryLocaleContent = {
42
42
  },
43
43
  {
44
44
  type: 'paragraph',
45
- html: 'Escolher a tarifa de eletricidade correta é igualmente importante. Os contratos de mercado com preço fixo podem ser vantajosos para consumidores com hábitos regulares; as tarifas indexadas flutuam com o mercado grossista e recompensam quem desloca o consumo para as horas de vazio. Comparar ambas as opções com os seus dados de consumo reais pode fazer uma diferença de <strong>100300 € por ano</strong>.',
45
+ html: 'Escolher a tarifa de eletricidade correta é igualmente importante. Os contratos de mercado com preço fixo podem ser vantajosos para consumidores com hábitos regulares; as tarifas indexadas flutuam com o mercado grossista e recompensam quem desloca o consumo para as horas de vazio. Comparar ambas as opções com os seus dados de consumo reais pode fazer uma diferença de <strong>100-300 € por ano</strong>.',
46
46
  },
47
47
  {
48
48
  type: 'title',
@@ -51,7 +51,7 @@ export const content: CategoryLocaleContent = {
51
51
  },
52
52
  {
53
53
  type: 'paragraph',
54
- html: 'A humidade relativa sustentada acima de 70% leva à condensação em pontes térmicas, ao crescimento de bolor e à deterioração estrutural. A temperatura do ponto de orvalho o valor no qual o vapor de água no ar condensa é a métrica principal. Se a superfície da sua parede interior estiver abaixo desse ponto, a condensação formar-se-á independentemente de poder vê-la ou não.',
54
+ html: 'A humidade relativa sustentada acima de 70% leva à condensação em pontes térmicas, ao crescimento de bolor e à deterioração estrutural. A temperatura do ponto de orvalho: o valor no qual o vapor de água no ar condensa: é a métrica principal. Se a superfície da sua parede interior estiver abaixo desse ponto, a condensação formar-se-á independentemente de poder vê-la ou não.',
55
55
  },
56
56
  {
57
57
  type: 'paragraph',
@@ -64,7 +64,7 @@ export const content: CategoryLocaleContent = {
64
64
  },
65
65
  {
66
66
  type: 'paragraph',
67
- html: 'Um projetor não se coloca "onde calhar". O rácio de projeção (throw ratio) a relação entre a distância de projeção e a largura da imagem determina exatamente quão atrás precisa de posicionar a unidade para alcançar o tamanho de ecrã desejado. Um erro de posicionamento de 50 cm pode significar uma imagem 20 cm mais pequena, ou forçar um zoom digital que reduz a resolução efetiva.',
67
+ html: 'Um projetor não se coloca "onde calhar". O rácio de projeção (throw ratio): a relação entre a distância de projeção e a largura da imagem: determina exatamente quão atrás precisa de posicionar a unidade para alcançar o tamanho de ecrã desejado. Um erro de posicionamento de 50 cm pode significar uma imagem 20 cm mais pequena, ou forçar um zoom digital que reduz a resolução efetiva.',
68
68
  },
69
69
  {
70
70
  type: 'paragraph',
@@ -77,12 +77,12 @@ export const content: CategoryLocaleContent = {
77
77
  },
78
78
  {
79
79
  type: 'paragraph',
80
- html: 'A casa moderna integra tecnologia em todos os níveis: redes Wi-Fi, dispositivos IoT, acesso baseado em códigos QR. O gerador de códigos QR permite-lhe criar atalhos para o seu Wi-Fi doméstico, cartões de contacto, URLs de dispositivos inteligentes ou qualquer informação que queira partilhar facilmente com convidados ou entre dispositivos sem precisar de digitar.',
80
+ html: 'A casa moderna integra tecnologia em todos os níveis: redes Wi-Fi, dispositivos IoT, acesso baseado em códigos QR. O gerador de códigos QR permite-lhe criar atalhos para o seu Wi-Fi doméstico, cartões de contacto, URLs de dispositivos inteligentes ou qualquer informação que queira partilhar facilmente com convidados ou entre dispositivos: sem precisar de digitar.',
81
81
  },
82
82
  {
83
83
  type: 'list',
84
84
  items: [
85
- '<strong>Poupança quantificável:</strong> Cada ferramenta devolve números concretos euros poupados por ano, kWh gerados por mês, graus de inclinação ideais. Sem estimativas vagas.',
85
+ '<strong>Poupança quantificável:</strong> Cada ferramenta devolve números concretos: euros poupados por ano, kWh gerados por mês, graus de inclinação ideais. Sem estimativas vagas.',
86
86
  '<strong>Sem necessidade de instalação:</strong> Calculadoras online que correm diretamente no navegador, sem necessidade de aplicações ou contas.',
87
87
  '<strong>Baseado em normas técnicas:</strong> Fórmulas psicrométricas (ASHRAE), ótica de projeção, radiação solar por latitude e regulamentos elétricos relevantes.',
88
88
  '<strong>Útil antes de comprar:</strong> Valide decisões de compra antes de se comprometer. Os painéis solares compensam no seu telhado? Quanto é que os LEDs poupam realmente? Calcule primeiro.',
@@ -95,7 +95,7 @@ export const content: CategoryLocaleContent = {
95
95
  },
96
96
  {
97
97
  type: 'paragraph',
98
- html: 'As melhorias na eficiência energética doméstica têm um ROI concreto. Uma instalação fotovoltaica bem dimensionada pode pagar-se em 69 anos com os preços atuais da eletricidade. Uma substituição total por LEDs numa casa média paga-se em menos de 2 anos. Uma tarifa bem escolhida poupa dinheiro desde o primeiro mês. O ponto de partida é sempre o mesmo: <strong>medir antes de agir</strong>.',
98
+ html: 'As melhorias na eficiência energética doméstica têm um ROI concreto. Uma instalação fotovoltaica bem dimensionada pode pagar-se em 6-9 anos com os preços atuais da eletricidade. Uma substituição total por LEDs numa casa média paga-se em menos de 2 anos. Uma tarifa bem escolhida poupa dinheiro desde o primeiro mês. O ponto de partida é sempre o mesmo: <strong>medir antes de agir</strong>.',
99
99
  },
100
100
  {
101
101
  type: 'paragraph',
@@ -12,11 +12,11 @@ export const content: CategoryLocaleContent = {
12
12
  },
13
13
  {
14
14
  type: 'paragraph',
15
- html: 'Большинство решений в быту принимается интуитивно: «Думаю, этих солнечных панелей хватит», «замена лампочек должна что-то сэкономить». На самом деле пятиминутный расчет может сэкономить вам сотни евро в год или уберечь от дорогостоящего ремонта. Наши инструменты основаны на <strong>реальной физике</strong>: солнечное излучение по широте, измеренная потребляемая мощность, психрометрия влажного воздуха, проекционная оптика.',
15
+ html: 'Большинство решений в быту принимается интуитивно: "Думаю, этих солнечных панелей хватит", "замена лампочек должна что-то сэкономить". На самом деле пятиминутный расчет может сэкономить вам сотни евро в год или уберечь от дорогостоящего ремонта. Наши инструменты основаны на <strong>реальной физике</strong>: солнечное излучение по широте, измеренная потребляемая мощность, психрометрия влажного воздуха, проекционная оптика.',
16
16
  },
17
17
  {
18
18
  type: 'paragraph',
19
- html: 'Эффективный дом это не роскошь, а техническое решение. Разница между домохозяйством с бесконтрольно растущими счетами за электричество и домом с контролируемым потреблением редко заключается в цене тарифа: она в точном знании того, сколько потребляет каждое устройство, когда имеет смысл вырабатывать энергию самостоятельно и где происходят потери.',
19
+ html: 'Эффективный дом: это не роскошь, а техническое решение. Разница между домохозяйством с бесконтрольно растущими счетами за электричество и домом с контролируемым потреблением редко заключается в цене тарифа: она в точном знании того, сколько потребляет каждое устройство, когда имеет смысл вырабатывать энергию самостоятельно и где происходят потери.',
20
20
  },
21
21
  {
22
22
  type: 'title',
@@ -25,11 +25,11 @@ export const content: CategoryLocaleContent = {
25
25
  },
26
26
  {
27
27
  type: 'paragraph',
28
- html: 'Домашние фотоэлектрические установки имеют реальную окупаемость, которая зависит от трех переменных: уровня инсоляции в вашем регионе, угла наклона панелей и вашего почасового потребления. Панель, установленная под углом на 10° ниже оптимального, может терять <strong>1520% годовой выработки</strong>. Наш солнечный калькулятор даст вам точный угол и оценку ежемесячной генерации.',
28
+ html: 'Домашние фотоэлектрические установки имеют реальную окупаемость, которая зависит от трех переменных: уровня инсоляции в вашем регионе, угла наклона панелей и вашего почасового потребления. Панель, установленная под углом на 10° ниже оптимального, может терять <strong>15-20% годовой выработки</strong>. Наш солнечный калькулятор даст вам точный угол и оценку ежемесячной генерации.',
29
29
  },
30
30
  {
31
31
  type: 'paragraph',
32
- html: 'Оптимальная ориентация и наклон солнечной панели зависят от широты. В континентальной Европе идеальный угол варьируется от 30° до 40° в зависимости от сезона. Оптимизация под общую годовую выработку это не то же самое, что оптимизация для зимних месяцев, когда спрос на электроэнергию максимален.',
32
+ html: 'Оптимальная ориентация и наклон солнечной панели зависят от широты. В континентальной Европе идеальный угол варьируется от 30° до 40° в зависимости от сезона. Оптимизация под общую годовую выработку: это не то же самое, что оптимизация для зимних месяцев, когда спрос на электроэнергию максимален.',
33
33
  },
34
34
  {
35
35
  type: 'title',
@@ -38,11 +38,11 @@ export const content: CategoryLocaleContent = {
38
38
  },
39
39
  {
40
40
  type: 'paragraph',
41
- html: 'Переход с галогенных ламп на светодиодные (LED) это не просто «использование меньшего количества ватт». Это понимание того, что светодиод мощностью 9 Вт заменяет 60-ваттную галогенную лампу, обеспечивая тот же световой поток (800 люмен), что дает <strong>сокращение потребления на 85%</strong>. Умножив это на годовое время работы и цену за кВт·ч, можно рассчитать экономию до копейки. Наш калькулятор делает именно это.',
41
+ html: 'Переход с галогенных ламп на светодиодные (LED): это не просто "использование меньшего количества ватт". Это понимание того, что светодиод мощностью 9 Вт заменяет 60-ваттную галогенную лампу, обеспечивая тот же световой поток (800 люмен), что дает <strong>сокращение потребления на 85%</strong>. Умножив это на годовое время работы и цену за кВт·ч, можно рассчитать экономию до копейки. Наш калькулятор делает именно это.',
42
42
  },
43
43
  {
44
44
  type: 'paragraph',
45
- html: 'Выбор правильного тарифа на электроэнергию не менее важен. Контракты с фиксированной ценой могут быть выгодны потребителям с регулярными привычками; индексируемые тарифы колеблются вместе с оптовым рынком и поощряют тех, кто переносит потребление на часы вне пиковой нагрузки. Сравнение обоих вариантов с вашими реальными данными о потреблении может дать разницу в <strong>100300 € в год</strong>.',
45
+ html: 'Выбор правильного тарифа на электроэнергию не менее важен. Контракты с фиксированной ценой могут быть выгодны потребителям с регулярными привычками; индексируемые тарифы колеблются вместе с оптовым рынком и поощряют тех, кто переносит потребление на часы вне пиковой нагрузки. Сравнение обоих вариантов с вашими реальными данными о потреблении может дать разницу в <strong>100-300 € в год</strong>.',
46
46
  },
47
47
  {
48
48
  type: 'title',
@@ -51,7 +51,7 @@ export const content: CategoryLocaleContent = {
51
51
  },
52
52
  {
53
53
  type: 'paragraph',
54
- html: 'Поддержание относительной влажности выше 70% приводит к конденсации на тепловых мостиках, росту плесени и разрушению конструкций. Температура точки росы значение, при котором водяной пар в воздухе конденсируется является ключевым показателем. Если температура поверхности вашей внутренней стены ниже этой точки, конденсат будет образовываться независимо от того, видите вы его или нет.',
54
+ html: 'Поддержание относительной влажности выше 70% приводит к конденсации на тепловых мостиках, росту плесени и разрушению конструкций. Температура точки росы: значение, при котором водяной пар в воздухе конденсируется: является ключевым показателем. Если температура поверхности вашей внутренней стены ниже этой точки, конденсат будет образовываться независимо от того, видите вы его или нет.',
55
55
  },
56
56
  {
57
57
  type: 'paragraph',
@@ -64,7 +64,7 @@ export const content: CategoryLocaleContent = {
64
64
  },
65
65
  {
66
66
  type: 'paragraph',
67
- html: 'Проектор не ставят «куда получится». Проекционное отношение (throw ratio) зависимость между расстоянием до экрана и шириной изображения точно определяет, насколько далеко нужно расположить устройство, чтобы получить желаемый размер экрана. Ошибка в установке на 50 см может привести к уменьшению изображения на 20 см или вынудить использовать цифровой зум, снижающий четкость.',
67
+ html: 'Проектор не ставят "куда получится". Проекционное отношение (throw ratio): зависимость между расстоянием до экрана и шириной изображения: точно определяет, насколько далеко нужно расположить устройство, чтобы получить желаемый размер экрана. Ошибка в установке на 50 см может привести к уменьшению изображения на 20 см или вынудить использовать цифровой зум, снижающий четкость.',
68
68
  },
69
69
  {
70
70
  type: 'paragraph',
@@ -82,7 +82,7 @@ export const content: CategoryLocaleContent = {
82
82
  {
83
83
  type: 'list',
84
84
  items: [
85
- '<strong>Количественная экономия:</strong> Каждый инструмент возвращает конкретные цифры сэкономленные евро в год, выработанные кВт·ч в месяц, оптимальные углы наклона. Никаких туманных оценок.',
85
+ '<strong>Количественная экономия:</strong> Каждый инструмент возвращает конкретные цифры: сэкономленные евро в год, выработанные кВт·ч в месяц, оптимальные углы наклона. Никаких туманных оценок.',
86
86
  '<strong>Не требует установки:</strong> Онлайн-калькуляторы, которые работают прямо в браузере, не нужны приложения или учетные записи.',
87
87
  '<strong>Основано на технических стандартах:</strong> Психрометрические формулы (ASHRAE), проекционная оптика, солнечная радиация по широте и соответствующие электротехнические нормы.',
88
88
  '<strong>Полезно перед покупкой:</strong> Проверяйте решения о покупке, прежде чем их принимать. Окупятся ли солнечные панели на вашей крыше? Сколько на самом деле экономят светодиоды? Сначала посчитайте.',
@@ -95,7 +95,7 @@ export const content: CategoryLocaleContent = {
95
95
  },
96
96
  {
97
97
  type: 'paragraph',
98
- html: 'Улучшения энергоэффективности дома имеют конкретный ROI (окупаемость). Правильно подобранная фотоэлектрическая установка может окупиться за 69 лет при нынешних ценах на электроэнергию. Полная замена ламп на светодиодные в среднем доме окупается менее чем за 2 года. Грамотно выбранный тариф экономит деньги с первого месяца. Начальная точка всегда одна и та же: <strong>измеряйте, прежде чем действовать</strong>.',
98
+ html: 'Улучшения энергоэффективности дома имеют конкретный ROI (окупаемость). Правильно подобранная фотоэлектрическая установка может окупиться за 6-9 лет при нынешних ценах на электроэнергию. Полная замена ламп на светодиодные в среднем доме окупается менее чем за 2 года. Грамотно выбранный тариф экономит деньги с первого месяца. Начальная точка всегда одна и та же: <strong>измеряйте, прежде чем действовать</strong>.',
99
99
  },
100
100
  {
101
101
  type: 'paragraph',
@@ -16,7 +16,7 @@ export const content: CategoryLocaleContent = {
16
16
  },
17
17
  {
18
18
  type: 'paragraph',
19
- html: 'Ett effektivt hem är inte en lyx det är ett tekniskt beslut. Skillnaden mellan ett hushåll med en skenande elräkning och ett med kontrollerad förbrukning beror sällan på tariffpriset: det handlar om att veta exakt hur mycket varje enhet förbrukar, när det är vettigt att generera egen energi och var förlusterna uppstår.',
19
+ html: 'Ett effektivt hem är inte en lyx: det är ett tekniskt beslut. Skillnaden mellan ett hushåll med en skenande elräkning och ett med kontrollerad förbrukning beror sällan på tariffpriset: det handlar om att veta exakt hur mycket varje enhet förbrukar, när det är vettigt att generera egen energi och var förlusterna uppstår.',
20
20
  },
21
21
  {
22
22
  type: 'title',
@@ -25,7 +25,7 @@ export const content: CategoryLocaleContent = {
25
25
  },
26
26
  {
27
27
  type: 'paragraph',
28
- html: 'Fotovoltaiska installationer för bostäder har en verklig avkastning på investeringen som beror på tre variabler: instrålningen på din plats, panelernas lutningsvinkel och din förbrukning per timme. En panel som lutar 10° under det optimala kan förlora <strong>1520 % av den årliga produktionen</strong>. Vår solkalkylator ger dig den exakta vinkeln och en uppskattning av den månatliga generationen.',
28
+ html: 'Fotovoltaiska installationer för bostäder har en verklig avkastning på investeringen som beror på tre variabler: instrålningen på din plats, panelernas lutningsvinkel och din förbrukning per timme. En panel som lutar 10° under det optimala kan förlora <strong>15-20 % av den årliga produktionen</strong>. Vår solkalkylator ger dig den exakta vinkeln och en uppskattning av den månatliga generationen.',
29
29
  },
30
30
  {
31
31
  type: 'paragraph',
@@ -42,7 +42,7 @@ export const content: CategoryLocaleContent = {
42
42
  },
43
43
  {
44
44
  type: 'paragraph',
45
- html: 'Att välja rätt eltariff är lika viktigt. Fastprisavtal kan vara fördelaktiga för konsumenter med regelbundna vanor; rörliga tariffer fluktuerar med grossistmarknaden och belönar dem som flyttar sin förbrukning till lågtidstimmar. Att jämföra båda alternativen med dina faktiska förbrukningsdata kan göra en skillnad på <strong>100300 € per år</strong>.',
45
+ html: 'Att välja rätt eltariff är lika viktigt. Fastprisavtal kan vara fördelaktiga för konsumenter med regelbundna vanor; rörliga tariffer fluktuerar med grossistmarknaden och belönar dem som flyttar sin förbrukning till lågtidstimmar. Att jämföra båda alternativen med dina faktiska förbrukningsdata kan göra en skillnad på <strong>100-300 € per år</strong>.',
46
46
  },
47
47
  {
48
48
  type: 'title',
@@ -51,7 +51,7 @@ export const content: CategoryLocaleContent = {
51
51
  },
52
52
  {
53
53
  type: 'paragraph',
54
- html: 'Ihållande relativ luftfuktighet över 70 % leder till kondens vid köldbryggor, mögeltillväxt och strukturell försämring. Daggpunktstemperaturen det värde vid vilket vattenånga i luften kondenserar är nyckeltalet. Om ytan på din innervägg är under den punkten kommer kondens att bildas oavsett om du kan se den eller inte.',
54
+ html: 'Ihållande relativ luftfuktighet över 70 % leder till kondens vid köldbryggor, mögeltillväxt och strukturell försämring. Daggpunktstemperaturen: det värde vid vilket vattenånga i luften kondenserar: är nyckeltalet. Om ytan på din innervägg är under den punkten kommer kondens att bildas oavsett om du kan se den eller inte.',
55
55
  },
56
56
  {
57
57
  type: 'paragraph',
@@ -64,7 +64,7 @@ export const content: CategoryLocaleContent = {
64
64
  },
65
65
  {
66
66
  type: 'paragraph',
67
- html: 'En projektor placeras inte "var den än får plats". Projektionsförhållandet (throw ratio) förhållandet mellan projektionsavstånd och bildbredd avgör exakt hur långt bak du behöver placera enheten för att uppnå önskad skärmstorlek. Ett placeringsfel på 50 cm kan innebära en 20 cm mindre bild, eller tvinga fram en digital zoom som minskar den effektiva upplösningen.',
67
+ html: 'En projektor placeras inte "var den än får plats". Projektionsförhållandet (throw ratio): förhållandet mellan projektionsavstånd och bildbredd: avgör exakt hur långt bak du behöver placera enheten för att uppnå önskad skärmstorlek. Ett placeringsfel på 50 cm kan innebära en 20 cm mindre bild, eller tvinga fram en digital zoom som minskar den effektiva upplösningen.',
68
68
  },
69
69
  {
70
70
  type: 'paragraph',
@@ -77,12 +77,12 @@ export const content: CategoryLocaleContent = {
77
77
  },
78
78
  {
79
79
  type: 'paragraph',
80
- html: 'Det moderna hemmet integrerar teknik på alla nivåer: Wi-Fi-nätverk, IoT-enheter, QR-kodsbaserad åtkomst. QR-kodgeneratorn låter dig skapa genvägar till ditt hem-Wi-Fi, kontaktkort, URL:er till smarta enheter eller all information du enkelt vill dela med gäster eller mellan enheter utan att behöva skriva.',
80
+ html: 'Det moderna hemmet integrerar teknik på alla nivåer: Wi-Fi-nätverk, IoT-enheter, QR-kodsbaserad åtkomst. QR-kodgeneratorn låter dig skapa genvägar till ditt hem-Wi-Fi, kontaktkort, URL:er till smarta enheter eller all information du enkelt vill dela med gäster eller mellan enheter: utan att behöva skriva.',
81
81
  },
82
82
  {
83
83
  type: 'list',
84
84
  items: [
85
- '<strong>Kvantifierbara besparingar:</strong> Varje verktyg levererar konkreta siffror sparade euro per år, genererade kWh per månad, optimala lutningsvinklar. Inga vaga uppskattningar.',
85
+ '<strong>Kvantifierbara besparingar:</strong> Varje verktyg levererar konkreta siffror: sparade euro per år, genererade kWh per månad, optimala lutningsvinklar. Inga vaga uppskattningar.',
86
86
  '<strong>Ingen installation krävs:</strong> Onlinekalkylatorer som körs direkt i webbläsaren, inga appar eller konton krävs.',
87
87
  '<strong>Baserat på tekniska standarder:</strong> Psykrometriska formler (ASHRAE), projektionsoptik, solinstrålning per breddgrad och relevanta elföreskrifter.',
88
88
  '<strong>Användbart innan du köper:</strong> Validera köpbeslut innan du binder dig. Lönar sig solpaneler på ditt tak? Hur mycket sparar LED-lampor egentligen? Räkna först.',
@@ -95,7 +95,7 @@ export const content: CategoryLocaleContent = {
95
95
  },
96
96
  {
97
97
  type: 'paragraph',
98
- html: 'Förbättringar av hemets energieffektivitet har en konkret ROI. En väl dimensionerad solcellsanläggning kan betala sig själv på 69 år med nuvarande elpriser. Ett fullständigt byte till LED i ett genomsnittligt hem betalar sig på under 2 år. En väl vald tariff sparar pengar från första månaden. Startpunkten är alltid densamma: <strong>mät innan du agerar</strong>.',
98
+ html: 'Förbättringar av hemets energieffektivitet har en konkret ROI. En väl dimensionerad solcellsanläggning kan betala sig själv på 6-9 år med nuvarande elpriser. Ett fullständigt byte till LED i ett genomsnittligt hem betalar sig på under 2 år. En väl vald tariff sparar pengar från första månaden. Startpunkten är alltid densamma: <strong>mät innan du agerar</strong>.',
99
99
  },
100
100
  {
101
101
  type: 'paragraph',
@@ -42,7 +42,7 @@ export const content: CategoryLocaleContent = {
42
42
  },
43
43
  {
44
44
  type: 'paragraph',
45
- html: 'Doğru elektrik tarifesini seçmek de bir o kadar önemlidir. Sabit fiyatlı piyasa sözleşmeleri, düzenli alışkanlıkları olan tüketiciler için avantajlı olabilir; endeksli tarifeler toptan satış piyasasıyla dalgalanır ve tüketimini yoğun olmayan saatlere kaydıranları ödüllendirir. Her iki seçeneği de gerçek tüketim verilerinizle karşılaştırmak, <strong>yılda 100300 €</strong> fark yaratabilir.',
45
+ html: 'Doğru elektrik tarifesini seçmek de bir o kadar önemlidir. Sabit fiyatlı piyasa sözleşmeleri, düzenli alışkanlıkları olan tüketiciler için avantajlı olabilir; endeksli tarifeler toptan satış piyasasıyla dalgalanır ve tüketimini yoğun olmayan saatlere kaydıranları ödüllendirir. Her iki seçeneği de gerçek tüketim verilerinizle karşılaştırmak, <strong>yılda 100-300 €</strong> fark yaratabilir.',
46
46
  },
47
47
  {
48
48
  type: 'title',
@@ -64,7 +64,7 @@ export const content: CategoryLocaleContent = {
64
64
  },
65
65
  {
66
66
  type: 'paragraph',
67
- html: 'Bir projektör "nereye sığarsa oraya" yerleştirilmez. Yansıtma oranı (throw ratio) yansıtma mesafesi ile görüntü genişliği arasındaki ilişki istediğiniz ekran boyutuna ulaşmak için üniteyi tam olarak ne kadar geriye yerleştirmeniz gerektiğini belirler. 50 cm\'lik bir yerleştirme hatası, görüntünün 20 cm daha küçük olması veya efektif çözünürlüğü azaltan bir dijital zoom kullanımına zorlanmak anlamına gelebilir.',
67
+ html: 'Bir projektör "nereye sığarsa oraya" yerleştirilmez. Yansıtma oranı (throw ratio): yansıtma mesafesi ile görüntü genişliği arasındaki ilişki: istediğiniz ekran boyutuna ulaşmak için üniteyi tam olarak ne kadar geriye yerleştirmeniz gerektiğini belirler. 50 cm\'lik bir yerleştirme hatası, görüntünün 20 cm daha küçük olması veya efektif çözünürlüğü azaltan bir dijital zoom kullanımına zorlanmak anlamına gelebilir.',
68
68
  },
69
69
  {
70
70
  type: 'paragraph',
@@ -77,12 +77,12 @@ export const content: CategoryLocaleContent = {
77
77
  },
78
78
  {
79
79
  type: 'paragraph',
80
- html: 'Modern ev, teknolojiyi her düzeyde entegre eder: Wi-Fi ağları, IoT cihazları, QR kod tabanlı erişim. QR kod oluşturucu, ev Wi-Fi ağınıza kısayollar, kartvizitler, akıllı cihaz URL\'leri veya misafirlerle ya da cihazlar arasında kolayca paylaşmak istediğiniz her türlü bilgiyi yazma gerektirmeden oluşturmanıza olanak tanır.',
80
+ html: 'Modern ev, teknolojiyi her düzeyde entegre eder: Wi-Fi ağları, IoT cihazları, QR kod tabanlı erişim. QR kod oluşturucu, ev Wi-Fi ağınıza kısayollar, kartvizitler, akıllı cihaz URL\'leri veya misafirlerle ya da cihazlar arasında kolayca paylaşmak istediğiniz her türlü bilgiyi: yazma gerektirmeden: oluşturmanıza olanak tanır.',
81
81
  },
82
82
  {
83
83
  type: 'list',
84
84
  items: [
85
- '<strong>Ölçülebilir tasarruf:</strong> Her araç somut rakamlar verir yılda kaç euro tasarruf edildiği, ayda kaç kWh üretildiği, optimal eğim açıları. Belirsiz tahminler yok.',
85
+ '<strong>Ölçülebilir tasarruf:</strong> Her araç somut rakamlar verir: yılda kaç euro tasarruf edildiği, ayda kaç kWh üretildiği, optimal eğim açıları. Belirsiz tahminler yok.',
86
86
  '<strong>Kurulum gerekmez:</strong> Doğrudan tarayıcıda çalışan çevrimiçi hesaplayıcılar, uygulama veya hesap gerekmez.',
87
87
  '<strong>Teknik standartlara dayalı:</strong> Psikrometrik formüller (ASHRAE), projeksiyon optiği, enleme göre güneş radyasyonu ve ilgili elektrik yönetmelikleri.',
88
88
  '<strong>Satın almadan önce faydalı:</strong> Satın alma kararlarını taahhüt altına girmeden önce doğrulayın. Güneş panelleri çatınızda kendisini amorti eder mi? LED\'ler gerçekte ne kadar tasarruf sağlar? Önce hesaplayın.',
@@ -12,7 +12,7 @@ export const content: CategoryLocaleContent = {
12
12
  },
13
13
  {
14
14
  type: 'paragraph',
15
- html: '大多数关于家居的决定都是凭直觉做出的:“我觉得这些太阳能板应该够了”,“换灯泡应该能省点钱”。事实是,五分钟的计算每年可以为您节省数百欧元,或者避开昂贵的返工。我们的工具基于<strong>真实的物理学</strong>:按纬度计算的太阳能辐射、实测瓦数消耗、湿空气焓湿学、投射光学等。',
15
+ html: '大多数关于家居的决定都是凭直觉做出的:"我觉得这些太阳能板应该够了","换灯泡应该能省点钱"。事实是,五分钟的计算每年可以为您节省数百欧元,或者避开昂贵的返工。我们的工具基于<strong>真实的物理学</strong>:按纬度计算的太阳能辐射、实测瓦数消耗、湿空气焓湿学、投射光学等。',
16
16
  },
17
17
  {
18
18
  type: 'paragraph',
@@ -25,7 +25,7 @@ export const content: CategoryLocaleContent = {
25
25
  },
26
26
  {
27
27
  type: 'paragraph',
28
- html: '家用光伏安装具有真实的投资回报率,这取决于三个变量:您所在位置的太阳辐射量、电池板的倾斜角度以及您的每小时耗电量。倾斜角比最佳角度低 10°,可能会导致<strong>年发电量损失 1520%</strong>。我们的太阳能计算器可为您提供精确的角度和月度发电估算。',
28
+ html: '家用光伏安装具有真实的投资回报率,这取决于三个变量:您所在位置的太阳辐射量、电池板的倾斜角度以及您的每小时耗电量。倾斜角比最佳角度低 10°,可能会导致<strong>年发电量损失 15-20%</strong>。我们的太阳能计算器可为您提供精确的角度和月度发电估算。',
29
29
  },
30
30
  {
31
31
  type: 'paragraph',
@@ -38,11 +38,11 @@ export const content: CategoryLocaleContent = {
38
38
  },
39
39
  {
40
40
  type: 'paragraph',
41
- html: '将卤素灯更换为 LED 不仅仅是“降低瓦数”。这意味着要明白一个 9 W 的 LED 在提供相同光通量(800 流明)的同时取代了 60 W 的卤素灯,从而实现<strong>能耗降低 85%</strong>。乘以年运行时间和每度电单价,节省的费用可以量化到分。我们的计算器正是为此设计的。',
41
+ html: '将卤素灯更换为 LED 不仅仅是"降低瓦数"。这意味着要明白一个 9 W 的 LED 在提供相同光通量(800 流明)的同时取代了 60 W 的卤素灯,从而实现<strong>能耗降低 85%</strong>。乘以年运行时间和每度电单价,节省的费用可以量化到分。我们的计算器正是为此设计的。',
42
42
  },
43
43
  {
44
44
  type: 'paragraph',
45
- html: '选择合适的电费方案同样重要。固定价格合同可能对生活习惯规律的消费者有利;指数挂钩型电价随批发市场波动,奖励那些能将用电转移到非高峰时段的用户。将两种方案与您的实际用电数据进行比较,<strong>每年可能产生 100300 欧元的差异</strong>。',
45
+ html: '选择合适的电费方案同样重要。固定价格合同可能对生活习惯规律的消费者有利;指数挂钩型电价随批发市场波动,奖励那些能将用电转移到非高峰时段的用户。将两种方案与您的实际用电数据进行比较,<strong>每年可能产生 100-300 欧元的差异</strong>。',
46
46
  },
47
47
  {
48
48
  type: 'title',
@@ -51,7 +51,7 @@ export const content: CategoryLocaleContent = {
51
51
  },
52
52
  {
53
53
  type: 'paragraph',
54
- html: '长期处于 70% 以上的相对湿度会导致热桥处产生冷凝水,引发霉菌滋生和结构劣变。露点温度——即空气中水蒸气开始凝结的温度值——是关键指标。如果您的内墙表面温度低于该点,无论您是否看得见,都会产生冷凝水。',
54
+ html: '长期处于 70% 以上的相对湿度会导致热桥处产生冷凝水,引发霉菌滋生和结构劣变。露点温度:: 即空气中水蒸气开始凝结的温度值:: 是关键指标。如果您的内墙表面温度低于该点,无论您是否看得见,都会产生冷凝水。',
55
55
  },
56
56
  {
57
57
  type: 'paragraph',
@@ -64,7 +64,7 @@ export const content: CategoryLocaleContent = {
64
64
  },
65
65
  {
66
66
  type: 'paragraph',
67
- html: '投影仪不能“随处安放”。投射比(投射距离与画面宽度的关系)决定了您需要将机器向后放置多远才能达到理想的屏幕尺寸。50 厘米的安装误差可能意味着图像小了 20 厘米,或者被迫使用降低有效分辨率的数字缩放。',
67
+ html: '投影仪不能"随处安放"。投射比(投射距离与画面宽度的关系)决定了您需要将机器向后放置多远才能达到理想的屏幕尺寸。50 厘米的安装误差可能意味着图像小了 20 厘米,或者被迫使用降低有效分辨率的数字缩放。',
68
68
  },
69
69
  {
70
70
  type: 'paragraph',
@@ -82,7 +82,7 @@ export const content: CategoryLocaleContent = {
82
82
  {
83
83
  type: 'list',
84
84
  items: [
85
- '<strong>可量化的节省:</strong> 每个工具都会返回具体的数字——每年的节省费用、每月的发电量、最佳倾斜角度。没有模糊的估算。',
85
+ '<strong>可量化的节省:</strong> 每个工具都会返回具体的数字:: 每年的节省费用、每月的发电量、最佳倾斜角度。没有模糊的估算。',
86
86
  '<strong>无需安装:</strong> 在浏览器中直接运行的在线计算器,无需下载 App 或注册账户。',
87
87
  '<strong>基于技术标准:</strong> 使用焓湿学公式 (ASHRAE)、投射光学、按纬度计算的太阳辐射以及相关的电气法规。',
88
88
  '<strong>购前验证:</strong> 在投入成本前验证决策。您家屋顶装太阳能板划算吗?LED 到底能省多少钱?先算一算。',
@@ -95,7 +95,7 @@ export const content: CategoryLocaleContent = {
95
95
  },
96
96
  {
97
97
  type: 'paragraph',
98
- html: '家居节能改进具有具体的投资回报率 (ROI)。一个配置合理的光伏系统在当前电价下 69 年内即可收回成本。普通家庭全面更换 LED 灯具在不到 2 年内即可回本。选对电费方案从第一个月起就能省钱。起点总是一样的:<strong>先测量,后行动</strong>。',
98
+ html: '家居节能改进具有具体的投资回报率 (ROI)。一个配置合理的光伏系统在当前电价下 6-9 年内即可收回成本。普通家庭全面更换 LED 灯具在不到 2 年内即可回本。选对电费方案从第一个月起就能省钱。起点总是一样的:<strong>先测量,后行动</strong>。',
99
99
  },
100
100
  {
101
101
  type: 'paragraph',
package/src/entries.ts CHANGED
@@ -12,6 +12,8 @@ export { solarCalculator } from './tool/solarCalculator/entry';
12
12
  export type { SolarCalculatorLocaleContent } from './tool/solarCalculator/entry';
13
13
  export { tariffComparator } from './tool/tariffComparator/entry';
14
14
  export type { TariffComparatorLocaleContent } from './tool/tariffComparator/entry';
15
+ export { wifiRangeSimulator } from './tool/wifiRangeSimulator/entry';
16
+ export type { WifiRangeSimulatorLocaleContent } from './tool/wifiRangeSimulator/entry';
15
17
  export { homeCategory } from './category';
16
18
  import { dewPointCalculator } from './tool/dewPointCalculator/entry';
17
19
  import { heatingComparator } from './tool/heatingComparator/entry';
@@ -20,4 +22,5 @@ import { projectorCalculator } from './tool/projectorCalculator/entry';
20
22
  import { qrGenerator } from './tool/qrGenerator/entry';
21
23
  import { solarCalculator } from './tool/solarCalculator/entry';
22
24
  import { tariffComparator } from './tool/tariffComparator/entry';
23
- export const ALL_ENTRIES = [dewPointCalculator, heatingComparator, ledSavingCalculator, projectorCalculator, qrGenerator, solarCalculator, tariffComparator];
25
+ import { wifiRangeSimulator } from './tool/wifiRangeSimulator/entry';
26
+ export const ALL_ENTRIES = [dewPointCalculator, heatingComparator, ledSavingCalculator, projectorCalculator, qrGenerator, solarCalculator, tariffComparator, wifiRangeSimulator];
@@ -34,18 +34,28 @@ export async function getStaticPaths() {
34
34
  ]),
35
35
  ) as Partial<Record<KnownLocale, string>>;
36
36
 
37
+ const firstLoader = entry.i18n.en ?? Object.values(entry.i18n)[0];
38
+ const englishSlug = firstLoader ? (await firstLoader()).slug : entry.id;
39
+
37
40
  for (const { locale, content } of localeContents) {
38
- const allToolsNav = await Promise.all(
39
- ALL_TOOLS.map(async ({ entry: navEntry }) => ({
40
- id: navEntry.id,
41
- title: (await navEntry.i18n[locale]!()).title,
42
- href: `/${locale}/${(await navEntry.i18n[locale]!()).slug}`,
43
- isActive: navEntry.id === entry.id,
44
- })),
45
- );
41
+ const allToolsNav = (
42
+ await Promise.all(
43
+ ALL_TOOLS.map(async ({ entry: navEntry }) => {
44
+ const loader = navEntry.i18n[locale] ?? navEntry.i18n.en;
45
+ if (!loader) return null;
46
+ const navContent = await loader();
47
+ return {
48
+ id: navEntry.id,
49
+ title: navContent.title,
50
+ href: `/${locale}/${navContent.slug}`,
51
+ isActive: navEntry.id === entry.id,
52
+ };
53
+ }),
54
+ )
55
+ ).filter(Boolean) as NavItem[];
46
56
  paths.push({
47
57
  params: { locale, slug: content.slug },
48
- props: { Component, locale, content, localeUrls, allToolsNav },
58
+ props: { Component, locale, content, localeUrls, allToolsNav, englishSlug },
49
59
  });
50
60
  }
51
61
  }
@@ -66,11 +76,16 @@ interface Props {
66
76
  content: ToolLocaleContent;
67
77
  localeUrls: Partial<Record<KnownLocale, string>>;
68
78
  allToolsNav: NavItem[];
79
+ englishSlug: string;
69
80
  }
70
81
 
71
- const { Component, locale, content, localeUrls, allToolsNav } = Astro.props;
82
+ const { Component, locale, content, localeUrls, allToolsNav, englishSlug } = Astro.props;
83
+
84
+ const cssFiles = import.meta.glob("../../tool/*/*.css", { query: "?raw", import: "default" });
85
+ const cssKey = Object.keys(cssFiles).find((k) => k.endsWith(`/${englishSlug}.css`));
86
+ const toolCss = cssKey ? await cssFiles[cssKey]() as string : "";
72
87
 
73
- const seoContent: UtilitySEOContent = { locale, sections: content.seo };
88
+ const seoContent: UtilitySEOContent = { locale, sections: content.seo ?? [] };
74
89
 
75
90
  const words = content.title.split(" ");
76
91
  const titleHighlight = words[0] || "";
@@ -89,8 +104,9 @@ const titleBase = words.slice(1).join(" ") || "";
89
104
  tools={allToolsNav}
90
105
  />
91
106
  <Fragment slot="head">
107
+ {toolCss ? <Fragment set:html={`<style is:inline>${toolCss}</style>`} /> : null}
92
108
  {
93
- content.schemas.map((schema: unknown) => (
109
+ ( content.schemas ?? []).map((schema: unknown) => (
94
110
  <script
95
111
  is:inline
96
112
  type="application/ld+json"
@@ -7,36 +7,18 @@ describe('Locale Completeness Validation', () => {
7
7
  describe(`Tool: ${tool.entry.id}`, () => {
8
8
  Object.keys(tool.entry.i18n).forEach((locale) => {
9
9
  describe(`Locale: ${locale}`, () => {
10
- it('faqTitle should be defined when faq items exist', async () => {
10
+ it('should load without errors', async () => {
11
11
  const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
12
12
  const content = (await loader?.()) as ToolLocaleContent;
13
-
14
- if (content.faq.length > 0) {
15
- expect(
16
- content.faqTitle,
17
- `Tool "${tool.entry.id}" locale "${locale}" has ${content.faq.length} FAQ items but is missing faqTitle`,
18
- ).toBeTruthy();
19
- }
20
- });
21
-
22
- it('bibliographyTitle should be defined when bibliography items exist', async () => {
23
- const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
24
- const content = (await loader?.()) as ToolLocaleContent;
25
-
26
- if (content.bibliography.length > 0) {
27
- expect(
28
- content.bibliographyTitle,
29
- `Tool "${tool.entry.id}" locale "${locale}" has ${content.bibliography.length} bibliography items but is missing bibliographyTitle`,
30
- ).toBeTruthy();
31
- }
13
+ expect(content).toBeDefined();
32
14
  });
33
15
  });
34
16
  });
35
17
  });
36
18
  });
37
19
 
38
- it('should have 6 tools registered', () => {
39
- expect(ALL_TOOLS.length).toBe(7);
20
+ it('should have 8 tools registered', () => {
21
+ expect(ALL_TOOLS.length).toBe(8);
40
22
  });
41
23
  });
42
24
 
@@ -0,0 +1,70 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+
5
+ function getFiles(dir: string): string[] {
6
+ const results: string[] = [];
7
+ if (!fs.existsSync(dir)) {
8
+ return results;
9
+ }
10
+ const list = fs.readdirSync(dir);
11
+ for (const file of list) {
12
+ const fullPath = path.join(dir, file);
13
+ const stat = fs.statSync(fullPath);
14
+ if (stat && stat.isDirectory()) {
15
+ if (file !== 'tests' && file !== 'node_modules' && file !== '.astro') {
16
+ results.push(...getFiles(fullPath));
17
+ }
18
+ } else {
19
+ results.push(fullPath);
20
+ }
21
+ }
22
+ return results;
23
+ }
24
+
25
+ function isContentFile(filePath: string): boolean {
26
+ return /\\i18n\\/.test(filePath) || filePath.endsWith('bibliography.ts');
27
+ }
28
+
29
+ const srcDir = path.join(process.cwd(), 'src');
30
+ const scriptsDir = path.join(process.cwd(), 'scripts');
31
+ const filesToTest = [
32
+ ...getFiles(srcDir).filter(isContentFile),
33
+ ...getFiles(scriptsDir).filter(isContentFile),
34
+ ];
35
+
36
+ const aiTypographyGarbage = [
37
+ '\u2013',
38
+ '\u2014',
39
+ '\u2026',
40
+ '\u201C',
41
+ '\u201D',
42
+ '\u2018',
43
+ '\u2019',
44
+ '\u00AB',
45
+ '\u00BB',
46
+ '\u200B',
47
+ '\u201E',
48
+ ];
49
+
50
+ describe('Typography Garbage Character Validation', () => {
51
+ filesToTest.forEach((filePath) => {
52
+ const relativePath = path.relative(process.cwd(), filePath);
53
+ it(`should not contain typography garbage characters in ${relativePath}`, () => {
54
+ const content = fs.readFileSync(filePath, 'utf-8');
55
+ const hasAiPatterns = aiTypographyGarbage.some(char => content.includes(char));
56
+ expect(hasAiPatterns).toBe(false);
57
+ });
58
+
59
+ it(`should not contain space before colon in ${relativePath}`, () => {
60
+ const content = fs.readFileSync(filePath, 'utf-8');
61
+ const spaceBeforeColon = / : /.test(content);
62
+ expect(spaceBeforeColon).toBe(false);
63
+ });
64
+
65
+ it(`should not contain double hyphen in ${relativePath}`, () => {
66
+ const content = fs.readFileSync(filePath, 'utf-8');
67
+ expect(content).not.toContain('--');
68
+ });
69
+ });
70
+ });
@@ -0,0 +1,56 @@
1
+ import type { ToolDefinition } from '../types';
2
+
3
+ export interface ToolExportValidationResult {
4
+ passed: boolean;
5
+ failures: string[];
6
+ }
7
+
8
+ function validateComponentType(
9
+ toolId: string,
10
+ componentName: string,
11
+ component: unknown,
12
+ failures: string[],
13
+ ): void {
14
+ if (typeof component !== 'function') {
15
+ failures.push(`${toolId}: ${componentName} is not a function (${typeof component})`);
16
+ }
17
+ }
18
+
19
+ async function validateComponentExecution(
20
+ toolId: string,
21
+ componentName: string,
22
+ fn: () => Promise<unknown>,
23
+ failures: string[],
24
+ ): Promise<void> {
25
+ try {
26
+ const result = await fn();
27
+ if (!result || typeof result !== 'object') {
28
+ failures.push(`${toolId}: ${componentName} import returned invalid result`);
29
+ }
30
+ } catch (error) {
31
+ failures.push(`${toolId}: ${componentName} execution error - ${error instanceof Error ? error.message : 'unknown'}`);
32
+ }
33
+ }
34
+
35
+ export async function validateToolExports(tools: ToolDefinition[]): Promise<ToolExportValidationResult> {
36
+ const failures: string[] = [];
37
+
38
+ for (const tool of tools) {
39
+ validateComponentType(tool.entry.id, 'Component', tool.Component, failures);
40
+ validateComponentType(tool.entry.id, 'SEOComponent', tool.SEOComponent, failures);
41
+ validateComponentType(tool.entry.id, 'BibliographyComponent', tool.BibliographyComponent, failures);
42
+
43
+ const componentFn = tool.Component as () => Promise<unknown>;
44
+ const seoFn = tool.SEOComponent as () => Promise<unknown>;
45
+ const bibFn = tool.BibliographyComponent as () => Promise<unknown>;
46
+
47
+ await validateComponentExecution(tool.entry.id, 'Component', componentFn, failures);
48
+ await validateComponentExecution(tool.entry.id, 'SEOComponent', seoFn, failures);
49
+ await validateComponentExecution(tool.entry.id, 'BibliographyComponent', bibFn, failures);
50
+ }
51
+
52
+ return {
53
+ passed: failures.length === 0,
54
+ failures,
55
+ };
56
+ }