@jjlmoya/utils-developer 1.30.0 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/package.json +70 -70
  2. package/src/category/seo.astro +1 -1
  3. package/src/components/PreviewNavSidebar.astro +1 -1
  4. package/src/components/PreviewToolbar.astro +1 -1
  5. package/src/data.ts +1 -1
  6. package/src/env.d.ts +1 -1
  7. package/src/layouts/PreviewLayout.astro +1 -1
  8. package/src/pages/[locale]/[slug].astro +162 -162
  9. package/src/pages/index.astro +1 -1
  10. package/src/tests/entry_contract.test.ts +8 -2
  11. package/src/tests/faq_count.test.ts +1 -1
  12. package/src/tests/i18n_coverage.test.ts +2 -6
  13. package/src/tests/inverted_punctuation.test.ts +113 -113
  14. package/src/tests/mocks/astro_mock.js +1 -1
  15. package/src/tests/no_h1_in_components.test.ts +1 -1
  16. package/src/tests/promote_this_website_i18n.test.ts +33 -0
  17. package/src/tests/slug_language_code_format.test.ts +25 -25
  18. package/src/tests/slug_uniqueness.test.ts +86 -86
  19. package/src/tests/tool_validation.test.ts +15 -15
  20. package/src/tool/aspectRatio/i18n/de.ts +164 -164
  21. package/src/tool/aspectRatio/i18n/ja.ts +1 -1
  22. package/src/tool/aspectRatio/i18n/ko.ts +1 -1
  23. package/src/tool/aspectRatio/i18n/pl.ts +164 -164
  24. package/src/tool/aspectRatio/i18n/ru.ts +164 -164
  25. package/src/tool/aspectRatio/i18n/zh.ts +165 -165
  26. package/src/tool/aspectRatio/seo.astro +15 -15
  27. package/src/tool/calculadoraTiempoDatos/i18n/de.ts +143 -143
  28. package/src/tool/calculadoraTiempoDatos/i18n/ja.ts +1 -1
  29. package/src/tool/calculadoraTiempoDatos/i18n/ko.ts +1 -1
  30. package/src/tool/calculadoraTiempoDatos/i18n/pl.ts +143 -143
  31. package/src/tool/calculadoraTiempoDatos/i18n/ru.ts +144 -144
  32. package/src/tool/calculadoraTiempoDatos/i18n/sv.ts +143 -143
  33. package/src/tool/calculadoraTiempoDatos/i18n/zh.ts +144 -144
  34. package/src/tool/calculadoraTiempoDatos/seo.astro +15 -15
  35. package/src/tool/colorConverter/i18n/de.ts +120 -120
  36. package/src/tool/colorConverter/i18n/ja.ts +1 -1
  37. package/src/tool/colorConverter/i18n/ko.ts +1 -1
  38. package/src/tool/colorConverter/i18n/ru.ts +120 -120
  39. package/src/tool/colorConverter/i18n/zh.ts +1 -1
  40. package/src/tool/colorConverter/seo.astro +15 -15
  41. package/src/tool/conversorExcelCsvHtml/i18n/ja.ts +1 -1
  42. package/src/tool/conversorExcelCsvHtml/i18n/ko.ts +1 -1
  43. package/src/tool/conversorExcelCsvHtml/i18n/pl.ts +124 -124
  44. package/src/tool/conversorExcelCsvHtml/i18n/ru.ts +124 -124
  45. package/src/tool/conversorExcelCsvHtml/i18n/zh.ts +125 -125
  46. package/src/tool/conversorExcelCsvHtml/seo.astro +15 -15
  47. package/src/tool/cronGenerator/i18n/ja.ts +1 -1
  48. package/src/tool/cronGenerator/i18n/ko.ts +1 -1
  49. package/src/tool/cronGenerator/i18n/zh.ts +183 -183
  50. package/src/tool/cronGenerator/seo.astro +15 -15
  51. package/src/tool/cssSpecificityCalculator/i18n/ja.ts +1 -1
  52. package/src/tool/cssSpecificityCalculator/i18n/ko.ts +1 -1
  53. package/src/tool/cssSpecificityCalculator/i18n/zh.ts +1 -1
  54. package/src/tool/cssSpecificityCalculator/seo.astro +15 -15
  55. package/src/tool/cssToInlineConverter/i18n/ja.ts +1 -1
  56. package/src/tool/cssToInlineConverter/i18n/ko.ts +1 -1
  57. package/src/tool/cssToInlineConverter/i18n/zh.ts +1 -1
  58. package/src/tool/cssToInlineConverter/seo.astro +15 -15
  59. package/src/tool/duplicateCssRemover/i18n/ja.ts +1 -1
  60. package/src/tool/duplicateCssRemover/i18n/ko.ts +1 -1
  61. package/src/tool/duplicateCssRemover/i18n/zh.ts +1 -1
  62. package/src/tool/duplicateCssRemover/seo.astro +15 -15
  63. package/src/tool/generadorSecurityTxt/i18n/ja.ts +1 -1
  64. package/src/tool/generadorSecurityTxt/i18n/ko.ts +1 -1
  65. package/src/tool/generadorSecurityTxt/i18n/zh.ts +1 -1
  66. package/src/tool/generadorSecurityTxt/seo.astro +15 -15
  67. package/src/tool/hashGenerator/i18n/ja.ts +1 -1
  68. package/src/tool/hashGenerator/i18n/ko.ts +1 -1
  69. package/src/tool/hashGenerator/seo.astro +15 -15
  70. package/src/tool/inspectorCertificadosSsl/i18n/ja.ts +1 -1
  71. package/src/tool/inspectorCertificadosSsl/i18n/ko.ts +1 -1
  72. package/src/tool/inspectorCertificadosSsl/i18n/zh.ts +1 -1
  73. package/src/tool/inspectorCertificadosSsl/seo.astro +15 -15
  74. package/src/tool/jsonFormatter/seo.astro +15 -15
  75. package/src/tool/jwtDecoder/i18n/es.ts +248 -248
  76. package/src/tool/jwtDecoder/i18n/fr.ts +248 -248
  77. package/src/tool/jwtDecoder/i18n/tr.ts +248 -248
  78. package/src/tool/keycode/seo.astro +15 -15
  79. package/src/tool/llmCostCalculator/i18n/fr.ts +149 -149
  80. package/src/tool/llmCostCalculator/i18n/ja.ts +1 -1
  81. package/src/tool/llmCostCalculator/i18n/ko.ts +1 -1
  82. package/src/tool/llmCostCalculator/seo.astro +15 -15
  83. package/src/tool/mobileMockupGenerator/i18n/ja.ts +1 -1
  84. package/src/tool/mobileMockupGenerator/i18n/ko.ts +1 -1
  85. package/src/tool/mobileMockupGenerator/i18n/zh.ts +1 -1
  86. package/src/tool/mobileMockupGenerator/seo.astro +15 -15
  87. package/src/tool/musicalTypography/i18n/ja.ts +1 -1
  88. package/src/tool/musicalTypography/i18n/ko.ts +1 -1
  89. package/src/tool/musicalTypography/i18n/zh.ts +1 -1
  90. package/src/tool/musicalTypography/seo.astro +15 -15
  91. package/src/tool/placeholderGenerator/i18n/ja.ts +1 -1
  92. package/src/tool/placeholderGenerator/i18n/ko.ts +1 -1
  93. package/src/tool/placeholderGenerator/i18n/zh.ts +1 -1
  94. package/src/tool/placeholderGenerator/seo.astro +15 -15
  95. package/src/tool/promoteThisWebsite/entry.ts +13 -0
  96. package/src/tool/promoteThisWebsite/i18n/de.ts +95 -0
  97. package/src/tool/promoteThisWebsite/i18n/fr.ts +95 -0
  98. package/src/tool/promoteThisWebsite/i18n/id.ts +95 -0
  99. package/src/tool/promoteThisWebsite/i18n/it.ts +95 -0
  100. package/src/tool/promoteThisWebsite/i18n/ja.ts +95 -0
  101. package/src/tool/promoteThisWebsite/i18n/ko.ts +95 -0
  102. package/src/tool/promoteThisWebsite/i18n/nl.ts +95 -0
  103. package/src/tool/promoteThisWebsite/i18n/pl.ts +95 -0
  104. package/src/tool/promoteThisWebsite/i18n/pt.ts +95 -0
  105. package/src/tool/promoteThisWebsite/i18n/ru.ts +95 -0
  106. package/src/tool/promoteThisWebsite/i18n/sv.ts +95 -0
  107. package/src/tool/promoteThisWebsite/i18n/tr.ts +95 -0
  108. package/src/tool/promoteThisWebsite/i18n/zh.ts +95 -0
  109. package/src/tool/promptLibrary/i18n/ja.ts +1 -1
  110. package/src/tool/promptLibrary/i18n/ko.ts +1 -1
  111. package/src/tool/promptLibrary/i18n/zh.ts +1 -1
  112. package/src/tool/promptLibrary/seo.astro +15 -15
  113. package/src/tool/readabilityCalculator/i18n/ja.ts +1 -1
  114. package/src/tool/readabilityCalculator/i18n/ko.ts +1 -1
  115. package/src/tool/readabilityCalculator/i18n/zh.ts +1 -1
  116. package/src/tool/readabilityCalculator/seo.astro +15 -15
  117. package/src/tool/serpPixelSimulator/entry.ts +30 -30
  118. package/src/tool/serpPixelSimulator/i18n/en.ts +211 -211
  119. package/src/tool/serpPixelSimulator/i18n/fr.ts +214 -214
  120. package/src/tool/serpPixelSimulator/i18n/ru.ts +214 -214
  121. package/src/tool/serpPixelSimulator/logic.ts +18 -18
  122. package/src/tool/serpPixelSimulator/serp-pixel-simulator.css +195 -195
  123. package/src/tool/svgSanitizer/i18n/ja.ts +1 -1
  124. package/src/tool/svgSanitizer/i18n/ko.ts +1 -1
  125. package/src/tool/svgSanitizer/seo.astro +15 -15
  126. package/src/tool/svgToCss/i18n/ja.ts +1 -1
  127. package/src/tool/svgToCss/i18n/ko.ts +1 -1
  128. package/src/tool/svgToCss/seo.astro +15 -15
  129. package/src/tool/urlCleaner/i18n/ja.ts +1 -1
  130. package/src/tool/urlCleaner/i18n/ko.ts +1 -1
  131. package/src/tool/urlCleaner/i18n/zh.ts +1 -1
  132. package/src/tool/urlCleaner/seo.astro +15 -15
  133. package/src/tool/urlEncoderDecoder/i18n/es.ts +146 -146
  134. package/src/tool/urlEncoderDecoder/i18n/ko.ts +1 -1
  135. package/src/tool/urlEncoderDecoder/seo.astro +15 -15
  136. package/src/tool/utmGenerator/i18n/ja.ts +1 -1
  137. package/src/tool/utmGenerator/i18n/ko.ts +1 -1
  138. package/src/tool/utmGenerator/i18n/zh.ts +1 -1
  139. package/src/tool/utmGenerator/seo.astro +15 -15
  140. package/src/types.ts +1 -1
