@jjlmoya/utils-social 1.13.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/package.json +4 -2
  2. package/src/category/i18n/fr.ts +2 -2
  3. package/src/category/i18n/ru.ts +1 -1
  4. package/src/env.d.ts +5 -0
  5. package/src/layouts/PreviewLayout.astro +7 -2
  6. package/src/pages/[locale]/[slug].astro +28 -12
  7. package/src/tests/diacritics_density.test.ts +118 -0
  8. package/src/tests/inverted_punctuation.test.ts +84 -0
  9. package/src/tests/locale_completeness.test.ts +4 -14
  10. package/src/tests/no_en_dash.test.ts +70 -0
  11. package/src/tests/pagespeed_best_practices.test.ts +198 -0
  12. package/src/tests/script_density.test.ts +94 -0
  13. package/src/tests/shared-test-helpers.ts +56 -0
  14. package/src/tests/tool_exports.test.ts +34 -0
  15. package/src/tool/redditFormatter/bibliography.astro +2 -10
  16. package/src/tool/redditFormatter/bibliography.ts +12 -0
  17. package/src/tool/redditFormatter/i18n/de.ts +3 -13
  18. package/src/tool/redditFormatter/i18n/en.ts +3 -13
  19. package/src/tool/redditFormatter/i18n/es.ts +3 -13
  20. package/src/tool/redditFormatter/i18n/fr.ts +5 -15
  21. package/src/tool/redditFormatter/i18n/id.ts +3 -13
  22. package/src/tool/redditFormatter/i18n/it.ts +3 -13
  23. package/src/tool/redditFormatter/i18n/ja.ts +3 -13
  24. package/src/tool/redditFormatter/i18n/ko.ts +3 -13
  25. package/src/tool/redditFormatter/i18n/nl.ts +3 -13
  26. package/src/tool/redditFormatter/i18n/pl.ts +7 -17
  27. package/src/tool/redditFormatter/i18n/pt.ts +3 -13
  28. package/src/tool/redditFormatter/i18n/ru.ts +5 -15
  29. package/src/tool/redditFormatter/i18n/sv.ts +3 -13
  30. package/src/tool/redditFormatter/i18n/tr.ts +3 -13
  31. package/src/tool/redditFormatter/i18n/zh.ts +4 -14
  32. package/src/tool/redditFormatter/seo.astro +2 -1
  33. package/src/tool/safeZones/bibliography.astro +2 -10
  34. package/src/tool/safeZones/bibliography.ts +20 -0
  35. package/src/tool/safeZones/component.astro +1 -1
  36. package/src/tool/safeZones/i18n/de.ts +5 -23
  37. package/src/tool/safeZones/i18n/en.ts +5 -23
  38. package/src/tool/safeZones/i18n/es.ts +3 -21
  39. package/src/tool/safeZones/i18n/fr.ts +14 -32
  40. package/src/tool/safeZones/i18n/id.ts +5 -23
  41. package/src/tool/safeZones/i18n/it.ts +9 -27
  42. package/src/tool/safeZones/i18n/ja.ts +3 -21
  43. package/src/tool/safeZones/i18n/ko.ts +3 -21
  44. package/src/tool/safeZones/i18n/nl.ts +5 -23
  45. package/src/tool/safeZones/i18n/pl.ts +10 -28
  46. package/src/tool/safeZones/i18n/pt.ts +5 -23
  47. package/src/tool/safeZones/i18n/ru.ts +12 -30
  48. package/src/tool/safeZones/i18n/sv.ts +5 -23
  49. package/src/tool/safeZones/i18n/tr.ts +3 -21
  50. package/src/tool/safeZones/i18n/zh.ts +7 -25
  51. package/src/tool/safeZones/seo.astro +2 -1
  52. package/src/tool/socialImageResizer/bibliography.astro +2 -10
  53. package/src/tool/socialImageResizer/bibliography.ts +12 -0
  54. package/src/tool/socialImageResizer/component.astro +2 -2
  55. package/src/tool/socialImageResizer/i18n/de.ts +8 -18
  56. package/src/tool/socialImageResizer/i18n/en.ts +11 -21
  57. package/src/tool/socialImageResizer/i18n/es.ts +10 -20
  58. package/src/tool/socialImageResizer/i18n/fr.ts +14 -24
  59. package/src/tool/socialImageResizer/i18n/id.ts +11 -21
  60. package/src/tool/socialImageResizer/i18n/it.ts +19 -29
  61. package/src/tool/socialImageResizer/i18n/ja.ts +10 -20
  62. package/src/tool/socialImageResizer/i18n/ko.ts +10 -20
  63. package/src/tool/socialImageResizer/i18n/nl.ts +11 -21
  64. package/src/tool/socialImageResizer/i18n/pl.ts +12 -22
  65. package/src/tool/socialImageResizer/i18n/pt.ts +11 -21
  66. package/src/tool/socialImageResizer/i18n/ru.ts +17 -27
  67. package/src/tool/socialImageResizer/i18n/sv.ts +11 -21
  68. package/src/tool/socialImageResizer/i18n/tr.ts +10 -20
  69. package/src/tool/socialImageResizer/i18n/zh.ts +10 -20
  70. package/src/tool/socialImageResizer/seo.astro +2 -1
  71. package/src/tool/socialValueCalculator/bibliography.astro +2 -10
  72. package/src/tool/socialValueCalculator/bibliography.ts +16 -0
  73. package/src/tool/socialValueCalculator/component.astro +1 -2
  74. package/src/tool/socialValueCalculator/i18n/de.ts +5 -19
  75. package/src/tool/socialValueCalculator/i18n/en.ts +4 -18
  76. package/src/tool/socialValueCalculator/i18n/es.ts +5 -19
  77. package/src/tool/socialValueCalculator/i18n/fr.ts +9 -23
  78. package/src/tool/socialValueCalculator/i18n/id.ts +4 -18
  79. package/src/tool/socialValueCalculator/i18n/it.ts +17 -31
  80. package/src/tool/socialValueCalculator/i18n/ja.ts +4 -18
  81. package/src/tool/socialValueCalculator/i18n/ko.ts +4 -18
  82. package/src/tool/socialValueCalculator/i18n/nl.ts +4 -18
  83. package/src/tool/socialValueCalculator/i18n/pl.ts +4 -18
  84. package/src/tool/socialValueCalculator/i18n/pt.ts +4 -18
  85. package/src/tool/socialValueCalculator/i18n/ru.ts +10 -24
  86. package/src/tool/socialValueCalculator/i18n/sv.ts +4 -18
  87. package/src/tool/socialValueCalculator/i18n/tr.ts +4 -18
  88. package/src/tool/socialValueCalculator/i18n/zh.ts +7 -21
  89. package/src/tool/socialValueCalculator/seo.astro +2 -1
  90. package/src/tool/tinderPhotoOptimizer/bibliography.astro +2 -10
  91. package/src/tool/tinderPhotoOptimizer/bibliography.ts +12 -0
  92. package/src/tool/tinderPhotoOptimizer/component.astro +23 -6
  93. package/src/tool/tinderPhotoOptimizer/i18n/de.ts +6 -16
  94. package/src/tool/tinderPhotoOptimizer/i18n/en.ts +4 -14
  95. package/src/tool/tinderPhotoOptimizer/i18n/es.ts +3 -13
  96. package/src/tool/tinderPhotoOptimizer/i18n/fr.ts +28 -38
  97. package/src/tool/tinderPhotoOptimizer/i18n/id.ts +3 -13
  98. package/src/tool/tinderPhotoOptimizer/i18n/it.ts +3 -13
  99. package/src/tool/tinderPhotoOptimizer/i18n/ja.ts +3 -13
  100. package/src/tool/tinderPhotoOptimizer/i18n/ko.ts +3 -13
  101. package/src/tool/tinderPhotoOptimizer/i18n/nl.ts +3 -13
  102. package/src/tool/tinderPhotoOptimizer/i18n/pl.ts +3 -13
  103. package/src/tool/tinderPhotoOptimizer/i18n/pt.ts +3 -13
  104. package/src/tool/tinderPhotoOptimizer/i18n/ru.ts +12 -22
  105. package/src/tool/tinderPhotoOptimizer/i18n/sv.ts +3 -13
  106. package/src/tool/tinderPhotoOptimizer/i18n/tr.ts +3 -13
  107. package/src/tool/tinderPhotoOptimizer/i18n/zh.ts +5 -15
  108. package/src/tool/tinderPhotoOptimizer/seo.astro +2 -1
  109. package/src/tool/youtubeThumbnail/bibliography.astro +2 -10
  110. package/src/tool/youtubeThumbnail/bibliography.ts +16 -0
  111. package/src/tool/youtubeThumbnail/component.astro +1 -0
  112. package/src/tool/youtubeThumbnail/i18n/de.ts +6 -20
  113. package/src/tool/youtubeThumbnail/i18n/en.ts +4 -18
  114. package/src/tool/youtubeThumbnail/i18n/es.ts +3 -17
  115. package/src/tool/youtubeThumbnail/i18n/fr.ts +6 -20
  116. package/src/tool/youtubeThumbnail/i18n/id.ts +3 -17
  117. package/src/tool/youtubeThumbnail/i18n/it.ts +3 -17
  118. package/src/tool/youtubeThumbnail/i18n/ja.ts +3 -17
  119. package/src/tool/youtubeThumbnail/i18n/ko.ts +3 -17
  120. package/src/tool/youtubeThumbnail/i18n/nl.ts +3 -17
  121. package/src/tool/youtubeThumbnail/i18n/pl.ts +3 -17
  122. package/src/tool/youtubeThumbnail/i18n/pt.ts +3 -17
  123. package/src/tool/youtubeThumbnail/i18n/ru.ts +6 -20
  124. package/src/tool/youtubeThumbnail/i18n/sv.ts +3 -17
  125. package/src/tool/youtubeThumbnail/i18n/tr.ts +3 -17
  126. package/src/tool/youtubeThumbnail/i18n/zh.ts +5 -19
  127. package/src/tool/youtubeThumbnail/seo.astro +2 -1
  128. package/src/tool/youtubeThumbnailPreviewer/bibliography.astro +2 -10
  129. package/src/tool/youtubeThumbnailPreviewer/bibliography.ts +16 -0
  130. package/src/tool/youtubeThumbnailPreviewer/i18n/de.ts +11 -25
  131. package/src/tool/youtubeThumbnailPreviewer/i18n/en.ts +5 -19
  132. package/src/tool/youtubeThumbnailPreviewer/i18n/es.ts +3 -17
  133. package/src/tool/youtubeThumbnailPreviewer/i18n/fr.ts +12 -26
  134. package/src/tool/youtubeThumbnailPreviewer/i18n/id.ts +5 -19
  135. package/src/tool/youtubeThumbnailPreviewer/i18n/it.ts +24 -38
  136. package/src/tool/youtubeThumbnailPreviewer/i18n/ja.ts +3 -17
  137. package/src/tool/youtubeThumbnailPreviewer/i18n/ko.ts +3 -17
  138. package/src/tool/youtubeThumbnailPreviewer/i18n/nl.ts +7 -21
  139. package/src/tool/youtubeThumbnailPreviewer/i18n/pl.ts +10 -24
  140. package/src/tool/youtubeThumbnailPreviewer/i18n/pt.ts +3 -17
  141. package/src/tool/youtubeThumbnailPreviewer/i18n/ru.ts +14 -28
  142. package/src/tool/youtubeThumbnailPreviewer/i18n/sv.ts +5 -19
  143. package/src/tool/youtubeThumbnailPreviewer/i18n/tr.ts +3 -17
  144. package/src/tool/youtubeThumbnailPreviewer/i18n/zh.ts +13 -27
  145. package/src/tool/youtubeThumbnailPreviewer/seo.astro +2 -1
  146. package/src/types.ts +0 -2
