@jjlmoya/utils-developer 1.14.0 → 1.16.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 (200) hide show
  1. package/package.json +1 -1
  2. package/src/category/i18n/fr.ts +1 -1
  3. package/src/category/i18n/ru.ts +1 -1
  4. package/src/category/index.ts +2 -1
  5. package/src/entries.ts +4 -1
  6. package/src/index.ts +2 -0
  7. package/src/layouts/PreviewLayout.astro +1 -0
  8. package/src/pages/[locale]/[slug].astro +29 -12
  9. package/src/tests/diacritics_density.test.ts +118 -0
  10. package/src/tests/inverted_punctuation.test.ts +113 -0
  11. package/src/tests/locale_completeness.test.ts +2 -3
  12. package/src/tests/no_en_dash.test.ts +73 -0
  13. package/src/tests/pagespeed_best_practices.test.ts +198 -0
  14. package/src/tests/script_density.test.ts +94 -0
  15. package/src/tests/shared-test-helpers.ts +56 -0
  16. package/src/tests/tool_exports.test.ts +34 -0
  17. package/src/tests/tool_validation.test.ts +2 -2
  18. package/src/tool/aspectRatio/component.astro +3 -1
  19. package/src/tool/aspectRatio/i18n/de.ts +1 -1
  20. package/src/tool/aspectRatio/i18n/fr.ts +1 -1
  21. package/src/tool/aspectRatio/i18n/pl.ts +2 -2
  22. package/src/tool/aspectRatio/i18n/ru.ts +4 -4
  23. package/src/tool/aspectRatio/i18n/zh.ts +1 -1
  24. package/src/tool/aspectRatio/seo.astro +2 -1
  25. package/src/tool/calculadoraTiempoDatos/i18n/de.ts +1 -1
  26. package/src/tool/calculadoraTiempoDatos/i18n/pl.ts +1 -1
  27. package/src/tool/calculadoraTiempoDatos/i18n/ru.ts +5 -5
  28. package/src/tool/calculadoraTiempoDatos/i18n/sv.ts +5 -5
  29. package/src/tool/calculadoraTiempoDatos/i18n/zh.ts +1 -1
  30. package/src/tool/calculadoraTiempoDatos/seo.astro +2 -1
  31. package/src/tool/colorConverter/component.astro +3 -3
  32. package/src/tool/colorConverter/i18n/de.ts +1 -1
  33. package/src/tool/colorConverter/i18n/ru.ts +2 -2
  34. package/src/tool/colorConverter/seo.astro +2 -1
  35. package/src/tool/conversorExcelCsvHtml/i18n/es.ts +1 -1
  36. package/src/tool/conversorExcelCsvHtml/i18n/pl.ts +1 -1
  37. package/src/tool/conversorExcelCsvHtml/i18n/ru.ts +2 -2
  38. package/src/tool/conversorExcelCsvHtml/i18n/zh.ts +2 -2
  39. package/src/tool/conversorExcelCsvHtml/seo.astro +2 -1
  40. package/src/tool/cronGenerator/i18n/de.ts +4 -4
  41. package/src/tool/cronGenerator/i18n/en.ts +1 -1
  42. package/src/tool/cronGenerator/i18n/es.ts +2 -2
  43. package/src/tool/cronGenerator/i18n/fr.ts +5 -5
  44. package/src/tool/cronGenerator/i18n/id.ts +1 -1
  45. package/src/tool/cronGenerator/i18n/nl.ts +1 -1
  46. package/src/tool/cronGenerator/i18n/pl.ts +8 -8
  47. package/src/tool/cronGenerator/i18n/pt.ts +1 -1
  48. package/src/tool/cronGenerator/i18n/ru.ts +9 -9
  49. package/src/tool/cronGenerator/i18n/sv.ts +1 -1
  50. package/src/tool/cronGenerator/i18n/zh.ts +3 -3
  51. package/src/tool/cronGenerator/seo.astro +2 -1
  52. package/src/tool/cssSpecificityCalculator/i18n/de.ts +1 -1
  53. package/src/tool/cssSpecificityCalculator/i18n/fr.ts +3 -3
  54. package/src/tool/cssSpecificityCalculator/i18n/pl.ts +2 -2
  55. package/src/tool/cssSpecificityCalculator/i18n/ru.ts +2 -2
  56. package/src/tool/cssSpecificityCalculator/seo.astro +2 -1
  57. package/src/tool/cssToInlineConverter/i18n/de.ts +6 -6
  58. package/src/tool/cssToInlineConverter/i18n/es.ts +1 -1
  59. package/src/tool/cssToInlineConverter/i18n/fr.ts +3 -3
  60. package/src/tool/cssToInlineConverter/seo.astro +2 -1
  61. package/src/tool/duplicateCssRemover/i18n/de.ts +7 -7
  62. package/src/tool/duplicateCssRemover/i18n/fr.ts +1 -1
  63. package/src/tool/duplicateCssRemover/i18n/id.ts +1 -1
  64. package/src/tool/duplicateCssRemover/i18n/nl.ts +1 -1
  65. package/src/tool/duplicateCssRemover/i18n/pl.ts +1 -1
  66. package/src/tool/duplicateCssRemover/i18n/pt.ts +1 -1
  67. package/src/tool/duplicateCssRemover/i18n/ru.ts +3 -3
  68. package/src/tool/duplicateCssRemover/i18n/sv.ts +1 -1
  69. package/src/tool/duplicateCssRemover/seo.astro +2 -1
  70. package/src/tool/generadorSecurityTxt/i18n/de.ts +5 -5
  71. package/src/tool/generadorSecurityTxt/i18n/ru.ts +2 -2
  72. package/src/tool/generadorSecurityTxt/seo.astro +2 -1
  73. package/src/tool/hashGenerator/i18n/ru.ts +5 -5
  74. package/src/tool/hashGenerator/i18n/zh.ts +2 -2
  75. package/src/tool/hashGenerator/seo.astro +2 -1
  76. package/src/tool/inspectorCertificadosSsl/i18n/de.ts +6 -6
  77. package/src/tool/inspectorCertificadosSsl/i18n/ru.ts +5 -5
  78. package/src/tool/inspectorCertificadosSsl/seo.astro +2 -1
  79. package/src/tool/jsonFormatter/i18n/de.ts +4 -4
  80. package/src/tool/jsonFormatter/i18n/en.ts +4 -4
  81. package/src/tool/jsonFormatter/i18n/es.ts +4 -4
  82. package/src/tool/jsonFormatter/i18n/fr.ts +4 -4
  83. package/src/tool/jsonFormatter/i18n/id.ts +4 -4
  84. package/src/tool/jsonFormatter/i18n/it.ts +4 -4
  85. package/src/tool/jsonFormatter/i18n/ja.ts +4 -4
  86. package/src/tool/jsonFormatter/i18n/ko.ts +4 -4
  87. package/src/tool/jsonFormatter/i18n/nl.ts +4 -4
  88. package/src/tool/jsonFormatter/i18n/pl.ts +4 -4
  89. package/src/tool/jsonFormatter/i18n/pt.ts +4 -4
  90. package/src/tool/jsonFormatter/i18n/ru.ts +5 -5
  91. package/src/tool/jsonFormatter/i18n/sv.ts +4 -4
  92. package/src/tool/jsonFormatter/i18n/tr.ts +4 -4
  93. package/src/tool/jsonFormatter/i18n/zh.ts +5 -5
  94. package/src/tool/jsonFormatter/seo.astro +2 -1
  95. package/src/tool/keycode/i18n/de.ts +7 -7
  96. package/src/tool/keycode/i18n/en.ts +5 -5
  97. package/src/tool/keycode/i18n/es.ts +5 -5
  98. package/src/tool/keycode/i18n/fr.ts +7 -7
  99. package/src/tool/keycode/i18n/id.ts +5 -5
  100. package/src/tool/keycode/i18n/it.ts +5 -5
  101. package/src/tool/keycode/i18n/ja.ts +5 -5
  102. package/src/tool/keycode/i18n/ko.ts +5 -5
  103. package/src/tool/keycode/i18n/nl.ts +5 -5
  104. package/src/tool/keycode/i18n/pl.ts +7 -7
  105. package/src/tool/keycode/i18n/pt.ts +5 -5
  106. package/src/tool/keycode/i18n/ru.ts +6 -6
  107. package/src/tool/keycode/i18n/sv.ts +5 -5
  108. package/src/tool/keycode/i18n/tr.ts +5 -5
  109. package/src/tool/keycode/i18n/zh.ts +5 -5
  110. package/src/tool/keycode/seo.astro +2 -1
  111. package/src/tool/llmCostCalculator/component.astro +1 -2
  112. package/src/tool/llmCostCalculator/i18n/de.ts +4 -4
  113. package/src/tool/llmCostCalculator/i18n/en.ts +3 -3
  114. package/src/tool/llmCostCalculator/i18n/fr.ts +3 -3
  115. package/src/tool/llmCostCalculator/i18n/id.ts +3 -3
  116. package/src/tool/llmCostCalculator/i18n/pt.ts +3 -3
  117. package/src/tool/llmCostCalculator/i18n/ru.ts +3 -3
  118. package/src/tool/llmCostCalculator/i18n/sv.ts +3 -3
  119. package/src/tool/llmCostCalculator/i18n/tr.ts +3 -3
  120. package/src/tool/llmCostCalculator/i18n/zh.ts +3 -3
  121. package/src/tool/llmCostCalculator/seo.astro +2 -1
  122. package/src/tool/mobileMockupGenerator/component.astro +4 -5
  123. package/src/tool/mobileMockupGenerator/i18n/es.ts +1 -1
  124. package/src/tool/mobileMockupGenerator/seo.astro +2 -1
  125. package/src/tool/musicalTypography/i18n/de.ts +1 -1
  126. package/src/tool/musicalTypography/i18n/fr.ts +1 -1
  127. package/src/tool/musicalTypography/i18n/id.ts +1 -1
  128. package/src/tool/musicalTypography/i18n/it.ts +1 -1
  129. package/src/tool/musicalTypography/i18n/ko.ts +1 -1
  130. package/src/tool/musicalTypography/i18n/ru.ts +3 -3
  131. package/src/tool/musicalTypography/seo.astro +2 -1
  132. package/src/tool/placeholderGenerator/component.astro +2 -2
  133. package/src/tool/placeholderGenerator/i18n/de.ts +4 -4
  134. package/src/tool/placeholderGenerator/i18n/ru.ts +1 -1
  135. package/src/tool/placeholderGenerator/seo.astro +2 -1
  136. package/src/tool/promptLibrary/i18n/de.ts +1 -1
  137. package/src/tool/promptLibrary/seo.astro +2 -1
  138. package/src/tool/readabilityCalculator/component.astro +4 -4
  139. package/src/tool/readabilityCalculator/i18n/de.ts +2 -2
  140. package/src/tool/readabilityCalculator/seo.astro +2 -1
  141. package/src/tool/readabilityCalculator/visual-readability-calculator-wcag-apca.css +87 -3
  142. package/src/tool/serpPixelSimulator/bibliography.astro +7 -0
  143. package/src/tool/serpPixelSimulator/bibliography.ts +16 -0
  144. package/src/tool/serpPixelSimulator/component.astro +84 -0
  145. package/src/tool/serpPixelSimulator/controller.ts +323 -0
  146. package/src/tool/serpPixelSimulator/entry.ts +30 -0
  147. package/src/tool/serpPixelSimulator/i18n/de.ts +214 -0
  148. package/src/tool/serpPixelSimulator/i18n/en.ts +213 -0
  149. package/src/tool/serpPixelSimulator/i18n/es.ts +214 -0
  150. package/src/tool/serpPixelSimulator/i18n/fr.ts +214 -0
  151. package/src/tool/serpPixelSimulator/i18n/id.ts +214 -0
  152. package/src/tool/serpPixelSimulator/i18n/it.ts +214 -0
  153. package/src/tool/serpPixelSimulator/i18n/ja.ts +214 -0
  154. package/src/tool/serpPixelSimulator/i18n/ko.ts +214 -0
  155. package/src/tool/serpPixelSimulator/i18n/nl.ts +214 -0
  156. package/src/tool/serpPixelSimulator/i18n/pl.ts +214 -0
  157. package/src/tool/serpPixelSimulator/i18n/pt.ts +214 -0
  158. package/src/tool/serpPixelSimulator/i18n/ru.ts +214 -0
  159. package/src/tool/serpPixelSimulator/i18n/sv.ts +214 -0
  160. package/src/tool/serpPixelSimulator/i18n/tr.ts +214 -0
  161. package/src/tool/serpPixelSimulator/i18n/zh.ts +214 -0
  162. package/src/tool/serpPixelSimulator/index.ts +12 -0
  163. package/src/tool/serpPixelSimulator/logic.ts +18 -0
  164. package/src/tool/serpPixelSimulator/seo.astro +12 -0
  165. package/src/tool/serpPixelSimulator/serp-pixel-simulator.css +335 -0
  166. package/src/tool/serpPixelSimulator/ui.ts +33 -0
  167. package/src/tool/svgSanitizer/i18n/de.ts +2 -2
  168. package/src/tool/svgSanitizer/i18n/id.ts +1 -1
  169. package/src/tool/svgSanitizer/i18n/pl.ts +1 -1
  170. package/src/tool/svgSanitizer/i18n/ru.ts +7 -7
  171. package/src/tool/svgSanitizer/i18n/sv.ts +3 -3
  172. package/src/tool/svgSanitizer/i18n/tr.ts +3 -3
  173. package/src/tool/svgSanitizer/i18n/zh.ts +3 -3
  174. package/src/tool/svgSanitizer/seo.astro +2 -1
  175. package/src/tool/svgToCss/i18n/de.ts +2 -2
  176. package/src/tool/svgToCss/i18n/es.ts +1 -1
  177. package/src/tool/svgToCss/i18n/fr.ts +1 -1
  178. package/src/tool/svgToCss/i18n/pl.ts +1 -1
  179. package/src/tool/svgToCss/i18n/ru.ts +2 -2
  180. package/src/tool/svgToCss/i18n/zh.ts +2 -2
  181. package/src/tool/svgToCss/seo.astro +2 -1
  182. package/src/tool/urlCleaner/component.astro +23 -5
  183. package/src/tool/urlCleaner/i18n/de.ts +3 -3
  184. package/src/tool/urlCleaner/i18n/es.ts +1 -1
  185. package/src/tool/urlCleaner/i18n/id.ts +1 -1
  186. package/src/tool/urlCleaner/i18n/nl.ts +1 -1
  187. package/src/tool/urlCleaner/seo.astro +2 -1
  188. package/src/tool/urlCleaner/url-tracking-cleaner.css +92 -2
  189. package/src/tool/urlEncoderDecoder/i18n/de.ts +5 -5
  190. package/src/tool/urlEncoderDecoder/i18n/fr.ts +2 -2
  191. package/src/tool/urlEncoderDecoder/i18n/pl.ts +5 -5
  192. package/src/tool/urlEncoderDecoder/i18n/ru.ts +8 -8
  193. package/src/tool/urlEncoderDecoder/i18n/sv.ts +5 -5
  194. package/src/tool/urlEncoderDecoder/i18n/zh.ts +5 -5
  195. package/src/tool/urlEncoderDecoder/seo.astro +2 -1
  196. package/src/tool/utmGenerator/i18n/de.ts +2 -2
  197. package/src/tool/utmGenerator/i18n/pl.ts +5 -5
  198. package/src/tool/utmGenerator/i18n/ru.ts +6 -6
  199. package/src/tool/utmGenerator/seo.astro +2 -1
  200. package/src/tools.ts +2 -2