@@ -1,150 +1,150 @@
1
1
  import { bibliography } from '../bibliography';
2
- import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
3
- import type { ToolLocaleContent } from '../../../types';
4
- import type { LlmCostCalculatorUI } from '../ui';
5
-
6
- const slug = 'calculateur-couts-llm';
7
- const title = 'Calculateur de Coûts LLM. Estimateur de Prix des APIs IA';
8
- const description =
9
- 'Outil en ligne gratuit pour estimer le coût des appels aux APIs de modèles de langage. Comparez GPT-4o, Claude, Gemini, Llama et plus avec les vrais prix par million de tokens.';
10
-
11
- const faqData = [
12
- {
13
- question: "Comment le coût d'une API LLM est-il calculé ?",
14
- answer:
15
- "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.",
16
- },
17
- {
18
- question: 'Que sont les tokens et comment se rapportent-ils aux mots ?',
19
- answer:
20
- "Un token est l'unité de base de texte qu'un modèle de langage traite. En moyenne, 1 token équivaut à environ 0,75 mot en anglais, soit 1 000 tokens ≈ 750 mots. Les prix sont indiqués par million de tokens ($/1M), qui est l'unité tarifaire standard chez tous les fournisseurs.",
21
- },
22
- {
23
- question: "Pourquoi les tokens de sortie sont-ils plus chers que les tokens d'entrée ?",
24
- answer:
25
- "Générer du texte (sortie) oblige le modèle à calculer chaque token séquentiellement, ce qui est plus coûteux en calcul que de lire l'entrée. La plupart des fournisseurs facturent 3 à 5 fois plus pour les tokens de sortie que pour les tokens d'entrée.",
26
- },
27
- {
28
- question: 'Comment réduire les coûts de mon API LLM ?',
29
- answer:
30
- "Utilisez le modèle le plus petit qui répond à vos exigences de qualité. Mettez en cache les prompts répétés si possible. Minimisez la longueur du prompt système et évitez le contexte inutile. Pour les tâches simples de classification ou d'extraction, des modèles plus petits comme GPT-4o mini ou Gemini Flash offrent des économies significatives.",
31
- },
32
- ];
33
-
34
- const howToData = [
35
- {
36
- name: 'Sélectionner un modèle',
37
- text: "Choisissez le modèle IA que vous prévoyez d'utiliser dans la liste déroulante groupée. Les modèles sont organisés par fournisseur.",
38
- },
39
- {
40
- name: 'Saisir le nombre de tokens',
41
- text: "Entrez le nombre attendu de tokens d'entrée (votre prompt) et de sortie (la réponse). Une estimation en mots apparaît sous chaque champ.",
42
- },
43
- {
44
- name: 'Définir le nombre de requêtes',
45
- text: "Utilisez le curseur ou le champ numérique pour indiquer combien d'appels API vous prévoyez. Le coût total se met à jour en temps réel.",
46
- },
47
- ];
48
-
49
- const faqSchema: WithContext<FAQPage> = {
50
- '@context': 'https://schema.org',
51
- '@type': 'FAQPage',
52
- mainEntity: faqData.map((item) => ({
53
- '@type': 'Question',
54
- name: item.question,
55
- acceptedAnswer: { '@type': 'Answer', text: item.answer },
56
- })),
57
- };
58
-
59
- const howToSchema: WithContext<HowToThing> = {
60
- '@context': 'https://schema.org',
61
- '@type': 'HowTo',
62
- name: title,
63
- description,
64
- step: howToData.map((step, i) => ({
65
- '@type': 'HowToStep',
66
- position: i + 1,
67
- name: step.name,
68
- text: step.text,
69
- })),
70
- };
71
-
72
- const appSchema: WithContext<SoftwareApplication> = {
73
- '@context': 'https://schema.org',
74
- '@type': 'SoftwareApplication',
75
- name: title,
76
- description,
77
- applicationCategory: 'DeveloperApplication',
78
- operatingSystem: 'All',
79
- offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
80
- inLanguage: 'fr',
81
- };
82
-
83
- const ui: LlmCostCalculatorUI = {
84
- labelModel: 'Modèle LLM',
85
- labelInputTokens: "Tokens d'entrée",
86
- labelOutputTokens: 'Tokens de sortie',
87
- labelRequests: 'Nombre de requêtes',
88
- unitWords: 'mots',
89
- labelCostPerRequest: 'Coût par requête',
90
- labelTotal: 'Coût total estimé',
91
- labelInput: 'Input',
92
- labelOutput: 'Output',
93
- };
94
-
95
- export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
96
- slug,
97
- title,
98
- description,
99
- ui,
100
- faqTitle: 'Questions fréquentes',
101
- faq: faqData,
102
- bibliographyTitle: 'Références et Sources de Prix',
103
- bibliography,
104
- howTo: howToData,
105
- schemas: [faqSchema, howToSchema, appSchema],
106
- seo: [
107
- {
108
- type: 'title',
109
- text: 'Comprendre la tarification des APIs LLM',
110
- level: 2,
111
- },
112
- {
113
- type: 'paragraph',
114
- 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.",
115
- },
116
- {
117
- type: 'title',
118
- text: "Tokens d'entrée et tokens de sortie",
119
- level: 3,
120
- },
121
- {
122
- type: 'grid',
123
- columns: 2,
124
- },
125
- {
126
- type: 'card',
127
- title: "Tokens d'entrée",
128
- 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>",
129
- },
130
- {
131
- type: 'card',
132
- title: 'Tokens de sortie',
133
- html: '<p>Les tokens de sortie sont générés un par un séquentiellement, ce qui les rend plus coûteux en calcul. La plupart des fournisseurs facturent <strong>3 à 5 fois plus</strong> pour les tokens de sortie. Une réponse de 300 mots génère environ 400 tokens de sortie. Garder les réponses concises est une des stratégies d\'économie les plus efficaces.</p>',
134
- },
135
- {
136
- type: 'title',
137
- text: 'Choisir le bon modèle pour votre budget',
138
- level: 3,
139
- },
140
- {
141
- type: 'tip',
142
- html: 'Commencez avec un modèle de milieu de gamme comme <code>GPT-4o mini</code> ou <code>Gemini 1.5 Flash</code> et ne montez en gamme que si la qualité est insuffisante. La différence de coût entre un petit et un grand modèle peut être de 10 à 100 fois.',
143
- },
144
- {
145
- type: 'paragraph',
146
- html: "Toutes les tâches ne nécessitent pas le même niveau de modèle. Les tâches de classification, d'extraction et de résumé fonctionnent souvent bien avec des modèles plus petits et moins chers. Réservez les grands modèles comme <code>claude-3-opus</code> ou <code>o1</code> pour les raisonnements complexes où la qualité impacte directement les résultats.",
147
- },
148
- ],
149
- };
150
-
2
+ import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
3
+ import type { ToolLocaleContent } from '../../../types';
4
+ import type { LlmCostCalculatorUI } from '../ui';
5
+
6
+ const slug = 'calculateur-couts-llm';
7
+ const title = 'Calculateur de Coûts LLM. Estimateur de Prix des APIs IA';
8
+ const description =
9
+ 'Outil en ligne gratuit pour estimer le coût des appels aux APIs de modèles de langage. Comparez GPT-4o, Claude, Gemini, Llama et plus avec les vrais prix par million de tokens.';
10
+
11
+ const faqData = [
12
+ {
13
+ question: "Comment le coût d'une API LLM est-il calculé ?",
14
+ answer:
15
+ "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.",
16
+ },
17
+ {
18
+ question: 'Que sont les tokens et comment se rapportent-ils aux mots ?',
19
+ answer:
20
+ "Un token est l'unité de base de texte qu'un modèle de langage traite. En moyenne, 1 token équivaut à environ 0,75 mot en anglais, soit 1 000 tokens ≈ 750 mots. Les prix sont indiqués par million de tokens ($/1M), qui est l'unité tarifaire standard chez tous les fournisseurs.",
21
+ },
22
+ {
23
+ question: "Pourquoi les tokens de sortie sont-ils plus chers que les tokens d'entrée ?",
24
+ answer:
25
+ "Générer du texte (sortie) oblige le modèle à calculer chaque token séquentiellement, ce qui est plus coûteux en calcul que de lire l'entrée. La plupart des fournisseurs facturent 3 à 5 fois plus pour les tokens de sortie que pour les tokens d'entrée.",
26
+ },
27
+ {
28
+ question: 'Comment réduire les coûts de mon API LLM ?',
29
+ answer:
30
+ "Utilisez le modèle le plus petit qui répond à vos exigences de qualité. Mettez en cache les prompts répétés si possible. Minimisez la longueur du prompt système et évitez le contexte inutile. Pour les tâches simples de classification ou d'extraction, des modèles plus petits comme GPT-4o mini ou Gemini Flash offrent des économies significatives.",
31
+ },
32
+ ];
33
+
34
+ const howToData = [
35
+ {
36
+ name: 'Sélectionner un modèle',
37
+ text: "Choisissez le modèle IA que vous prévoyez d'utiliser dans la liste déroulante groupée. Les modèles sont organisés par fournisseur.",
38
+ },
39
+ {
40
+ name: 'Saisir le nombre de tokens',
41
+ text: "Entrez le nombre attendu de tokens d'entrée (votre prompt) et de sortie (la réponse). Une estimation en mots apparaît sous chaque champ.",
42
+ },
43
+ {
44
+ name: 'Définir le nombre de requêtes',
45
+ text: "Utilisez le curseur ou le champ numérique pour indiquer combien d'appels API vous prévoyez. Le coût total se met à jour en temps réel.",
46
+ },
47
+ ];
48
+
49
+ const faqSchema: WithContext<FAQPage> = {
50
+ '@context': 'https://schema.org',
51
+ '@type': 'FAQPage',
52
+ mainEntity: faqData.map((item) => ({
53
+ '@type': 'Question',
54
+ name: item.question,
55
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
56
+ })),
57
+ };
58
+
59
+ const howToSchema: WithContext<HowToThing> = {
60
+ '@context': 'https://schema.org',
61
+ '@type': 'HowTo',
62
+ name: title,
63
+ description,
64
+ step: howToData.map((step, i) => ({
65
+ '@type': 'HowToStep',
66
+ position: i + 1,
67
+ name: step.name,
68
+ text: step.text,
69
+ })),
70
+ };
71
+
72
+ const appSchema: WithContext<SoftwareApplication> = {
73
+ '@context': 'https://schema.org',
74
+ '@type': 'SoftwareApplication',
75
+ name: title,
76
+ description,
77
+ applicationCategory: 'DeveloperApplication',
78
+ operatingSystem: 'All',
79
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
80
+ inLanguage: 'fr',
81
+ };
82
+
83
+ const ui: LlmCostCalculatorUI = {
84
+ labelModel: 'Modèle LLM',
85
+ labelInputTokens: "Tokens d'entrée",
86
+ labelOutputTokens: 'Tokens de sortie',
87
+ labelRequests: 'Nombre de requêtes',
88
+ unitWords: 'mots',
89
+ labelCostPerRequest: 'Coût par requête',
90
+ labelTotal: 'Coût total estimé',
91
+ labelInput: 'Input',
92
+ labelOutput: 'Output',
93
+ };
94
+
95
+ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
96
+ slug,
97
+ title,
98
+ description,
99
+ ui,
100
+ faqTitle: 'Questions fréquentes',
101
+ faq: faqData,
102
+ bibliographyTitle: 'Références et Sources de Prix',
103
+ bibliography,
104
+ howTo: howToData,
105
+ schemas: [faqSchema, howToSchema, appSchema],
106
+ seo: [
107
+ {
108
+ type: 'title',
109
+ text: 'Comprendre la tarification des APIs LLM',
110
+ level: 2,
111
+ },
112
+ {
113
+ type: 'paragraph',
114
+ 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.",
115
+ },
116
+ {
117
+ type: 'title',
118
+ text: "Tokens d'entrée et tokens de sortie",
119
+ level: 3,
120
+ },
121
+ {
122
+ type: 'grid',
123
+ columns: 2,
124
+ },
125
+ {
126
+ type: 'card',
127
+ title: "Tokens d'entrée",
128
+ 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>",
129
+ },
130
+ {
131
+ type: 'card',
132
+ title: 'Tokens de sortie',
133
+ html: '<p>Les tokens de sortie sont générés un par un séquentiellement, ce qui les rend plus coûteux en calcul. La plupart des fournisseurs facturent <strong>3 à 5 fois plus</strong> pour les tokens de sortie. Une réponse de 300 mots génère environ 400 tokens de sortie. Garder les réponses concises est une des stratégies d\'économie les plus efficaces.</p>',
134
+ },
135
+ {
136
+ type: 'title',
137
+ text: 'Choisir le bon modèle pour votre budget',
138
+ level: 3,
139
+ },
140
+ {
141
+ type: 'tip',
142
+ html: 'Commencez avec un modèle de milieu de gamme comme <code>GPT-4o mini</code> ou <code>Gemini 1.5 Flash</code> et ne montez en gamme que si la qualité est insuffisante. La différence de coût entre un petit et un grand modèle peut être de 10 à 100 fois.',
143
+ },
144
+ {
145
+ type: 'paragraph',
146
+ html: "Toutes les tâches ne nécessitent pas le même niveau de modèle. Les tâches de classification, d'extraction et de résumé fonctionnent souvent bien avec des modèles plus petits et moins chers. Réservez les grands modèles comme <code>claude-3-opus</code> ou <code>o1</code> pour les raisonnements complexes où la qualité impacte directement les résultats.",
147
+ },
148
+ ],
149
+ };
150
+
@@ -147,4 +147,4 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
147
147
  },