@@ -1,3 +1,4 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialImageResizerUI } from '../ui';
@@ -36,7 +37,7 @@ const howToData = [
36
37
  },
37
38
  {
38
39
  name: 'Настройте и скачайте',
39
- text: 'Отредактируйте положение фото перетаскиванием и используйте зум для идеальной обрезки. По завершении нажмите «Скачать».',
40
+ text: 'Отредактируйте положение фото перетаскиванием и используйте зум для идеальной обрезки. По завершении нажмите \"Скачать\".',
40
41
  },
41
42
  ];
42
43
 
@@ -78,19 +79,8 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
78
79
  slug,
79
80
  title,
80
81
  description,
81
- faqTitle: 'Часто задаваемые вопросы',
82
- faq: faqData,
83
- bibliographyTitle: 'Источники',
84
- bibliography: [
85
- {
86
- name: 'MDN Web Docs: Canvas API',
87
- url: 'https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API',
88
- },
89
- {
90
- name: 'Sprout Social: руководство по размерам изображений для соцсетей 2026',
91
- url: 'https://sproutsocial.com/insights/social-media-image-sizes-guide/',
92
- },
93
- ],
82
+ faq: faqData,
83
+ bibliography,
94
84
  howTo: howToData,
95
85
  schemas: [faqSchema, howToSchema, appSchema],