@@ -59,7 +59,7 @@ const t = (ui ?? {}) as LlmCostCalculatorUI;
59
59
  step="100"
60
60
  value="1000"
61
61
  />
62
- <input class="llm-req-num" type="number" id="llm-requests-num" value="1000" min="1" />
62
+ <input class="llm-req-num" type="number" id="llm-requests-num" value="1000" min="1" aria-label={t.labelRequests} />
63
63
  </div>
64
64
  </div>
65
65
  </div>
@@ -232,4 +232,3 @@ const t = (ui ?? {}) as LlmCostCalculatorUI;
232
232
 
233
233
  init();
234
234
  </script>
235
-
@@ -16,12 +16,12 @@ const faqData = [
16
16
  {
17
17
  question: 'Was sind Tokens und wie hängen sie mit Wörtern zusammen?',
18
18
  answer:
19
- 'Ein Token ist die grundlegende Texteinheit, die ein Sprachmodell verarbeitet. Im Durchschnitt entspricht 1 Token etwa 0,75 Wörtern auf Englisch, also 1.000 Tokens ≈ 750 Wörter. Preise werden pro Million Tokens ($/1M) angegeben das ist die branchenübliche Einheit bei allen Anbietern.',
19
+ 'Ein Token ist die grundlegende Texteinheit, die ein Sprachmodell verarbeitet. Im Durchschnitt entspricht 1 Token etwa 0,75 Wörtern auf Englisch, also 1.000 Tokens ≈ 750 Wörter. Preise werden pro Million Tokens ($/1M) angegeben - das ist die branchenübliche Einheit bei allen Anbietern.',
20
20
  },
21
21
  {
22
22
  question: 'Warum sind Ausgabe Tokens teurer als Eingabe Tokens?',
23
23
  answer:
24
- 'Das Generieren von Text (Ausgabe) erfordert, dass das Modell jeden Token nacheinander berechnet das ist rechenintensiver als das Lesen der Eingabe. Die meisten Anbieter berechnen für Ausgabe Tokens das 3- bis 5-Fache des Preises für Eingabe Tokens.',
24
+ 'Das Generieren von Text (Ausgabe) erfordert, dass das Modell jeden Token nacheinander berechnet - das ist rechenintensiver als das Lesen der Eingabe. Die meisten Anbieter berechnen für Ausgabe Tokens das 3- bis 5-Fache des Preises für Eingabe Tokens.',
25
25
  },
26
26
  {
27
27
  question: 'Wie kann ich die Kosten meiner LLM-API senken?',
@@ -127,7 +127,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
127
127
  },
128
128
  {
129
129
  type: 'paragraph',
130
- html: 'APIs für große Sprachmodelle werden nach Token-Nutzung abgerechnet nicht nach Zeit oder Anfragen. Jeder API-Aufruf hat zwei Kostenkomponenten: die <strong>Eingabekosten</strong> (Verarbeitung deines Prompts) und die <strong>Ausgabekosten</strong> (Generierung der Antwort). Diesen Unterschied zu verstehen ist der Schlüssel zur genauen Schätzung deiner monatlichen Rechnung.',
130
+ html: 'APIs für große Sprachmodelle werden nach Token-Nutzung abgerechnet - nicht nach Zeit oder Anfragen. Jeder API-Aufruf hat zwei Kostenkomponenten: die <strong>Eingabekosten</strong> (Verarbeitung deines Prompts) und die <strong>Ausgabekosten</strong> (Generierung der Antwort). Diesen Unterschied zu verstehen ist der Schlüssel zur genauen Schätzung deiner monatlichen Rechnung.',
131
131
  },
132
132
  {
133
133
  type: 'title',
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
146
146
  {
147
147
  type: 'card',
148
148
  title: 'Ausgabe Tokens',
149
- html: '<p>Ausgabe Tokens werden sequenziell Token für Token erzeugt, was sie rechenintensiver macht. Die meisten Anbieter berechnen für Ausgabe Tokens <strong>das 3- bis 5-Fache</strong> des Eingabepreises. Eine Antwort mit 300 Wörtern erzeugt etwa 400 Ausgabe Tokens. Präzise Antworten zu halten ist eine der wirkungsvollsten Methoden, Kosten zu sparen.</p>',
149
+ html: '<p>Ausgabe Tokens werden sequenziell - Token für Token - erzeugt, was sie rechenintensiver macht. Die meisten Anbieter berechnen für Ausgabe Tokens <strong>das 3- bis 5-Fache</strong> des Eingabepreises. Eine Antwort mit 300 Wörtern erzeugt etwa 400 Ausgabe Tokens. Präzise Antworten zu halten ist eine der wirkungsvollsten Methoden, Kosten zu sparen.</p>',
150
150
  },
151
151
  {
152
152
  type: 'title',
@@ -21,7 +21,7 @@ const faqData = [
21
21
  {
22
22
  question: 'Why are output tokens more expensive than input tokens?',
23
23
  answer:
24
- 'Generating text (output) requires the model to compute each token sequentially, which is computationally more intensive than reading the input. Most providers charge 35x more for output tokens than input tokens.',
24
+ 'Generating text (output) requires the model to compute each token sequentially, which is computationally more intensive than reading the input. Most providers charge 3-5x more for output tokens than input tokens.',
25
25
  },
26
26
  {
27
27
  question: 'How can I reduce my LLM API costs?',
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
146
146
  {
147
147
  type: 'card',
148
148
  title: 'Output tokens',
149
- html: '<p>Output tokens are generated one by one in sequence, making them more computationally expensive. Most providers charge <strong>35× more</strong> for output tokens. A 300-word response generates roughly 400 output tokens. Keeping responses concise is one of the most effective cost-saving strategies.</p>',
149
+ html: '<p>Output tokens are generated one by one in sequence, making them more computationally expensive. Most providers charge <strong>3-5× more</strong> for output tokens. A 300-word response generates roughly 400 output tokens. Keeping responses concise is one of the most effective cost-saving strategies.</p>',
150
150
  },
151
151
  {
152
152
  type: 'title',
@@ -155,7 +155,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
155
155
  },
156
156
  {
157
157
  type: 'tip',
158
- html: 'Start with a capable mid-tier model like <code>GPT-4o mini</code> or <code>Gemini 1.5 Flash</code> and only upgrade if quality falls short. The cost difference between a small and large model can be 10100×.',
158
+ html: 'Start with a capable mid-tier model like <code>GPT-4o mini</code> or <code>Gemini 1.5 Flash</code> and only upgrade if quality falls short. The cost difference between a small and large model can be 10-100×.',
159
159
  },
160
160
  {
161
161
  type: 'paragraph',
@@ -11,7 +11,7 @@ const faqData = [
11
11
  {
12
12
  question: "Comment le coût d'une API LLM est-il calculé ?",
13
13
  answer:
14
- "Les APIs LLM facturent séparément les tokens d'entrée (le prompt) et les tokens de sortie (la réponse). Le coût total par requête est : (tokens entrée × prix entrée + tokens sortie × prix sortie) / 1 000 000. Multipliez par le nombre de requêtes pour obtenir le coût mensuel total.",
14
+ "Les APIs LLM facturent séparément les tokens d'entrée (le prompt) et les tokens de sortie (la réponse). Le coût total par requête est: (tokens entrée × prix entrée + tokens sortie × prix sortie) / 1 000 000. Multipliez par le nombre de requêtes pour obtenir le coût mensuel total.",
15
15
  },
16
16
  {
17
17
  question: 'Que sont les tokens et comment se rapportent-ils aux mots ?',
@@ -127,7 +127,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
127
127
  },
128
128
  {
129
129
  type: 'paragraph',
130
- html: "Les APIs de modèles de langage facturent en fonction de l'utilisation des tokens, et non du temps ou des requêtes. Chaque appel a deux coûts : le <strong>coût d'entrée</strong> (traitement de votre prompt) et le <strong>coût de sortie</strong> (génération de la réponse). Comprendre cette distinction est essentiel pour estimer avec précision votre facture mensuelle.",
130
+ html: "Les APIs de modèles de langage facturent en fonction de l'utilisation des tokens, et non du temps ou des requêtes. Chaque appel a deux coûts: le <strong>coût d'entrée</strong> (traitement de votre prompt) et le <strong>coût de sortie</strong> (génération de la réponse). Comprendre cette distinction est essentiel pour estimer avec précision votre facture mensuelle.",
131
131
  },
132
132
  {
133
133
  type: 'title',
@@ -141,7 +141,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
141
141
  {
142
142
  type: 'card',
143
143
  title: "Tokens d'entrée",
144
- html: "<p>Les tokens d'entrée représentent tout ce qui est envoyé <strong>au</strong> modèle : votre prompt système, l'historique de la conversation et le message de l'utilisateur. Ils sont moins chers car le modèle les traite en parallèle. Un prompt système typique de 200 mots génère environ 267 tokens d'entrée.</p>",
144
+ html: "<p>Les tokens d'entrée représentent tout ce qui est envoyé <strong>au</strong> modèle: votre prompt système, l'historique de la conversation et le message de l'utilisateur. Ils sont moins chers car le modèle les traite en parallèle. Un prompt système typique de 200 mots génère environ 267 tokens d'entrée.</p>",
145
145
  },
146
146
  {
147
147
  type: 'card',
@@ -21,7 +21,7 @@ const faqData = [
21
21
  {
22
22
  question: 'Mengapa token output lebih mahal daripada token input?',
23
23
  answer:
24
- 'Menghasilkan teks (output) mengharuskan model menghitung setiap token secara berurutan, yang secara komputasi lebih intensif daripada membaca input. Sebagian besar penyedia mengenakan biaya 35 kali lebih mahal untuk token output dibandingkan token input.',
24
+ 'Menghasilkan teks (output) mengharuskan model menghitung setiap token secara berurutan, yang secara komputasi lebih intensif daripada membaca input. Sebagian besar penyedia mengenakan biaya 3-5 kali lebih mahal untuk token output dibandingkan token input.',
25
25
  },
26
26
  {
27
27
  question: 'Bagaimana cara mengurangi biaya API LLM saya?',
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
146
146
  {
147
147
  type: 'card',
148
148
  title: 'Token output',
149
- html: '<p>Token output dihasilkan satu per satu secara berurutan, sehingga lebih intensif secara komputasi. Sebagian besar penyedia mengenakan biaya <strong>35× lebih mahal</strong> untuk token output. Respons 300 kata menghasilkan sekitar 400 token output. Menjaga respons tetap ringkas adalah salah satu strategi penghematan biaya yang paling efektif.</p>',
149
+ html: '<p>Token output dihasilkan satu per satu secara berurutan, sehingga lebih intensif secara komputasi. Sebagian besar penyedia mengenakan biaya <strong>3-5× lebih mahal</strong> untuk token output. Respons 300 kata menghasilkan sekitar 400 token output. Menjaga respons tetap ringkas adalah salah satu strategi penghematan biaya yang paling efektif.</p>',
150
150
  },
151
151
  {
152
152
  type: 'title',
@@ -155,7 +155,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
155
155
  },
156
156
  {
157
157
  type: 'tip',
158
- html: 'Mulailah dengan model kelas menengah yang mumpuni seperti <code>GPT-4o mini</code> atau <code>Gemini 1.5 Flash</code> dan naik ke model yang lebih besar hanya jika kualitasnya belum memadai. Perbedaan biaya antara model kecil dan besar bisa mencapai 10100×.',
158
+ html: 'Mulailah dengan model kelas menengah yang mumpuni seperti <code>GPT-4o mini</code> atau <code>Gemini 1.5 Flash</code> dan naik ke model yang lebih besar hanya jika kualitasnya belum memadai. Perbedaan biaya antara model kecil dan besar bisa mencapai 10-100×.',
159
159
  },
160
160
  {
161
161
  type: 'paragraph',
@@ -21,7 +21,7 @@ const faqData = [
21
21
  {
22
22
  question: 'Por que os tokens de saída são mais caros que os de entrada?',
23
23
  answer:
24
- 'Gerar texto (saída) requer que o modelo compute cada token sequencialmente, o que é computacionalmente mais intensivo do que ler a entrada. A maioria dos provedores cobra 35x mais para tokens de saída do que de entrada.',
24
+ 'Gerar texto (saída) requer que o modelo compute cada token sequencialmente, o que é computacionalmente mais intensivo do que ler a entrada. A maioria dos provedores cobra 3-5x mais para tokens de saída do que de entrada.',
25
25
  },
26
26
  {
27
27
  question: 'Como posso reduzir meus custos de API LLM?',
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
146
146
  {
147
147
  type: 'card',
148
148
  title: 'Tokens de saída',
149
- html: '<p>Os tokens de saída são gerados um por um em sequência, tornando-os computacionalmente mais caros. A maioria dos provedores cobra <strong>35× mais</strong> para tokens de saída. Uma resposta de 300 palavras gera aproximadamente 400 tokens de saída. Manter as respostas concisas é uma das estratégias mais eficazes de economia de custos.</p>',
149
+ html: '<p>Os tokens de saída são gerados um por um em sequência, tornando-os computacionalmente mais caros. A maioria dos provedores cobra <strong>3-5× mais</strong> para tokens de saída. Uma resposta de 300 palavras gera aproximadamente 400 tokens de saída. Manter as respostas concisas é uma das estratégias mais eficazes de economia de custos.</p>',
150
150
  },
151
151
  {
152
152
  type: 'title',
@@ -155,7 +155,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
155
155
  },
156
156
  {
157
157
  type: 'tip',
158
- html: 'Comece com um modelo de nível médio capaz como <code>GPT-4o mini</code> ou <code>Gemini 1.5 Flash</code> e atualize apenas se a qualidade for insuficiente. A diferença de custo entre um modelo pequeno e grande pode ser 10100×.',
158
+ html: 'Comece com um modelo de nível médio capaz como <code>GPT-4o mini</code> ou <code>Gemini 1.5 Flash</code> e atualize apenas se a qualidade for insuficiente. A diferença de custo entre um modelo pequeno e grande pode ser 10-100×.',
159
159
  },
160
160
  {
161
161
  type: 'paragraph',
@@ -21,7 +21,7 @@ const faqData = [
21
21
  {
22
22
  question: 'Почему выходные токены дороже входных?',
23
23
  answer:
24
- 'Генерирование текста (выход) требует, чтобы модель последовательно вычисляла каждый токен, что вычислительно более интенсивно, чем чтение входа. Большинство провайдеров взимают в 35 раз больше за выходные токены, чем за входные.',
24
+ 'Генерирование текста (выход) требует, чтобы модель последовательно вычисляла каждый токен, что вычислительно более интенсивно, чем чтение входа. Большинство провайдеров взимают в 3-5 раз больше за выходные токены, чем за входные.',
25
25
  },
26
26
  {
27
27
  question: 'Как я могу снизить свои расходы на API LLM?',
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
146
146
  {
147
147
  type: 'card',
148
148
  title: 'Выходные токены',
149
- html: '<p>Выходные токены генерируются один за другим последовательно, делая их вычислительно более дорогостоящими. Большинство провайдеров взимают <strong>35× больше</strong> за выходные токены. Ответ из 300 слов генерирует примерно 400 выходных токенов. Сохранение ответов краткими - одна из наиболее эффективных стратегий экономии затрат.</p>',
149
+ html: '<p>Выходные токены генерируются один за другим последовательно, делая их вычислительно более дорогостоящими. Большинство провайдеров взимают <strong>3-5× больше</strong> за выходные токены. Ответ из 300 слов генерирует примерно 400 выходных токенов. Сохранение ответов краткими - одна из наиболее эффективных стратегий экономии затрат.</p>',
150
150
  },
151
151
  {
152
152
  type: 'title',
@@ -155,7 +155,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
155
155
  },
156
156
  {
157
157
  type: 'tip',
158
- html: 'Начните с способной модели среднего уровня, такой как <code>GPT-4o mini</code> или <code>Gemini 1.5 Flash</code>, и обновляйте, только если качество недостаточно. Разница в стоимости между маленькой и большой моделью может быть 10100×.',
158
+ html: 'Начните с способной модели среднего уровня, такой как <code>GPT-4o mini</code> или <code>Gemini 1.5 Flash</code>, и обновляйте, только если качество недостаточно. Разница в стоимости между маленькой и большой моделью может быть 10-100×.',
159
159
  },
160
160
  {
161
161
  type: 'paragraph',
@@ -21,7 +21,7 @@ const faqData = [
21
21
  {
22
22
  question: 'Varför är utdatatoken dyrare än indatatoken?',
23
23
  answer:
24
- 'Att generera text (utdata) kräver att modellen beräknar varje token sekventiellt, vilket är mer beräkningsintensivt än att läsa indata. De flesta leverantörer tar ut 35 gånger mer för utdatatoken än indatatoken.',
24
+ 'Att generera text (utdata) kräver att modellen beräknar varje token sekventiellt, vilket är mer beräkningsintensivt än att läsa indata. De flesta leverantörer tar ut 3-5 gånger mer för utdatatoken än indatatoken.',
25
25
  },
26
26
  {
27
27
  question: 'Hur kan jag minska mina LLM API-kostnader?',
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
146
146
  {
147
147
  type: 'card',
148
148
  title: 'Utdatatoken',
149
- html: '<p>Utdatatoken genereras sekventiellt, en i taget, vilket gör dem beräkningsmässigt dyrare. De flesta leverantörer tar ut <strong>35× mer</strong> för utdatatoken. Ett svar på 300 ord genererar ungefär 400 utdatatoken. Att hålla svaren korta är en av de mest effektiva kostnadsbesparingsstrategi.</p>',
149
+ html: '<p>Utdatatoken genereras sekventiellt, en i taget, vilket gör dem beräkningsmässigt dyrare. De flesta leverantörer tar ut <strong>3-5× mer</strong> för utdatatoken. Ett svar på 300 ord genererar ungefär 400 utdatatoken. Att hålla svaren korta är en av de mest effektiva kostnadsbesparingsstrategi.</p>',
150
150
  },
151
151
  {
152
152
  type: 'title',
@@ -155,7 +155,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
155
155
  },
156
156
  {
157
157
  type: 'tip',
158
- html: 'Börja med en kapabel mellanniesemodell som <code>GPT-4o mini</code> eller <code>Gemini 1.5 Flash</code> och uppgradera bara om kvaliteten är otillräcklig. Skillnaden i kostnad mellan en liten och stor modell kan vara 10100×.',
158
+ html: 'Börja med en kapabel mellanniesemodell som <code>GPT-4o mini</code> eller <code>Gemini 1.5 Flash</code> och uppgradera bara om kvaliteten är otillräcklig. Skillnaden i kostnad mellan en liten och stor modell kan vara 10-100×.',
159
159
  },
160
160
  {
161
161
  type: 'paragraph',
@@ -21,7 +21,7 @@ const faqData = [
21
21
  {
22
22
  question: 'Çıkış token\'ları neden giriş token\'larından daha pahalıdır?',
23
23
  answer:
24
- 'Metin oluşturma (çıkış), modelin her token\'u sırayla hesaplamasını gerektirir ve bu, girişi okumaktan hesaplamalar açısından daha yoğundur. Çoğu sağlayıcı çıkış token\'ları için giriş token\'larından 35 kat daha fazla ücret alır.',
24
+ 'Metin oluşturma (çıkış), modelin her token\'u sırayla hesaplamasını gerektirir ve bu, girişi okumaktan hesaplamalar açısından daha yoğundur. Çoğu sağlayıcı çıkış token\'ları için giriş token\'larından 3-5 kat daha fazla ücret alır.',
25
25
  },
26
26
  {
27
27
  question: 'LLM API maliyetlerimi nasıl azaltabilirim?',
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
146
146
  {
147
147
  type: 'card',
148
148
  title: 'Çıkış token\'ları',
149
- html: '<p>Çıkış token\'ları sırayla, teker teker oluşturulur ve bu onları hesaplamalar açısından daha pahalı hale getirir. Çoğu sağlayıcı çıkış token\'ları için <strong>35 kat daha fazla</strong> ücret alır. 300 sözcüklük bir yanıt yaklaşık 400 çıkış token\'ı üretir. Yanıtları kısa tutmak en etkili maliyet tasarrufu stratejilerinden biridir.</p>',
149
+ html: '<p>Çıkış token\'ları sırayla, teker teker oluşturulur ve bu onları hesaplamalar açısından daha pahalı hale getirir. Çoğu sağlayıcı çıkış token\'ları için <strong>3-5 kat daha fazla</strong> ücret alır. 300 sözcüklük bir yanıt yaklaşık 400 çıkış token\'ı üretir. Yanıtları kısa tutmak en etkili maliyet tasarrufu stratejilerinden biridir.</p>',
150
150
  },
151
151
  {
152
152
  type: 'title',
@@ -155,7 +155,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
155
155
  },
156
156
  {
157
157
  type: 'tip',
158
- html: '<code>GPT-4o mini</code> veya <code>Gemini 1.5 Flash</code> gibi yetenekli bir orta katman modeliyle başlayın ve yalnızca kalite yetersizse yükseltin. Küçük ve büyük bir model arasındaki maliyet farkı 10100× olabilir.',
158
+ html: '<code>GPT-4o mini</code> veya <code>Gemini 1.5 Flash</code> gibi yetenekli bir orta katman modeliyle başlayın ve yalnızca kalite yetersizse yükseltin. Küçük ve büyük bir model arasındaki maliyet farkı 10-100× olabilir.',
159
159
  },
160
160
  {
161
161
  type: 'paragraph',
@@ -21,7 +21,7 @@ const faqData = [
21
21
  {
22
22
  question: '为什么输出代币比输入代币更昂贵?',
23
23
  answer:
24
- '生成文本(输出)需要模型依次计算每个代币,这在计算上比读取输入更密集。大多数提供商对输出代币的收费是输入代币的 35 倍。',
24
+ '生成文本(输出)需要模型依次计算每个代币,这在计算上比读取输入更密集。大多数提供商对输出代币的收费是输入代币的 3-5 倍。',
25
25
  },
26
26
  {
27
27
  question: '如何降低我的 LLM API 成本?',
@@ -146,7 +146,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
146
146
  {
147
147
  type: 'card',
148
148
  title: '输出代币',
149
- html: '<p>输出代币按顺序逐个生成,使其在计算上更昂贵。大多数提供商对输出代币的收费<strong>多出 35 倍</strong>。一个 300 字的响应会生成大约 400 个输出代币。保持响应简洁是最有效的成本节省策略之一。</p>',
149
+ html: '<p>输出代币按顺序逐个生成,使其在计算上更昂贵。大多数提供商对输出代币的收费<strong>多出 3-5 倍</strong>。一个 300 字的响应会生成大约 400 个输出代币。保持响应简洁是最有效的成本节省策略之一。</p>',
150
150
  },
151
151
  {
152
152
  type: 'title',
@@ -155,7 +155,7 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
155
155
  },
156
156
  {
157
157
  type: 'tip',
158
- html: '从有能力的中等层级模型开始,例如 <code>GPT-4o mini</code> 或 <code>Gemini 1.5 Flash</code>,仅在质量不足时升级。小型和大型模型之间的成本差异可能是 10100×。',
158
+ html: '从有能力的中等层级模型开始,例如 <code>GPT-4o mini</code> 或 <code>Gemini 1.5 Flash</code>,仅在质量不足时升级。小型和大型模型之间的成本差异可能是 10-100×。',
159
159
  },
160
160
  {
161
161
  type: 'paragraph',
@@ -9,6 +9,7 @@ interface Props {
9
9
 
10
10
  const { locale = 'es' } = Astro.props;
11
11
  const content = await llmCostCalculator.i18n[locale]?.();
12
+ if (!content) return null;
12
13
  ---
13
14
 
14
- {content && <SEORenderer content={{ locale, sections: content.seo }} />}
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -90,16 +90,16 @@ const t = (ui ?? {}) as MobileMockupGeneratorUI;
90
90
  </div>
91
91
  <div id="mmg-presets" class="mmg-presets-row"></div>
92
92
  <div class="mmg-gradient-inputs">
93
- <input type="color" id="mmg-grad-start" value="#6366f1" class="mmg-color-picker" />
93
+ <input type="color" id="mmg-grad-start" value="#6366f1" class="mmg-color-picker" aria-label={t.labelBackground} />
94
94
  <Icon name="mdi:arrow-right" class="mmg-arrow-icon" />
95
- <input type="color" id="mmg-grad-end" value="#a855f7" class="mmg-color-picker" />
95
+ <input type="color" id="mmg-grad-end" value="#a855f7" class="mmg-color-picker" aria-label={t.labelBackground} />
96
96
  </div>
97
97
  <div class="mmg-angle-section">
98
98
  <div class="mmg-angle-row">
99
99
  <span>{t.labelAngle}</span>
100
100
  <span id="mmg-angle-val">135&deg;</span>
101
101
  </div>
102
- <input type="range" id="mmg-grad-angle" min="0" max="360" value="135" class="mmg-range" />
102
+ <input type="range" id="mmg-grad-angle" min="0" max="360" value="135" class="mmg-range" aria-label={t.labelAngle} />
103
103
  </div>
104
104
  </div>
105
105
 
@@ -111,7 +111,7 @@ const t = (ui ?? {}) as MobileMockupGeneratorUI;
111
111
  </button>
112
112
  </div>
113
113
  <div class="mmg-safe-color-row">
114
- <input type="color" id="mmg-safe-color" value="#000000" class="mmg-color-picker-sm" />
114
+ <input type="color" id="mmg-safe-color" value="#000000" class="mmg-color-picker-sm" aria-label={t.labelSafeAreaColor} />
115
115
  <span class="mmg-safe-color-label">{t.labelSafeAreaColor}</span>
116
116
  </div>
117
117
  </div>
@@ -135,4 +135,3 @@ const t = (ui ?? {}) as MobileMockupGeneratorUI;
135
135
  import { App } from './app';
136
136
  new App();
137
137
  </script>
138
-
@@ -91,7 +91,7 @@ const ui: MobileMockupGeneratorUI = {
91
91
  presetImageRight: 'Imagen Der.',
92
92
  confirmClear: '¿Estás seguro de eliminar todos los mockups?',
93
93
  processingExport: 'Procesando...',
94
- exportDone: 'Listo!',
94
+ exportDone: '¡Listo!',
95
95
  };
96
96
 
97
97
  export const content: ToolLocaleContent<MobileMockupGeneratorUI> = {
@@ -9,6 +9,7 @@ interface Props {
9
9
 
10
10
  const { locale = 'es' } = Astro.props;
11
11
  const content = await mobileMockupGenerator.i18n[locale]?.();
12
+ if (!content) return null;
12
13
  ---
13
14
 
14
- {content && <SEORenderer content={{ locale, sections: content.seo }} />}
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -160,7 +160,7 @@ export const content: ToolLocaleContent<MusicalTypographyUI> = {
160
160
  {
161
161
  type: 'card',
162
162
  title: 'Warum "Musikalisch"',
163
- html: '<p>Die Pythagoreer entdeckten, dass das Teilen einer Saite in einfache Proportionen (1:2, 2:3, 3:4) Konsonanz erzeugt. Diese Intervalle Oktave, reine Quinte und reine Quarte sind genau die typografischen Ratios. Du komponierst visuelle Musik.</p>',
163
+ html: '<p>Die Pythagoreer entdeckten, dass das Teilen einer Saite in einfache Proportionen (1:2, 2:3, 3:4) Konsonanz erzeugt. Diese Intervalle - Oktave, reine Quinte und reine Quarte - sind genau die typografischen Ratios. Du komponierst visuelle Musik.</p>',
164
164
  },
165
165
  {
166
166
  type: 'title',
@@ -155,7 +155,7 @@ export const content: ToolLocaleContent<MusicalTypographyUI> = {
155
155
  {
156
156
  type: 'card',
157
157
  title: 'La formule',
158
- html: '<p>La progression est simple : <code>Taille = Base × Ratio<sup>n</sup></code>. L\'étape 0 est votre texte de base. L\'étape 1 est un petit sous-titre. L\'étape 4 ou 5 pourrait être votre H1 principal. La même constante multiplicative garantit que toutes les relations sont cohérentes.</p>',
158
+ html: '<p>La progression est simple: <code>Taille = Base × Ratio<sup>n</sup></code>. L\'étape 0 est votre texte de base. L\'étape 1 est un petit sous-titre. L\'étape 4 ou 5 pourrait être votre H1 principal. La même constante multiplicative garantit que toutes les relations sont cohérentes.</p>',
159
159
  },
160
160
  {
161
161
  type: 'card',
@@ -160,7 +160,7 @@ export const content: ToolLocaleContent<MusicalTypographyUI> = {
160
160
  {
161
161
  type: 'card',
162
162
  title: 'Mengapa "Musikal"',
163
- html: '<p>Kaum Pythagoras menemukan bahwa membagi senar dalam proporsi sederhana (1:2, 2:3, 3:4) menghasilkan bunyi yang konsonan. Interval-interval ini oktaf, kuint sempurna, dan kuart sempurna adalah persis rasio tipografi yang digunakan. Anda sedang menggubah musik visual.</p>',
163
+ html: '<p>Kaum Pythagoras menemukan bahwa membagi senar dalam proporsi sederhana (1:2, 2:3, 3:4) menghasilkan bunyi yang konsonan. Interval-interval ini - oktaf, kuint sempurna, dan kuart sempurna - adalah persis rasio tipografi yang digunakan. Anda sedang menggubah musik visual.</p>',
164
164
  },
165
165
  {
166
166
  type: 'title',
@@ -160,7 +160,7 @@ export const content: ToolLocaleContent<MusicalTypographyUI> = {
160
160
  {
161
161
  type: 'card',
162
162
  title: 'Perché "Musicale"',
163
- html: "<p>I pitagorici scoprirono che dividere una corda in proporzioni semplici (1:2, 2:3, 3:4) produceva suoni consonanti. Questi intervalli ottava, quinta giusta e quarta giusta sono esattamente i rapporti tipografici. Stai componendo musica visiva.</p>",
163
+ html: "<p>I pitagorici scoprirono che dividere una corda in proporzioni semplici (1:2, 2:3, 3:4) produceva suoni consonanti. Questi intervalli - ottava, quinta giusta e quarta giusta - sono esattamente i rapporti tipografici. Stai componendo musica visiva.</p>",
164
164
  },
165
165
  {
166
166
  type: 'title',
@@ -160,7 +160,7 @@ export const content: ToolLocaleContent<MusicalTypographyUI> = {
160
160
  {
161
161
  type: 'card',
162
162
  title: '왜 "음악적"인가',
163
- html: '<p>피타고라스학파는 현을 단순한 비율(1:2, 2:3, 3:4)로 나누면 협화음이 생긴다는 것을 발견했습니다. 옥타브, 완전5도, 완전4도 이 음정들이 바로 타이포그래피 비율과 정확히 일치합니다. 당신은 시각적 음악을 작곡하고 있는 것입니다.</p>',
163
+ html: '<p>피타고라스학파는 현을 단순한 비율(1:2, 2:3, 3:4)로 나누면 협화음이 생긴다는 것을 발견했습니다. 옥타브, 완전5도, 완전4도 - 이 음정들이 바로 타이포그래피 비율과 정확히 일치합니다. 당신은 시각적 음악을 작곡하고 있는 것입니다.</p>',
164
164
  },
165
165
  {
166
166
  type: 'title',
@@ -8,7 +8,7 @@ const description = 'Бесплатный онлайн-инструмент дл
8
8
 
9
9
  const faqData = [
10
10
  { question: 'Что такое типографическая модульная шкала?', answer: 'Это метод определения размеров шрифтов на основе постоянного математического соотношения. Подобно музыке, где ноты имеют гармонические отношения, модульная шкала создаёт сбалансированную и предсказуемую визуальную иерархию.' },
11
- { question: 'Почему использовать музыкальные интервалы для дизайна?', answer: 'Музыкальные интервалы это пропорции, которые человеческий мозг воспринимает как гармоничные. Применение их к размерам текста создаёт визуальную структуру, которая ощущается правильной и профессиональной, а не случайно выбранной.' },
11
+ { question: 'Почему использовать музыкальные интервалы для дизайна?', answer: 'Музыкальные интервалы - это пропорции, которые человеческий мозг воспринимает как гармоничные. Применение их к размерам текста создаёт визуальную структуру, которая ощущается правильной и профессиональной, а не случайно выбранной.' },
12
12
  { question: 'Что такое Золотое Сечение в типографии?', answer: 'Это пропорция 1.618, известная как Золотое Сечение. Она создаёт очень драматичные и элегантные шкалы, где каждый шаг иерархии растёт экспоненциально. Идеально для портфолио или сайтов, ориентированных на искусство.' },
13
13
  { question: 'Как я могу применить шкалу в своём файле CSS?', answer: 'Инструмент генерирует CSS-переменные (токены) в формате :root { --step-N: Xrem; }. Скопируйте их в свой основной CSS-файл и используйте с var(--step-N), чтобы сохранить типографическую согласованность на всём сайте.' },
14
14
  ];
@@ -38,8 +38,8 @@ export const content: ToolLocaleContent<MusicalTypographyUI> = {
38
38
  { type: 'paragraph', html: '<strong>Музыкальная Типографическая Шкала</strong> применяет математику музыкальных интервалов к типографическому дизайну. Подобно тому, как музыкальная композиция управляется точными пропорциями, хороший дизайн выигрывает от математической структуры, которая связывает все размеры вместе.' },
39
39
  { type: 'title', text: 'Как работает модульная шкала', level: 3 },
40
40
  { type: 'grid', columns: 2 },
41
- { type: 'card', title: 'Формула', html: '<p>Прогрессия простая: <code>Size = Base × Ratio<sup>n</sup></code>. Шаг 0 это ваш базовый текст. Шаг 1 маленький подзаголовок. Шаг 4 или 5 может быть вашим главным H1. Одна и та же постоянная умножения (соотношение) гарантирует, что все отношения согласованы.</p>' },
42
- { type: 'card', title: 'Почему "Музыкальная"', html: '<p>Пифагорейцы открыли, что деление струны на простые пропорции (1:2, 2:3, 3:4) производит созвучные звуки. Эти интервалы, октава, чистая квинта и чистая кварта, это ровно типографические соотношения. Вы сочиняете визуальную музыку.</p>' },
41
+ { type: 'card', title: 'Формула', html: '<p>Прогрессия простая: <code>Size = Base × Ratio<sup>n</sup></code>. Шаг 0 - это ваш базовый текст. Шаг 1 - маленький подзаголовок. Шаг 4 или 5 может быть вашим главным H1. Одна и та же постоянная умножения (соотношение) гарантирует, что все отношения согласованы.</p>' },
42
+ { type: 'card', title: 'Почему "Музыкальная"', html: '<p>Пифагорейцы открыли, что деление струны на простые пропорции (1:2, 2:3, 3:4) производит созвучные звуки. Эти интервалы, октава, чистая квинта и чистая кварта, - это ровно типографические соотношения. Вы сочиняете визуальную музыку.</p>' },
43
43
  { type: 'title', text: 'Выбор правильного соотношения', level: 3 },
44
44
  { type: 'tip', html: 'Для плотных интерфейсов (приборные панели, таблицы) используйте малые соотношения, такие как <code>1.125</code> или <code>1.2</code>. Для редакционных или портфельных сайтов используйте более выразительные соотношения, такие как <code>1.5</code> или <code>1.618</code>.' },
45
45
  { type: 'paragraph', html: 'Не ограничивайте шкалу только <code>font-size</code>. Те же CSS-переменные работают для <code>margin</code>, <code>padding</code> и <code>gap</code>. Когда белое пространство следует той же математической прогрессии, что и текст, дизайн достигает уровня связности, который все ощущают, но мало кто может объяснить.' },
@@ -9,6 +9,7 @@ interface Props {
9
9
 
10
10
  const { locale = 'es' } = Astro.props;
11
11
  const content = await musicalTypography.i18n[locale]?.();
12
+ if (!content) return null;
12
13
  ---
13
14
 
14
- {content && <SEORenderer content={{ locale, sections: content.seo }} />}
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -43,14 +43,14 @@ const t = (ui ?? {}) as PlaceholderGeneratorUI;
43
43
  <label class="pg-label" for="p-bg-color">{t.labelBgColor}</label>
44
44
  <div class="pg-color-wrapper">
45
45
  <input type="color" id="p-bg-color" value="#e2e8f0" />
46
- <input class="pg-color-text" type="text" id="p-bg-text" value="#e2e8f0" maxlength="7" />
46
+ <input class="pg-color-text" type="text" id="p-bg-text" value="#e2e8f0" maxlength="7" aria-label={t.labelBgColor} />
47
47
  </div>
48
48
  </div>
49
49
  <div class="pg-control-group">
50
50
  <label class="pg-label" for="p-text-color">{t.labelTextColor}</label>
51
51
  <div class="pg-color-wrapper">
52
52
  <input type="color" id="p-text-color" value="#64748b" />
53
- <input class="pg-color-text" type="text" id="p-text-text" value="#64748b" maxlength="7" />
53
+ <input class="pg-color-text" type="text" id="p-text-text" value="#64748b" maxlength="7" aria-label={t.labelTextColor} />
54
54
  </div>
55
55
  </div>
56
56
  </div>
@@ -16,7 +16,7 @@ const faqData = [
16
16
  {
17
17
  question: 'Kann ich im Generator jede beliebige Auflösung verwenden?',
18
18
  answer:
19
- 'Ja, Sie können beliebige numerische Werte für Breite und Höhe eingeben. Der Generator erstellt eine Arbeitsfläche mit exakt den angeforderten Abmessungen ideal für präzise Raster oder spezifische Werbeformate.',
19
+ 'Ja, Sie können beliebige numerische Werte für Breite und Höhe eingeben. Der Generator erstellt eine Arbeitsfläche mit exakt den angeforderten Abmessungen - ideal für präzise Raster oder spezifische Werbeformate.',
20
20
  },
21
21
  {
22
22
  question: 'In welchem Format werden die Bilder heruntergeladen?',
@@ -45,7 +45,7 @@ const howToData = [
45
45
  },
46
46
  {
47
47
  name: 'Bild herunterladen',
48
- text: 'Klicken Sie auf die Schaltfläche Herunterladen", um das erstellte Platzhalterbild direkt auf Ihrem Gerät zu speichern.',
48
+ text: 'Klicken Sie auf die Schaltfläche "Herunterladen", um das erstellte Platzhalterbild direkt auf Ihrem Gerät zu speichern.',
49
49
  },
50
50
  ];
51
51
 
@@ -159,7 +159,7 @@ export const content: ToolLocaleContent<PlaceholderGeneratorUI> = {
159
159
  type: 'list',
160
160
  items: [
161
161
  '<strong>Pixel-genaue Auflösung:</strong> Der native HTML5 Canvas stellt sicher, dass die exportierte Arbeitsfläche arithmetisch exakt den vom Nutzer angegebenen Koordinaten entspricht.',
162
- '<strong>Typografisches Autoscaling:</strong> Im automatischen Modus berechnet die Schriftgröße die Umfangsfläche und Zeichenanzahl, um den Text elegant einzupassen ohne unerwünschte <em>Overflows</em>.',
162
+ '<strong>Typografisches Autoscaling:</strong> Im automatischen Modus berechnet die Schriftgröße die Umfangsfläche und Zeichenanzahl, um den Text elegant einzupassen - ohne unerwünschte <em>Overflows</em>.',
163
163
  '<strong>Hexadezimale Synchronisation:</strong> Bidirektionale Zustandskontrolle zwischen nativen HTML-Farbwählern und Texteingaben sorgt für präzise Kontraste, die Ihrer Figma- oder Penpot-Palette entsprechen.',
164
164
  ],
165
165
  },
@@ -170,7 +170,7 @@ export const content: ToolLocaleContent<PlaceholderGeneratorUI> = {
170
170
  },
171
171
  {
172
172
  type: 'paragraph',
173
- html: 'Kein monolithisches Projekt und kein Micro-Frontend kommt ohne Grundlagenarbeit aus erst recht nicht bei anspruchsvollen Kunden oder Product Managern mit klarer Vision. Wer grafische Iterationen zügig durchführen kann, ohne fertige <em>Assets</em> mitschleppen zu müssen, hat einen klaren Vorteil. Dieser Generator greift direkt auf die moderne JS-API <code>toDataURL()</code> auf Ihrer lokalen Maschine zurück und liefert ein professionelles Ergebnis ohne fragwürdige Zwischenverarbeitung.',
173
+ html: 'Kein monolithisches Projekt und kein Micro-Frontend kommt ohne Grundlagenarbeit aus - erst recht nicht bei anspruchsvollen Kunden oder Product Managern mit klarer Vision. Wer grafische Iterationen zügig durchführen kann, ohne fertige <em>Assets</em> mitschleppen zu müssen, hat einen klaren Vorteil. Dieser Generator greift direkt auf die moderne JS-API <code>toDataURL()</code> auf Ihrer lokalen Maschine zurück und liefert ein professionelles Ergebnis ohne fragwürdige Zwischenverarbeitung.',
174
174
  },
175
175
  ],
176
176
  };
@@ -11,7 +11,7 @@ const faqData = [
11
11
  {
12
12
  question: 'Что такое плейсхолдер-изображение?',
13
13
  answer:
14
- 'Плейсхолдер или заполняющее изображение это временный графический элемент, используемый в веб-дизайне и макете для зарезервирования пространства, где будет размещено окончательное изображение. Они помогают визуализировать структуру страницы до появления финального контента.',
14
+ 'Плейсхолдер или заполняющее изображение - это временный графический элемент, используемый в веб-дизайне и макете для зарезервирования пространства, где будет размещено окончательное изображение. Они помогают визуализировать структуру страницы до появления финального контента.',
15
15
  },
16
16
  {
17
17
  question: 'Могу ли я использовать любое разрешение в генераторе?',
@@ -9,6 +9,7 @@ interface Props {
9
9
 
10
10
  const { locale = 'es' } = Astro.props;
11
11
  const content = await placeholderGenerator.i18n[locale]?.();
12
+ if (!content) return null;
12
13
  ---
13
14
 
14
- {content && <SEORenderer content={{ locale, sections: content.seo }} />}
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -112,7 +112,7 @@ export const content: ToolLocaleContent<PromptLibraryUI> = {
112
112
  type: 'list',
113
113
  items: [
114
114
  '<strong>Sofortsuche:</strong> Finde jene spezifische Anweisung, die du vor Monaten verwendet hast, mit einer einfachen Textsuche.',
115
- '<strong>Tag-Klassifizierung:</strong> Verschlagworte deine Prompts mit Marketing", Programmierung" oder Copywriting", um schnell zu filtern.',
115
+ '<strong>Tag-Klassifizierung:</strong> Verschlagworte deine Prompts mit "Marketing", "Programmierung" oder "Copywriting", um schnell zu filtern.',
116
116
  '<strong>Ein-Klick-Kopieren:</strong> Den vollständigen Text mit einem einzigen Klick in die Zwischenablage kopieren.',
117
117
  '<strong>Vollständige Privatsphäre:</strong> Alle deine Daten werden lokal im Browser über localStorage gespeichert.',
118
118
  ],
@@ -9,6 +9,7 @@ interface Props {
9
9
 
10
10
  const { locale = 'es' } = Astro.props;
11
11
  const content = await promptLibrary.i18n[locale]?.();
12
+ if (!content) return null;
12
13
  ---
13
14
 
14
- {content && <SEORenderer content={{ locale, sections: content.seo }} />}
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -18,14 +18,14 @@ const t = (ui ?? {}) as ReadabilityCalculatorUI;
18
18
  <div class="rc-input-wrapper">
19
19
  <label class="rc-label-mini">{t.labelText}</label>
20
20
  <div class="rc-color-input-container">
21
- <input type="color" id="rc-text-color" class="rc-color-picker" value="#1e293b" />
21
+ <input type="color" id="rc-text-color" class="rc-color-picker" value="#1e293b" aria-label={t.labelText} />
22
22
  <span id="rc-text-hex" class="rc-hex-text">#1E293B</span>
23
23
  </div>
24
24
  </div>
25
25
  <div class="rc-input-wrapper">
26
26
  <label class="rc-label-mini">{t.labelBg}</label>
27
27
  <div class="rc-color-input-container">
28
- <input type="color" id="rc-bg-color" class="rc-color-picker" value="#ffffff" />
28
+ <input type="color" id="rc-bg-color" class="rc-color-picker" value="#ffffff" aria-label={t.labelBg} />
29
29
  <span id="rc-bg-hex" class="rc-hex-text">#FFFFFF</span>
30
30
  </div>
31
31
  </div>
@@ -38,14 +38,14 @@ const t = (ui ?? {}) as ReadabilityCalculatorUI;
38
38
  <label class="rc-label-mini">{t.labelFontSize}</label>
39
39
  <span id="rc-size-val" class="rc-slider-value">16px</span>
40
40
  </div>
41
- <input type="range" id="rc-size-slider" class="rc-range" min="12" max="72" value="16" />
41
+ <input type="range" id="rc-size-slider" class="rc-range" min="12" max="72" value="16" aria-label={t.labelFontSize} />
42
42
  </div>
43
43
  <div class="rc-slider-group">
44
44
  <div class="rc-slider-header">
45
45
  <label class="rc-label-mini">{t.labelFontWeight}</label>
46
46
  <span id="rc-weight-val" class="rc-slider-value">400</span>
47
47
  </div>
48
- <input type="range" id="rc-weight-slider" class="rc-range" min="100" max="900" step="100" value="400" />
48
+ <input type="range" id="rc-weight-slider" class="rc-range" min="100" max="900" step="100" value="400" aria-label={t.labelFontWeight} />
49
49
  </div>
50
50
  </div>
51
51
 
@@ -9,7 +9,7 @@ const description = 'Prüfen Sie den echten Kontrast Ihrer Designs mit APCA (WCA
9
9
  const faqData = [
10
10
  {
11
11
  question: 'Was ist APCA und warum unterscheidet es sich von WCAG 2.1?',
12
- answer: 'APCA ist der Advanced Perceptual Contrast Algorithm, der für WCAG 3.0 entwickelt wurde. Anders als das alte einfache Verhältnis verwendet APCA mathematische Modelle, die nachbilden, wie das menschliche Gehirn Kontrast wahrnimmt unter Berücksichtigung der Polarität (heller vs. dunkler Hintergrund) und der Schriftgröße bzw. des Schriftgewichts.',
12
+ answer: 'APCA ist der Advanced Perceptual Contrast Algorithm, der für WCAG 3.0 entwickelt wurde. Anders als das alte einfache Verhältnis verwendet APCA mathematische Modelle, die nachbilden, wie das menschliche Gehirn Kontrast wahrnimmt - unter Berücksichtigung der Polarität (heller vs. dunkler Hintergrund) und der Schriftgröße bzw. des Schriftgewichts.',
13
13
  },
14
14
  {
15
15
  question: 'Was bedeutet der Lc-Wert?',
@@ -108,7 +108,7 @@ export const content: ToolLocaleContent<ReadabilityCalculatorUI> = {
108
108
  { type: 'title', text: 'Visueller Lesbarkeitsrechner (WCAG vs APCA)', level: 2 },
109
109
  {
110
110
  type: 'paragraph',
111
- html: 'Verstehen Sie, wie Farben und Typografie die tatsächliche Lesbarkeit beeinflussen mit dem neuen wahrnehmungsbasierten Barrierefreiheitsstandard. WCAG 2.1 nutzt eine einfache Formel aus dem Jahr 2008. <strong>APCA</strong> ist das neue Modell für <strong>WCAG 3.0</strong>, das menschliche Wahrnehmung nachbildet.',
111
+ html: 'Verstehen Sie, wie Farben und Typografie die tatsächliche Lesbarkeit beeinflussen - mit dem neuen wahrnehmungsbasierten Barrierefreiheitsstandard. WCAG 2.1 nutzt eine einfache Formel aus dem Jahr 2008. <strong>APCA</strong> ist das neue Modell für <strong>WCAG 3.0</strong>, das menschliche Wahrnehmung nachbildet.',
112
112
  },
113
113
  { type: 'title', text: 'Kernpunkte von APCA', level: 3 },
114
114
  {
@@ -9,6 +9,7 @@ interface Props {
9
9
 
10
10
  const { locale = 'es' } = Astro.props;
11
11
  const content = await readabilityCalculator.i18n[locale]?.();
12
+ if (!content) return null;
12
13
  ---
13
14
 
14
- {content && <SEORenderer content={{ locale, sections: content.seo }} />}
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}