148
148
  ],
149
149
  };
150
-
150
+
@@ -147,4 +147,4 @@ export const content: ToolLocaleContent<LlmCostCalculatorUI> = {
147
147
  },
148
148
  ],
149
149
  };
150
-
150
+
@@ -1,15 +1,15 @@
1
- ---
2
- import { SEORenderer } from '@jjlmoya/utils-shared';
3
- import { llmCostCalculator } from './index';
4
- import type { KnownLocale } from '../../types';
5
-
6
- interface Props {
7
- locale?: KnownLocale;
8
- }
9
-
10
- const { locale = 'es' } = Astro.props;
11
- const content = await llmCostCalculator.i18n[locale]?.();
12
- if (!content) return null;
13
- ---
14
-
15
- {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { llmCostCalculator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await llmCostCalculator.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -117,4 +117,4 @@ export const content: ToolLocaleContent<MobileMockupGeneratorUI> = {
117
117
  { type: 'tip', html: '「左分割」と「右分割」のプリセットを使うと、InstagramカルーセルやApp Storeのスクリーンショットで画像がシームレスにつながるモックアップを作成できます。' },
118
118
  ],
119
119
  };
120
-
120
+
@@ -117,4 +117,4 @@ export const content: ToolLocaleContent<MobileMockupGeneratorUI> = {
117
117
  { type: 'tip', html: '"왼쪽 분할"과 "오른쪽 분할" 프리셋을 사용하면 Instagram 캐러셀이나 App Store 스크린샷에서 이미지가 자연스럽게 이어지는 연속 목업을 만들 수 있습니다.' },
118
118
  ],
119
119
  };