96
86
  seo: [
@@ -101,11 +91,11 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
101
91
  },
102
92
  {
103
93
  type: 'paragraph',
104
- html: 'В современной цифровой экосистеме первое впечатление строится на визуале. Каждая социальная сеть работает на основе специфических алгоритмов, которые отдают приоритет контенту, нативно адаптированному под его пропорции. Наш инструмент — это не просто техническое средство, а ваш союзник в том, чтобы сообщение дошло до аудитории без нежелательных обрезок и потери качества.',
94
+ html: 'В современной цифровой экосистеме первое впечатление строится на визуале. Каждая социальная сеть работает на основе специфических алгоритмов, которые отдают приоритет контенту, нативно адаптированному под его пропорции. Наш инструмент - это не просто техническое средство, а ваш союзник в том, чтобы сообщение дошло до аудитории без нежелательных обрезок и потери качества.',
105
95
  },
106
96
  {
107
97
  type: 'paragraph',
108
- html: 'Нужно ли вам превратить пейзажное фото в эффектный вертикальный формат для Instagram Stories или адаптировать дизайн под сложный баннер YouTube — наше приложение использует систему умной обрезки, позволяющую точно позиционировать и масштабировать изображение прямо в браузере.',
98
+ html: 'Нужно ли вам превратить пейзажное фото в эффектный вертикальный формат для Instagram Stories или адаптировать дизайн под сложный баннер YouTube - наше приложение использует систему умной обрезки, позволяющую точно позиционировать и масштабировать изображение прямо в браузере.',
109
99
  },