120
-
120
+
@@ -117,4 +117,4 @@ export const content: ToolLocaleContent<MobileMockupGeneratorUI> = {
117
117
  { type: 'tip', html: '使用"左分割"和"右分割"预设来创建连续的演示图,在 Instagram 轮播或 App Store 屏幕截图中从一个图像滑到另一个。' },
118
118
  ],
119
119
  };
120
-
120
+
@@ -1,15 +1,15 @@
1
- ---
2
- import { SEORenderer } from '@jjlmoya/utils-shared';
3
- import { mobileMockupGenerator } from './index';
4
- import type { KnownLocale } from '../../types';
5
-
6
- interface Props {
7
- locale?: KnownLocale;
8
- }
9
-
10
- const { locale = 'es' } = Astro.props;
11
- const content = await mobileMockupGenerator.i18n[locale]?.();
12
- if (!content) return null;
13
- ---
14
-
15
- {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { mobileMockupGenerator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await mobileMockupGenerator.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -165,4 +165,4 @@ export const content: ToolLocaleContent<MusicalTypographyUI> = {
165
165
  },
166
166
  ],
167
167
  };
168
-
168
+
@@ -165,4 +165,4 @@ export const content: ToolLocaleContent<MusicalTypographyUI> = {
165
165
  },
166
166
  ],
167
167
  };
168
-
168
+
@@ -28,4 +28,4 @@ const appSchema: WithContext<SoftwareApplication> = { '@context': 'https://schem
28
28
  const ui: MusicalTypographyUI = { labelConfig: '配置', labelBaseSize: '基础大小 (px)', hintBaseSize: '您的段落文本大小(通常16px)。', labelRatio: '音乐秤(比例)', hintRatio: '确定每个步骤的大小增长程度。', labelCalculated: '计算值', labelPreview: '预览', btnCopyCss: '复制CSS变量', feedbackCopied: '变量已复制到剪贴板!', previewText: '音乐排版', previewSubtext: '为您的设计提供完美的和谐秤。', ratioSecundaMenor: '小二度', ratioSegundaMayor: '大二度', ratioTerceraMenor: '小三度', ratioTerceraMayor: '大三度', ratioCuartaPerfecta: '完全四度', ratioCuartaAumentada: '增大四度', ratioQuintaPerfecta: '完全五度', ratioProporcionAurea: '黄金比例', ratioSextaMayor: '大六度', ratioSeptimaMenor: '小七度', ratioSeptimaMayor: '大七度', ratioOctava: '八度' };
29
29
 
30
30
  export const content: ToolLocaleContent<MusicalTypographyUI> = { slug, title, description, ui, faqTitle: '常见问题', faq: faqData, bibliographyTitle: '参考', bibliography, howTo: howToData, schemas: [faqSchema, howToSchema, appSchema], seo: [{ type: 'title', text: '网页设计中看不见的和谐', level: 2 }, { type: 'paragraph', html: '<strong>音乐排版秤</strong>将音乐间隔的数学应用于排版设计。就像音乐作品受精确比例支配一样,一个好的设计受益于一个将所有大小联系起来的数学结构。' }, { type: 'title', text: '模块化秤如何工作', level: 3 }, { type: 'grid', columns: 2 }, { type: 'card', title: '公式', html: '<p>进度很简单:<code>Size = Base × Ratio<sup>n</sup></code>。第0步是您的基础文本。第1步是小字幕。第4或5步可能是您的主H1。相同的乘法常数(比例)确保所有关系一致。</p>' }, { type: 'card', title: '为什么是"音乐的"', html: '<p>毕达哥拉斯发现,将弦分成简单比例(1:2、2:3、3:4)会产生辅音。这些间隔、八度、完全五度和完全四度,正是排版比例。您正在组成视觉音乐。</p>' }, { type: 'title', text: '选择正确的比例', level: 3 }, { type: 'tip', html: '对于密集界面(仪表板、表格),使用小比例(如<code>1.125</code>或<code>1.2</code>)。对于编辑或投资组合网站,使用更富表现力的比例(如<code>1.5</code>或<code>1.618</code>)。' }, { type: 'paragraph', html: '不要将秤限制在仅<code>font-size</code>。相同的CSS变量适用于<code>margin</code>、<code>padding</code>和<code>gap</code>。当空白遵循与文本相同的数学进度时,设计达到所有人都能感受但很少有人能解释的凝聚力。' }] };
31
-
31
+
@@ -1,15 +1,15 @@
1
- ---
2
- import { SEORenderer } from '@jjlmoya/utils-shared';
3
- import { musicalTypography } from './index';
4
- import type { KnownLocale } from '../../types';
5
-
6
- interface Props {
7
- locale?: KnownLocale;
8
- }
9
-
10
- const { locale = 'es' } = Astro.props;
11
- const content = await musicalTypography.i18n[locale]?.();
12
- if (!content) return null;
13
- ---
14
-
15
- {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { musicalTypography } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await musicalTypography.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -162,4 +162,4 @@ export const content: ToolLocaleContent<PlaceholderGeneratorUI> = {
162
162
  },
163
163
  ],
164
164
  };