110
100
  {
111
101
  type: 'title',
@@ -115,13 +105,13 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
115
105
  {
116
106
  type: 'grid',
117
107
  columns: [
118
- { title: 'Instagram — квадратный пост', body: '1080 × 1080 px · Соотношение 1:1' },
119
- { title: 'Instagram — вертикальный пост', body: '1080 × 1350 px · Соотношение 4:5' },
120
- { title: 'TikTok / Reels — вертикаль', body: '1080 × 1920 px · Соотношение 9:16' },
121
- { title: 'YouTube — миниатюра', body: '1280 × 720 px · Соотношение 16:9' },
122
- { title: 'YouTube — баннер канала', body: '2560 × 1440 px · Соотношение 16:9' },
123
- { title: 'X (Twitter) — стандартный пост', body: '1200 × 675 px · Соотношение 16:9' },
124
- { title: 'LinkedIn — обложка профиля', body: '1584 × 396 px · Соотношение 4:1' },
108
+ { title: 'Instagram: квадратный пост', body: '1080 × 1080 px · Соотношение 1:1' },
109
+ { title: 'Instagram: вертикальный пост', body: '1080 × 1350 px · Соотношение 4:5' },
110
+ { title: 'TikTok / Reels: вертикаль', body: '1080 × 1920 px · Соотношение 9:16' },
111
+ { title: 'YouTube: миниатюра', body: '1280 × 720 px · Соотношение 16:9' },
112
+ { title: 'YouTube: баннер канала', body: '2560 × 1440 px · Соотношение 16:9' },
113
+ { title: 'X (Twitter): стандартный пост', body: '1200 × 675 px · Соотношение 16:9' },
114
+ { title: 'LinkedIn: обложка профиля', body: '1584 × 396 px · Соотношение 4:1' },
125
115
  ],
126
116
  },
127
117
  {
@@ -137,11 +127,11 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
137
127
  },
138
128
  {
139
129
  title: 'Визуальный отклик',
140
- body: 'От миниатюр до баннеров — каждый графический элемент влияет на CTR. Точная обрезка гарантирует, что тексты и ключевые детали всегда будут читаемы.',
130
+ body: 'От миниатюр до баннеров - каждый графический элемент влияет на CTR. Точная обрезка гарантирует, что тексты и ключевые детали всегда будут читаемы.',
141
131
  },
142
132
  {
143
133
  title: 'Профессиональный брендинг',
144
- body: 'В деловых сетях вроде LinkedIn четкость — это авторитет. Обложки требуют специфических пропорций, чтобы не выглядеть размытыми на экранах с высокой плотностью пикселей.',
134
+ body: 'В деловых сетях вроде LinkedIn четкость - это авторитет. Обложки требуют специфических пропорций, чтобы не выглядеть размытыми на экранах с высокой плотностью пикселей.',
145
135
  },
146
136
  ],
147
137
  },
@@ -152,7 +142,7 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
152
142
  },
153
143
  {
154
144
  type: 'paragraph',
155
- html: 'Соотношение сторон — это пропорциональная связь между шириной и высотой изображения. Игнорирование этого заставляет платформы применять зум или добавлять черные полосы, что портит эстетику и снижает охваты.',
145
+ html: 'Соотношение сторон - это пропорциональная связь между шириной и высотой изображения. Игнорирование этого заставляет платформы применять зум или добавлять черные полосы, что портит эстетику и снижает охваты.',
156
146
  },
157
147
  {
158
148
  type: 'list',
@@ -198,7 +188,7 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
198
188
  },
199
189
  {
200
190
  type: 'paragraph',
201
- html: 'Профессиональная адаптация визуального контента — это прямая стратегия роста. Наше решение упрощает работу креаторам и менеджерам сообществ, делая каждый пост идеальным.',
191
+ html: 'Профессиональная адаптация визуального контента - это прямая стратегия роста. Наше решение упрощает работу креаторам и менеджерам сообществ, делая каждый пост идеальным.',
202
192
  },
203
193
  ],
204
194
  ui: {
@@ -1,3 +1,4 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialImageResizerUI } from '../ui';
@@ -78,19 +79,8 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
78
79
  slug,
79
80
  title,
80
81
  description,
81
- faqTitle: 'Vanliga frågor',
82
- faq: faqData,
83
- bibliographyTitle: 'Referenser',
84
- bibliography: [
85
- {
86
- name: 'MDN Web Docs: Canvas API',
87
- url: 'https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API',
88
- },
89
- {
90
- name: 'Sprout Social: Guide för bildstorlekar på sociala medier 2026',
91
- url: 'https://sproutsocial.com/insights/social-media-image-sizes-guide/',
92
- },
93
- ],
82
+ faq: faqData,
83
+ bibliography,
94
84
  howTo: howToData,
95
85
  schemas: [faqSchema, howToSchema, appSchema],
96
86
  seo: [
@@ -101,7 +91,7 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
101
91
  },
102
92
  {
103
93
  type: 'paragraph',
104
- html: 'I dagens digitala ekosystem är det första intrycket visuellt. Varje socialt nätverk arbetar under specifika algoritmer som prioriterar innehåll som är inbyggt anpassat till dess proportioner. Vår bildstorleksändrare för sociala medier är inte bara ett tekniskt verktyg – det är din partner för att säkerställa att ditt budskap når fram utan oönskad beskärning eller kvalitetsförlust.',
94
+ html: 'I dagens digitala ekosystem är det första intrycket visuellt. Varje socialt nätverk arbetar under specifika algoritmer som prioriterar innehåll som är inbyggt anpassat till dess proportioner. Vår bildstorleksändrare för sociala medier är inte bara ett tekniskt verktyg - det är din partner för att säkerställa att ditt budskap når fram utan oönskad beskärning eller kvalitetsförlust.',
105
95
  },
106
96
  {
107
97
  type: 'paragraph',
@@ -115,13 +105,13 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
115
105
  {
116
106
  type: 'grid',
117
107
  columns: [
118
- { title: 'Instagram — Kvadratiskt inlägg', body: '1080 × 1080 px · Ratio 1:1' },
119
- { title: 'Instagram — Vertikalt inlägg', body: '1080 × 1350 px · Ratio 4:5' },
120
- { title: 'TikTok / Reels — Vertikalt', body: '1080 × 1920 px · Ratio 9:16' },
121
- { title: 'YouTube — Miniatyrbild', body: '1280 × 720 px · Ratio 16:9' },
122
- { title: 'YouTube — Kanalbanner', body: '2560 × 1440 px · Ratio 16:9' },
123
- { title: 'X (Twitter) — Standardinlägg', body: '1200 × 675 px · Ratio 16:9' },
124
- { title: 'LinkedIn — Profilomslag', body: '1584 × 396 px · Ratio 4:1' },
108
+ { title: 'Instagram: Kvadratiskt inlägg', body: '1080 × 1080 px · Ratio 1:1' },
109
+ { title: 'Instagram: Vertikalt inlägg', body: '1080 × 1350 px · Ratio 4:5' },
110
+ { title: 'TikTok / Reels: Vertikalt', body: '1080 × 1920 px · Ratio 9:16' },
111
+ { title: 'YouTube: Miniatyrbild', body: '1280 × 720 px · Ratio 16:9' },
112
+ { title: 'YouTube: Kanalbanner', body: '2560 × 1440 px · Ratio 16:9' },
113
+ { title: 'X (Twitter): Standardinlägg', body: '1200 × 675 px · Ratio 16:9' },
114
+ { title: 'LinkedIn: Profilomslag', body: '1584 × 396 px · Ratio 4:1' },
125
115
  ],
126
116
  },
127
117
  {
@@ -1,3 +1,4 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialImageResizerUI } from '../ui';
@@ -78,19 +79,8 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
78
79
  slug,
79
80
  title,
80
81
  description,
81
- faqTitle: 'Sıkça Sorulan Sorular',
82
- faq: faqData,
83
- bibliographyTitle: 'Referanslar',
84
- bibliography: [
85
- {
86
- name: 'MDN Web Docs: Canvas API',
87
- url: 'https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API',
88
- },
89
- {
90
- name: 'Sprout Social: Sosyal Medya Resim Boyutları Kılavuzu 2026',
91
- url: 'https://sproutsocial.com/insights/social-media-image-sizes-guide/',
92
- },
93
- ],
82
+ faq: faqData,
83
+ bibliography,
94
84
  howTo: howToData,
95
85
  schemas: [faqSchema, howToSchema, appSchema],
96
86
  seo: [
@@ -115,13 +105,13 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
115
105
  {
116
106
  type: 'grid',
117
107
  columns: [
118
- { title: 'Instagram — Kare Gönderi', body: '1080 × 1080 px · Oran 1:1' },
119
- { title: 'Instagram — Dikey Gönderi', body: '1080 × 1350 px · Oran 4:5' },
120
- { title: 'TikTok / Reels — Dikey', body: '1080 × 1920 px · Oran 9:16' },
121
- { title: 'YouTube — Küçük Resim', body: '1280 × 720 px · Oran 16:9' },
122
- { title: 'YouTube — Kanal Banner\'ı', body: '2560 × 1440 px · Oran 16:9' },
123
- { title: 'X (Twitter) — Standart Gönderi', body: '1200 × 675 px · Oran 16:9' },
124
- { title: 'LinkedIn — Profil Kapağı', body: '1584 × 396 px · Oran 4:1' },
108
+ { title: 'Instagram: Kare Gönderi', body: '1080 × 1080 px · Oran 1:1' },
109
+ { title: 'Instagram: Dikey Gönderi', body: '1080 × 1350 px · Oran 4:5' },
110
+ { title: 'TikTok / Reels: Dikey', body: '1080 × 1920 px · Oran 9:16' },
111
+ { title: 'YouTube: Küçük Resim', body: '1280 × 720 px · Oran 16:9' },
112
+ { title: 'YouTube: Kanal Banner\'ı', body: '2560 × 1440 px · Oran 16:9' },
113
+ { title: 'X (Twitter): Standart Gönderi', body: '1200 × 675 px · Oran 16:9' },
114
+ { title: 'LinkedIn: Profil Kapağı', body: '1584 × 396 px · Oran 4:1' },
125
115
  ],
126
116
  },
127
117
  {
@@ -1,3 +1,4 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialImageResizerUI } from '../ui';
@@ -78,19 +79,8 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
78
79
  slug,
79
80
  title,
80
81
  description,
81
- faqTitle: '常见问题',
82
- faq: faqData,
83
- bibliographyTitle: '参考资料',
84
- bibliography: [
85
- {
86
- name: 'MDN Web Docs: Canvas API',
87
- url: 'https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API',
88
- },
89
- {
90
- name: 'Sprout Social: 2026 社交媒体图像尺寸指南',
91
- url: 'https://sproutsocial.com/insights/social-media-image-sizes-guide/',
92
- },
93
- ],
82
+ faq: faqData,
83
+ bibliography,
94
84
  howTo: howToData,
95
85
  schemas: [faqSchema, howToSchema, appSchema],
96
86
  seo: [
@@ -115,13 +105,13 @@ export const content: ToolLocaleContent<SocialImageResizerUI> = {
115
105
  {
116
106
  type: 'grid',
117
107
  columns: [
118
- { title: 'Instagram — 正方形帖子', body: '1080 × 1080 px · 比例 1:1' },
119
- { title: 'Instagram — 垂直帖子', body: '1080 × 1350 px · 比例 4:5' },
120
- { title: 'TikTok / Reels — 垂直', body: '1080 × 1920 px · 比例 9:16' },
121
- { title: 'YouTube — 缩略图', body: '1280 × 720 px · 比例 16:9' },
122
- { title: 'YouTube — 频道横幅', body: '2560 × 1440 px · 比例 16:9' },
123
- { title: 'X (Twitter) — 标准帖子', body: '1200 × 675 px · 比例 16:9' },
124
- { title: 'LinkedIn — 个人资料封面', body: '1584 × 396 px · 比例 4:1' },
108
+ { title: 'Instagram: 正方形帖子', body: '1080 × 1080 px · 比例 1:1' },
109
+ { title: 'Instagram: 垂直帖子', body: '1080 × 1350 px · 比例 4:5' },
110
+ { title: 'TikTok / Reels: 垂直', body: '1080 × 1920 px · 比例 9:16' },
111
+ { title: 'YouTube: 缩略图', body: '1280 × 720 px · 比例 16:9' },
112
+ { title: 'YouTube: 频道横幅', body: '2560 × 1440 px · 比例 16:9' },
113
+ { title: 'X (Twitter): 标准帖子', body: '1200 × 675 px · 比例 16:9' },
114
+ { title: 'LinkedIn: 个人资料封面', body: '1584 × 396 px · 比例 4:1' },
125
115
  ],
126
116
  },
127
117
  {
@@ -11,4 +11,5 @@ const { locale = 'es' } = Astro.props;
11
11
  const content = await socialImageResizer.i18n[locale]?.();
12
12
  if (!content) return null;
13
13
  ---
14
- <SEORenderer content={{ locale: locale as string, sections: content.seo }} />
14
+
15
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -1,14 +1,6 @@
1
1
  ---
2
2
  import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
- import { socialValueCalculator } 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 socialValueCalculator.i18n[locale]?.();
3
+ import { bibliography } from './bibliography';
12
4
  ---
13
5
 
14
- {content && <SharedBibliography links={content.bibliography} />}
6
+ <SharedBibliography links={bibliography} />
@@ -0,0 +1,16 @@
1
+ import type { BibliographyEntry } from '../../types';
2
+
3
+ export const bibliography: BibliographyEntry[] = [
4
+ {
5
+ name: 'Influencer Marketing Hub: Influencer Rates 2026',
6
+ url: 'https://influencermarketinghub.com/influencer-rates/',
7
+ },
8
+ {
9
+ name: 'HypeAuditor: TikTok & Instagram Engagement Report',
10
+ url: 'https://hypeauditor.com/free-tools/tiktok-engagement-calculator/',
11
+ },
12
+ {
13
+ name: 'Social Blade: Social Media Statistics',
14
+ url: 'https://socialblade.com/',
15
+ },
16
+ ];
@@ -248,8 +248,7 @@ const ICON_INFO = `<svg viewBox="0 0 24 24" fill="currentColor" width="16" heigh
248
248
  els.emptyState.classList.add('svc-hidden');
249
249
  els.results.classList.remove('svc-hidden');
250
250
  els.results.classList.remove('svc-fadein');
251
- void els.results.offsetWidth;
252
- els.results.classList.add('svc-fadein');
251
+ requestAnimationFrame(() => els.results.classList.add('svc-fadein'));
253
252
  }
254
253
 
255
254
  function calculate() {
@@ -1,3 +1,4 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialValueCalculatorUI } from '../ui';
@@ -21,7 +22,7 @@ const faqData = [
21
22
  {
22
23
  question: 'Was ist eine gute Engagement-Rate, um mehr verlangen zu können?',
23
24
  answer:
24
- 'Im Allgemeinen gilt ein Engagement von über 3 % als gesund. Konten mit mehr als 10 % Engagement gelten als „Premium-Profile“ und können einen deutlichen Aufschlag verlangen.',
25
+ 'Im Allgemeinen gilt ein Engagement von über 3 % als gesund. Konten mit mehr als 10 % Engagement gelten als \"Premium-Profile\" und können einen deutlichen Aufschlag verlangen.',
25
26
  },
26
27
  {
27
28
  question: 'Beeinflusst die Nische den Preis wirklich so stark?',
@@ -87,23 +88,8 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
87
88
  slug,
88
89
  title,
89
90
  description,
90
- faqTitle: 'Häufig gestellte Fragen',
91
- faq: faqData,
92
- bibliographyTitle: 'Quellen & Marktstudien',
93
- bibliography: [
94
- {
95
- name: 'Influencer Marketing Hub: Influencer Rates 2026',
96
- url: 'https://influencermarketinghub.com/influencer-rates/',
97
- },
98
- {
99
- name: 'HypeAuditor: TikTok & Instagram Engagement Report',
100
- url: 'https://hypeauditor.com/free-tools/tiktok-engagement-calculator/',
101
- },
102
- {
103
- name: 'Social Blade: Social Media Statistiken',
104
- url: 'https://socialblade.com/',
105
- },
106
- ],
91
+ faq: faqData,
92
+ bibliography,
107
93
  howTo: howToData,
108
94
  schemas: [faqSchema, howToSchema, appSchema],
109
95
  seo: [
@@ -145,7 +131,7 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
145
131
  },
146
132
  {
147
133
  type: 'card',
148
- title: '15€–50€',
134
+ title: '15€ bis 50€',
149
135
  html: '<p>Durchschnittlicher CPM in wertvollen Nischen</p>',
150
136
  },
151
137
  ],
@@ -1,3 +1,4 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialValueCalculatorUI } from '../ui';
@@ -87,23 +88,8 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
87
88
  slug,
88
89
  title,
89
90
  description,
90
- faqTitle: 'Frequently Asked Questions',
91
- faq: faqData,
92
- bibliographyTitle: 'Sources & Market Studies',
93
- bibliography: [
94
- {
95
- name: 'Influencer Marketing Hub: Influencer Rates 2026',
96
- url: 'https://influencermarketinghub.com/influencer-rates/',
97
- },
98
- {
99
- name: 'HypeAuditor: TikTok & Instagram Engagement Report',
100
- url: 'https://hypeauditor.com/free-tools/tiktok-engagement-calculator/',
101
- },
102
- {
103
- name: 'Social Blade: Social Media Statistics',
104
- url: 'https://socialblade.com/',
105
- },
106
- ],
91
+ faq: faqData,
92
+ bibliography,
107
93
  howTo: howToData,
108
94
  schemas: [faqSchema, howToSchema, appSchema],
109
95
  seo: [
@@ -145,7 +131,7 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
145
131
  },
146
132
  {
147
133
  type: 'card',
148
- title: '$15–$50',
134
+ title: '$15 to $50',
149
135
  html: '<p>Average CPM in high-value niches (stable)</p>',
150
136
  },
151
137
  ],
@@ -1,9 +1,10 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialValueCalculatorUI } from '../ui';
4
5
 
5
6
  const slug = 'calculadora-valor-cuenta-redes-sociales';
6
- const title = 'Calculadora de Valor de Cuenta TikTok & Instagram : Precios';
7
+ const title = 'Calculadora de Valor de Cuenta TikTok & Instagram: Precios';
7
8
  const description =
8
9
  'Descubre cuánto cobrar por tus publicaciones patrocinadas. Nuestra calculadora analiza seguidores, engagement y nicho para darte un valor de mercado justo.';
9
10
 
@@ -87,23 +88,8 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
87
88
  slug,
88
89
  title,
89
90
  description,
90
- faqTitle: 'Preguntas Frecuentes',
91
- faq: faqData,
92
- bibliographyTitle: 'Fuentes y Estudios de Mercado',
93
- bibliography: [
94
- {
95
- name: 'Influencer Marketing Hub: Influencer Rates 2026',
96
- url: 'https://influencermarketinghub.com/influencer-rates/',
97
- },
98
- {
99
- name: 'HypeAuditor: Reporte de Engagement en TikTok e Instagram',
100
- url: 'https://hypeauditor.com/es/free-tools/tiktok-engagement-calculator/',
101
- },
102
- {
103
- name: 'Social Blade: Estadísticas de Redes Sociales',
104
- url: 'https://socialblade.com/',
105
- },
106
- ],
91
+ faq: faqData,
92
+ bibliography,
107
93
  howTo: howToData,
108
94
  schemas: [faqSchema, howToSchema, appSchema],
109
95
  seo: [
@@ -145,7 +131,7 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
145
131
  },
146
132
  {
147
133
  type: 'card',
148
- title: '15 €–50 €',
134
+ title: '15 € a 50 €',
149
135
  html: '<p>CPM promedio en nichos de alto valor (estable)</p>',
150
136
  },
151
137
  ],
@@ -1,9 +1,10 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialValueCalculatorUI } from '../ui';
4
5
 
5
6
  const slug = 'calculateur-valeur-compte-reseaux-sociaux';
6
- const title = 'Calculateur de Valeur de Compte TikTok & Instagram : Tarifs';
7
+ const title = 'Calculateur de Valeur de Compte TikTok & Instagram: Tarifs';
7
8
  const description =
8
9
  "Découvrez combien facturer pour vos publications sponsorisées. Notre calculateur analyse les abonnés, l'engagement et le créneau pour vous donner une valeur de marché juste.";
9
10
 
@@ -87,23 +88,8 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
87
88
  slug,
88
89
  title,
89
90
  description,
90
- faqTitle: 'Questions Fréquentes',
91
- faq: faqData,
92
- bibliographyTitle: 'Sources et Études de Marché',
93
- bibliography: [
94
- {
95
- name: 'Influencer Marketing Hub: Influencer Rates 2026',
96
- url: 'https://influencermarketinghub.com/influencer-rates/',
97
- },
98
- {
99
- name: "HypeAuditor: Rapport d'engagement TikTok & Instagram",
100
- url: 'https://hypeauditor.com/free-tools/tiktok-engagement-calculator/',
101
- },
102
- {
103
- name: 'Social Blade: Statistiques des réseaux sociaux',
104
- url: 'https://socialblade.com/',
105
- },
106
- ],
91
+ faq: faqData,
92
+ bibliography,
107
93
  howTo: howToData,
108
94
  schemas: [faqSchema, howToSchema, appSchema],
109
95
  seo: [
@@ -114,12 +100,12 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
114
100
  },
115
101
  {
116
102
  type: 'title',
117
- text: 'Calculateur de Valeur de Compte : Combien facturer une promotion sur TikTok ou Instagram ?',
103
+ text: 'Calculateur de Valeur de Compte: Combien facturer une promotion sur TikTok ou Instagram ?',
118
104
  level: 2,
119
105
  },
120
106
  {
121
107
  type: 'paragraph',
122
- html: 'Si vous êtes créateur de contenu, influenceur ou simplement une communauté active sur les réseaux sociaux, vous vous êtes probablement demandé à un moment : <strong>combien vaut vraiment mon compte ?</strong> ou <strong>combien devrais-je demander pour une collaboration avec une marque ?</strong>.',
108
+ html: 'Si vous êtes créateur de contenu, influenceur ou simplement une communauté active sur les réseaux sociaux, vous vous êtes probablement demandé à un moment: <strong>combien vaut vraiment mon compte ?</strong> ou <strong>combien devrais-je demander pour une collaboration avec une marque ?</strong>.',
123
109
  },
124
110
  {
125
111
  type: 'title',
@@ -145,7 +131,7 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
145
131
  },
146
132
  {
147
133
  type: 'card',
148
- title: '15 €–50 €',
134
+ title: '15 € à 50 €',
149
135
  html: '<p>CPM moyen dans les créneaux de haute valeur (stable)</p>',
150
136
  },
151
137
  ],
@@ -207,7 +193,7 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
207
193
  },
208
194
  {
209
195
  type: 'title',
210
- text: "TikTok vs Instagram : Où est l'argent ?",
196
+ text: "TikTok vs Instagram: Où est l'argent ?",
211
197
  level: 2,
212
198
  },
213
199
  {
@@ -241,7 +227,7 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
241
227
  {
242
228
  type: 'tip',
243
229
  title: 'Modèle de négociation',
244
- html: "<p>Bonjour [Nom de la Marque], merci de m'avoir contacté. En me basant sur mes métriques actuelles de portée (moyenne de [X] vues) et mon taux d'engagement de [X]%, mon tarif pour une intégration dans un [Reel/TikTok] est de [Prix €]. Cela inclut : scénarisation et production vidéo, 1 lien en bio 24h, 2 Stories d'amplification, droits d'utilisation 30 jours.</p>",
230
+ html: "<p>Bonjour [Nom de la Marque], merci de m'avoir contacté. En me basant sur mes métriques actuelles de portée (moyenne de [X] vues) et mon taux d'engagement de [X]%, mon tarif pour une intégration dans un [Reel/TikTok] est de [Prix €]. Cela inclut: scénarisation et production vidéo, 1 lien en bio 24h, 2 Stories d'amplification, droits d'utilisation 30 jours.</p>",
245
231
  },
246
232
  {
247
233
  type: 'title',
@@ -1,3 +1,4 @@
1
+ import { bibliography } from '../bibliography';
1
2
  import type { WithContext, FAQPage, HowToThing, SoftwareApplication } from 'schema-dts';
2
3
  import type { ToolLocaleContent } from '../../../types';
3
4
  import type { SocialValueCalculatorUI } from '../ui';
@@ -87,23 +88,8 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
87
88
  slug,
88
89
  title,
89
90
  description,
90
- faqTitle: 'Pertanyaan yang Sering Diajukan',
91
- faq: faqData,
92
- bibliographyTitle: 'Sumber & Studi Pasar',
93
- bibliography: [
94
- {
95
- name: 'Influencer Marketing Hub: Influencer Rates 2026',
96
- url: 'https://influencermarketinghub.com/influencer-rates/',
97
- },
98
- {
99
- name: 'HypeAuditor: Laporan Keterlibatan TikTok & Instagram',
100
- url: 'https://hypeauditor.com/free-tools/tiktok-engagement-calculator/',
101
- },
102
- {
103
- name: 'Social Blade: Statistik Media Sosial',
104
- url: 'https://socialblade.com/',
105
- },
106
- ],
91
+ faq: faqData,
92
+ bibliography,
107
93
  howTo: howToData,
108
94
  schemas: [faqSchema, howToSchema, appSchema],
109
95
  seo: [
@@ -145,7 +131,7 @@ export const content: ToolLocaleContent<SocialValueCalculatorUI> = {
145
131
  },
146
132
  {
147
133
  type: 'card',
148
- title: 'Rp15rb–Rp50rb',
134
+ title: 'Rp15rb hingga Rp50rb',
149
135
  html: '<p>Rata-rata CPM di ceruk bernilai tinggi (per 1.000 tayangan)</p>',
150
136
  },
151
137
  ],