165
-
165
+
@@ -162,4 +162,4 @@ export const content: ToolLocaleContent<PlaceholderGeneratorUI> = {
162
162
  },
163
163
  ],
164
164
  };
165
-
165
+
@@ -162,4 +162,4 @@ export const content: ToolLocaleContent<PlaceholderGeneratorUI> = {
162
162
  },
163
163
  ],
164
164
  };
165
-
165
+
@@ -1,15 +1,15 @@
1
- ---
2
- import { SEORenderer } from '@jjlmoya/utils-shared';
3
- import { placeholderGenerator } from './index';
4
- import type { KnownLocale } from '../../types';
5
-
6
- interface Props {
7
- locale?: KnownLocale;
8
- }
9
-
10
- const { locale = 'es' } = Astro.props;
11
- const content = await placeholderGenerator.i18n[locale]?.();
12
- if (!content) return null;
13
- ---
14
-
15
- {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { placeholderGenerator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await placeholderGenerator.i18n[locale]?.();
12
+ if (!content) return null;
13
+ ---
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -10,7 +10,20 @@ export const promoteThisWebsite: DeveloperToolEntry<PromoteThisWebsiteUI> = {
10
10
  fg: 'mdi:image-multiple-outline',
11
11
  },
12
12
  i18n: {
13
+ de: async () => (await import('./i18n/de')).content,
13
14
  en: async () => (await import('./i18n/en')).content,
14
15
  es: async () => (await import('./i18n/es')).content,
16
+ fr: async () => (await import('./i18n/fr')).content,
17
+ id: async () => (await import('./i18n/id')).content,
18
+ it: async () => (await import('./i18n/it')).content,
19
+ ja: async () => (await import('./i18n/ja')).content,
20
+ ko: async () => (await import('./i18n/ko')).content,
21
+ nl: async () => (await import('./i18n/nl')).content,
22
+ pl: async () => (await import('./i18n/pl')).content,
23
+ pt: async () => (await import('./i18n/pt')).content,
24
+ ru: async () => (await import('./i18n/ru')).content,
25
+ sv: async () => (await import('./i18n/sv')).content,
26
+ tr: async () => (await import('./i18n/tr')).content,
27
+ zh: async () => (await import('./i18n/zh')).content,
15
28
  },
16
29
  };
@@ -0,0 +1,95 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { PromoteThisWebsiteUI } from '../ui';
4
+ import { bibliography } from '../bibliography';
5
+
6
+ const localized = {
7
+ slug: 'diese-website-bewerben',
8
+ title: 'Diese Website bewerben',
9
+ description: 'Die interne Propagandastelle für jjlmoya.es auf Spanisch und GameBob.dev international. Verwandle Screenshots deiner eigenen Seiten in Social-Bilder, bevor Bob den Feed peinlich findet.',
10
+ faqTitle: 'Diese Website bewerben, ohne die Katze zu verärgern',
11
+ bibliographyTitle: 'Seiten der Operation',
12
+ faq: [
13
+ { question: 'Für wen ist dieses Werkzeug eigentlich?', answer: 'Für die Bewerbung der Seiten jjlmoya.es auf Spanisch und GameBob.dev international. Alle anderen dürfen durchs Fenster schauen.' },
14
+ { question: 'Kann ich einen Screenshot direkt einfügen?', answer: 'Ja. Kopiere einen Screenshot und drücke Strg+V. Er wird zur Werkzeugebene, denn selbst die Katzenverwaltung akzeptiert Beweise im richtigen Format.' },
15
+ { question: 'Was passiert mit einer Produktions-URL?', answer: 'Das Werkzeug liest den Meta-Titel, wählt die passende Marke und lädt das Open-Graph-Bild. Der Slug bekommt endlich keine Beförderung.' },
16
+ { question: 'Warum gibt es zwei Marken?', answer: 'jjlmoya.es ist die spanische Seite und GameBob.dev die internationale Seite. Die Katzen ignorieren diesen Unterschied.' },
17
+ { question: 'Werden meine Bilder hochgeladen?', answer: 'Nein. Die Bilder bleiben im Browser und die Komposition wird lokal erstellt. Nur dein bewusst heruntergeladenes PNG verlässt die Seite.' },
18
+ ],
19
+ howTo: [
20
+ { name: 'Screenshot einfügen', text: 'Füge mit Strg+V einen Screenshot von jjlmoya.es oder GameBob.dev ein. Die Behörde verlangt Beweise aus dem eigenen Imperium.' },
21
+ { name: 'Marke auswählen', text: 'Wähle jjlmoya.es für Spanisch oder GameBob.dev für die internationale Seite. Die Katze besitzt bereits die Räumlichkeiten.' },
22
+ { name: 'Bild arrangieren', text: 'Ziehe Screenshot, Titel, Logo, Hintergrund und Maskottchen an die richtige Stelle, bis es absichtlich aussieht.' },
23
+ { name: 'PNG exportieren', text: 'Lade das PNG in den gewünschten Maßen herunter, bevor Bob den Verdienst beansprucht.' },
24
+ ],
25
+ seoTitle: 'Die offizielle Propagandastelle für jjlmoya und GameBob',
26
+ seoIntro: 'Dies ist kein beliebiger Social-Media-Komponist für jemanden, der gerade das Wort Branding entdeckt hat. Er existiert, um unsere Seiten unter jjlmoya.es und GameBob.dev zu bewerben, während die Katzen die Arbeit beaufsichtigen.',
27
+ seoBody: 'Füge einen echten Screenshot ein oder lade eine Produktions-URL. Das Werkzeug liest den Seitentitel statt aus dem Slug zu raten und hält das Open-Graph-Bild sichtbar, während die Nebenrollen platziert werden.',
28
+ seoTip: 'Beginne mit einer Produktions-URL von jjlmoya.es oder GameBob.dev. Wenn Titel, Marke oder Bild fehlen, beschuldigt die Behörde zuerst das Netz, dann den Menschen und zuletzt die Katzen.',
29
+ };
30
+ const ui: PromoteThisWebsiteUI = {
31
+ urlLabel: 'Webseiten-URL', urlPlaceholder: 'https://www.example.com/tools/beispiel/', applyUrl: 'Anwenden',
32
+ formatLabel: 'Format', panoramic: 'Panorama · 1536 × 1024', instagram: 'Instagram · 1080 × 1350', square: 'Quadrat · 1080 × 1080', story: 'Story · 1080 × 1920',
33
+ titleLabel: 'Titel', titlePlaceholder: 'Kurzer Titel für das Bild', titleSizeLabel: 'Schriftgröße des Titels', titleBoxSizeLabel: 'Größe des Titelfelds', titleStyleLabel: 'Titelgestaltung',
34
+ brandLabel: 'Marke', brandStyleLabel: 'Markengestaltung', advancedLabel: 'Erweiterte Komposition', assetsLabel: 'Elemente', backgroundLabel: 'Hintergrund', toolLabel: 'Werkzeug-Screenshot', logoLabel: 'Logo', mascotLabel: 'Maskottchen',
35
+ layersLabel: 'Ebenen', backgroundLayer: 'Hintergrund', toolLayer: 'Werkzeug', logoLayer: 'Logo', mascotLayer: 'Maskottchen', titleLayer: 'Titel', reset: 'Zurücksetzen', download: 'PNG herunterladen', activeLayer: 'Aktive Ebene',
36
+ canvasHint: 'Ziehe die Ebenen direkt auf der Zeichenfläche. Füge einen Screenshot mit Strg+V ein.', pasted: 'Screenshot als Werkzeugebene eingefügt.', urlApplied: 'URL angewendet. Passe den Titel an und füge den gewünschten Screenshot hinzu.', urlLoading: 'Seitentitel und offizielles Bild werden gelesen ...', urlFailed: 'Diese Seite konnte nicht gelesen werden. Prüfe die URL oder füge die Elemente manuell hinzu.', fileLoaded: 'Element geladen.',
37
+ titlePaper: 'Redaktionelles Papier', titleRibbon: 'Gefaltetes Band', titleInk: 'Tintenspritzer', titlePoster: 'Nachtplakat', titleTicket: 'Abgerissene Eintrittskarte', titleMarker: 'Material-Unterstreichung', titleSplit: 'Geteilter Block', titleCapsule: 'Minimale Kapsel', titleCorner: 'Redaktionelle Ecke', titleVertical: 'Vertikaler Akzent',
38
+ brandPlain: 'Schlichte Marke', brandPlaque: 'Keramiktafel', brandTicket: 'Eintrittskarte', brandStamp: 'Gummistempel', brandNeon: 'Neonschild', brandRibbon: 'Signalband', brandCorner: 'Redaktionelle Ecke', brandPixel: 'Pixelblock', brandHalo: 'Sanfter Schein', brandEditorial: 'Redaktionelle Linie', defaultTool: 'Füge den Werkzeug-Screenshot ein',
39
+ };
40
+
41
+ const faqSchema: WithContext<FAQPage> = {
42
+ '@context': 'https://schema.org',
43
+ '@type': 'FAQPage',
44
+ mainEntity: localized.faq.map((item) => ({
45
+ '@type': 'Question',
46
+ name: item.question,
47
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
48
+ })),
49
+ };
50
+ const howToSchema: WithContext<HowTo> = {
51
+ '@context': 'https://schema.org',
52
+ '@type': 'HowTo',
53
+ name: localized.title,
54
+ description: localized.description,
55
+ step: localized.howTo.map((step, index) => ({
56
+ '@type': 'HowToStep',
57
+ position: index + 1,
58
+ name: step.name,
59
+ text: step.text,
60
+ })),
61
+ };
62
+ const appSchema: WithContext<SoftwareApplication> = {
63
+ '@context': 'https://schema.org',
64
+ '@type': 'SoftwareApplication',
65
+ name: localized.title,
66
+ description: localized.description,
67
+ applicationCategory: 'DeveloperApplication',
68
+ operatingSystem: 'Any',
69
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
70
+ inLanguage: 'de',
71
+ };
72
+
73
+ export const content: ToolLocaleContent<PromoteThisWebsiteUI> = {
74
+ slug: localized.slug,
75
+ title: localized.title,
76
+ description: localized.description,
77
+ ui,
78
+ faqTitle: localized.faqTitle,
79
+ faq: localized.faq,
80
+ bibliographyTitle: localized.bibliographyTitle,
81
+ bibliography,
82
+ howTo: localized.howTo,
83
+ schemas: [appSchema, faqSchema, howToSchema],
84
+ seo: [
85
+ { type: 'title', text: localized.seoTitle, level: 2 },
86
+ { type: 'paragraph', html: localized.seoIntro },
87
+ { type: 'stats', columns: 3, items: [{ value: '2', label: ui.brandLabel, icon: 'mdi:domain' }, { value: '4', label: ui.formatLabel, icon: 'mdi:crop' }, { value: '0', label: ui.activeLayer, icon: 'mdi:cat' }] },
88
+ { type: 'title', text: localized.title, level: 3 },
89
+ { type: 'paragraph', html: localized.seoBody },
90
+ { type: 'title', text: localized.faqTitle, level: 3 },
91
+ { type: 'paragraph', html: localized.seoBody },
92
+ { type: 'table', headers: [ui.toolLayer, ui.titleLayer, ui.brandLabel], rows: [[ui.toolLabel, ui.titleLabel, ui.logoLabel]] },
93
+ { type: 'tip', title: localized.faqTitle, html: localized.seoTip },
94
+ ],
95
+ };