core-maugli 1.2.4 → 1.2.6

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 (68) hide show
  1. package/package.json +1 -1
  2. package/public/img/default/autor_default.webp +0 -0
  3. package/public/img/default/blog_default.webp +0 -0
  4. package/public/img/default/default.webp +0 -0
  5. package/public/img/default/product_default.webp +0 -0
  6. package/public/img/default/project_default.webp +0 -0
  7. package/public/img/default/rubric_default.webp +0 -0
  8. package/public/img/default/test.webp +0 -0
  9. package/public/img/default/test2.webp +0 -0
  10. package/scripts/test-version-update.js +54 -0
  11. package/scripts/update-components.js +94 -6
  12. package/scripts/upgrade-config.js +1 -1
  13. package/src/i18n/de.json +126 -0
  14. package/src/i18n/en.json +126 -0
  15. package/src/i18n/es.json +126 -0
  16. package/src/i18n/fr.json +126 -0
  17. package/src/i18n/index.ts +10 -0
  18. package/src/i18n/ja.json +126 -0
  19. package/src/i18n/languages.ts +23 -0
  20. package/src/i18n/pt.json +126 -0
  21. package/src/i18n/ru.json +123 -0
  22. package/src/i18n/zh.json +126 -0
  23. package/src/icons/ArrowLeft.astro +13 -0
  24. package/src/icons/ArrowRight.astro +13 -0
  25. package/src/icons/flags/brazil.svg +14 -0
  26. package/src/icons/flags/china.svg +15 -0
  27. package/src/icons/flags/france.svg +12 -0
  28. package/src/icons/flags/germany.svg +12 -0
  29. package/src/icons/flags/japan.svg +11 -0
  30. package/src/icons/flags/russia.svg +12 -0
  31. package/src/icons/flags/spain.svg +12 -0
  32. package/src/icons/flags/united arab emirates.svg +13 -0
  33. package/src/icons/flags/united states.svg +15 -0
  34. package/src/icons/socials/BlueskyIcon.astro +9 -0
  35. package/src/icons/socials/EmailIcon.astro +8 -0
  36. package/src/icons/socials/LinkedinIcon.astro +9 -0
  37. package/src/icons/socials/MastodonIcon.astro +9 -0
  38. package/src/icons/socials/MediumIcon.astro +9 -0
  39. package/src/icons/socials/RedditIcon.astro +11 -0
  40. package/src/icons/socials/TelegramIcon.astro +11 -0
  41. package/src/icons/socials/TwitterIcon.astro +9 -0
  42. package/src/layouts/BaseLayout.astro +59 -0
  43. package/src/pages/404.astro +24 -0
  44. package/src/pages/[...id].astro +50 -0
  45. package/src/pages/about.astro +0 -0
  46. package/src/pages/authors/[...page].astro +105 -0
  47. package/src/pages/authors/[id].astro +175 -0
  48. package/src/pages/blog/[...page].astro +59 -0
  49. package/src/pages/blog/[id].astro +175 -0
  50. package/src/pages/index.astro +90 -0
  51. package/src/pages/products/[...page].astro +50 -0
  52. package/src/pages/products/[id].astro +221 -0
  53. package/src/pages/projects/[...page].astro +74 -0
  54. package/src/pages/projects/[id].astro +165 -0
  55. package/src/pages/projects/tags/[id]/[...page].astro +58 -0
  56. package/src/pages/rss.xml.js +5 -0
  57. package/src/pages/tags/[id]/[...page].astro +110 -0
  58. package/src/pages/tags/index.astro +124 -0
  59. package/src/scripts/infoCardFadeIn.js +22 -0
  60. package/src/styles/global.css +273 -0
  61. package/src/utils/common-utils.ts +0 -0
  62. package/src/utils/content-loader.ts +14 -0
  63. package/src/utils/data-utils.ts +49 -0
  64. package/src/utils/featuredManager.ts +118 -0
  65. package/src/utils/posts.ts +43 -0
  66. package/src/utils/reading-time.ts +28 -0
  67. package/src/utils/remark-slugify.js +8 -0
  68. package/src/utils/rss.ts +23 -0
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "core-maugli",
3
3
  "description": "Astro & Tailwind CSS blog theme for Maugli.",
4
4
  "type": "module",
5
- "version": "1.2.4",
5
+ "version": "1.2.6",
6
6
  "license": "GPL-3.0-or-later OR Commercial",
7
7
  "repository": {
8
8
  "type": "git",
Binary file
Binary file
Binary file
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'fs/promises';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ async function testVersionUpdate() {
11
+ console.log('🧪 Testing version update function...');
12
+
13
+ try {
14
+ // Получаем версию из package.json
15
+ const packageJsonPath = path.join(__dirname, '../package.json');
16
+ const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
17
+ const packageData = JSON.parse(packageJsonContent);
18
+ const newVersion = packageData.version;
19
+
20
+ // Путь к конфигу
21
+ const configPath = path.join(__dirname, '../src/config/maugli.config.ts');
22
+
23
+ // Читаем конфиг
24
+ const configContent = await fs.readFile(configPath, 'utf-8');
25
+
26
+ // Ищем строку с MAUGLI_CONFIG_VERSION
27
+ const versionRegex = /export const MAUGLI_CONFIG_VERSION = ['"`]([^'"`]+)['"`];/;
28
+ const match = configContent.match(versionRegex);
29
+
30
+ if (match) {
31
+ const currentVersion = match[1];
32
+ console.log(`📦 Current config version: ${currentVersion}`);
33
+ console.log(`📦 Package version: ${newVersion}`);
34
+
35
+ if (currentVersion !== newVersion) {
36
+ const updatedContent = configContent.replace(
37
+ versionRegex,
38
+ `export const MAUGLI_CONFIG_VERSION = '${newVersion}';`
39
+ );
40
+
41
+ await fs.writeFile(configPath, updatedContent, 'utf-8');
42
+ console.log(`✅ Updated config version: ${currentVersion} → ${newVersion}`);
43
+ } else {
44
+ console.log(`✅ Config version already up to date: ${newVersion}`);
45
+ }
46
+ } else {
47
+ console.log('❌ Config version line not found');
48
+ }
49
+ } catch (error) {
50
+ console.error('❌ Test failed:', error.message);
51
+ }
52
+ }
53
+
54
+ testVersionUpdate();
@@ -8,11 +8,14 @@ const __filename = fileURLToPath(import.meta.url);
8
8
  const __dirname = path.dirname(__filename);
9
9
 
10
10
  // Определяем корневые папки
11
- const packageRoot = __dirname.includes('node_modules')
11
+ const isInNodeModules = __dirname.includes('node_modules');
12
+ const isSourceProject = !isInNodeModules && (__dirname.includes('core-maugli-blog') || process.cwd().includes('core-maugli-blog'));
13
+
14
+ const packageRoot = isInNodeModules
12
15
  ? path.join(__dirname, '../../..', 'node_modules', 'core-maugli') // из node_modules
13
- : path.join(__dirname, '..'); // из исходников (для разработки)
16
+ : path.join(__dirname, '..'); // из исходников
14
17
 
15
- const userRoot = __dirname.includes('node_modules')
18
+ const userRoot = isInNodeModules
16
19
  ? path.join(__dirname, '../../..') // корень пользовательского проекта
17
20
  : process.env.INIT_CWD || process.cwd(); // для разработки
18
21
 
@@ -25,6 +28,9 @@ const FORCE_UPDATE_PATHS = [
25
28
  'src/scripts',
26
29
  'src/icons',
27
30
  'src/i18n',
31
+ 'scripts', // Скрипты в корне проекта (включая generate-previews.js)
32
+ 'typograf-batch.js', // Отдельный файл
33
+ 'resize-all.cjs', // Отдельный файл для ресайза
28
34
  'public/flags',
29
35
  'public/img/default'
30
36
  // Исключили src/styles - может содержать пользовательские стили
@@ -38,9 +44,82 @@ const PRESERVE_PATHS = [
38
44
  'package.json',
39
45
  'astro.config.mjs',
40
46
  'tailwind.config.js',
41
- 'tsconfig.json'
47
+ 'tsconfig.json',
48
+ 'scripts/custom-*' // Пользовательские скрипты с префиксом custom-
42
49
  ];
43
50
 
51
+ async function updateConfigVersion() {
52
+ try {
53
+ // Получаем версию из package.json пакета
54
+ const packageJsonPath = path.join(packageRoot, 'package.json');
55
+ const packageJsonContent = await fs.readFile(packageJsonPath, 'utf-8');
56
+ const packageData = JSON.parse(packageJsonContent);
57
+ const newVersion = packageData.version;
58
+
59
+ // Путь к package.json пользователя
60
+ const userPackageJsonPath = path.join(userRoot, 'package.json');
61
+
62
+ try {
63
+ // Читаем package.json пользователя
64
+ const userPackageContent = await fs.readFile(userPackageJsonPath, 'utf-8');
65
+ const userPackageData = JSON.parse(userPackageContent);
66
+
67
+ let updated = false;
68
+
69
+ // Обновляем версию зависимости
70
+ if (userPackageData.dependencies && userPackageData.dependencies['core-maugli']) {
71
+ const currentVersion = userPackageData.dependencies['core-maugli'];
72
+ if (currentVersion !== `^${newVersion}`) {
73
+ userPackageData.dependencies['core-maugli'] = `^${newVersion}`;
74
+ updated = true;
75
+ }
76
+ }
77
+
78
+ if (userPackageData.devDependencies && userPackageData.devDependencies['core-maugli']) {
79
+ const currentVersion = userPackageData.devDependencies['core-maugli'];
80
+ if (currentVersion !== `^${newVersion}`) {
81
+ userPackageData.devDependencies['core-maugli'] = `^${newVersion}`;
82
+ updated = true;
83
+ }
84
+ }
85
+
86
+ // Обновляем build скрипт для включения генерации превью
87
+ if (userPackageData.scripts) {
88
+ const expectedBuildScript = "node typograf-batch.js && node scripts/generate-previews.js && node scripts/verify-assets.js && astro build";
89
+ const currentBuildScript = userPackageData.scripts.build;
90
+
91
+ // Проверяем, содержит ли build скрипт генерацию превью
92
+ if (currentBuildScript && !currentBuildScript.includes('generate-previews.js')) {
93
+ // Добавляем генерацию превью в build процесс
94
+ if (currentBuildScript.includes('astro build')) {
95
+ userPackageData.scripts.build = currentBuildScript.replace(
96
+ 'astro build',
97
+ 'node scripts/generate-previews.js && astro build'
98
+ );
99
+ updated = true;
100
+ console.log('📦 Added generate-previews.js to build script');
101
+ }
102
+ }
103
+ }
104
+
105
+ if (updated) {
106
+ await fs.writeFile(userPackageJsonPath, JSON.stringify(userPackageData, null, 2) + '\n', 'utf-8');
107
+ console.log(`📦 Updated package.json with version ^${newVersion}`);
108
+ } else {
109
+ console.log(`📦 Package.json already up to date`);
110
+ }
111
+ } catch (error) {
112
+ if (error.code === 'ENOENT') {
113
+ console.log('📦 User package.json not found, skipping version update');
114
+ } else {
115
+ console.warn('Warning: Could not update package.json version:', error.message);
116
+ }
117
+ }
118
+ } catch (error) {
119
+ console.warn('Warning: Could not read package version:', error.message);
120
+ }
121
+ }
122
+
44
123
  async function copyDirectory(src, dest) {
45
124
  try {
46
125
  await fs.mkdir(dest, { recursive: true });
@@ -102,12 +181,18 @@ async function updateStyles() {
102
181
  async function updateComponents() {
103
182
  console.log('🔄 Updating Maugli components and assets...');
104
183
 
105
- // Проверяем, что мы не в том же проекте (чтобы не удалить исходники)
106
- if (packageRoot === userRoot) {
184
+ // Проверяем, что мы не в исходном проекте (чтобы не удалить исходники)
185
+ if (isSourceProject) {
107
186
  console.log('⚠️ Skipping component update (running in source project)');
108
187
  return;
109
188
  }
110
189
 
190
+ // Дополнительная проверка
191
+ if (packageRoot === userRoot) {
192
+ console.log('⚠️ Skipping component update (packageRoot equals userRoot)');
193
+ return;
194
+ }
195
+
111
196
  let updatedCount = 0;
112
197
 
113
198
  for (const updatePath of FORCE_UPDATE_PATHS) {
@@ -145,6 +230,9 @@ async function updateComponents() {
145
230
  // Обрабатываем стили отдельно
146
231
  await updateStyles();
147
232
 
233
+ // Обновляем версию в конфиге
234
+ await updateConfigVersion();
235
+
148
236
  console.log(`✅ Updated ${updatedCount} component directories/files`);
149
237
  }
150
238
 
@@ -93,7 +93,7 @@ async function main() {
93
93
  const defText = await fs.readFile(defaultConfigPath, 'utf8');
94
94
  const headerEnd = defText.indexOf('export const maugliConfig');
95
95
  let header = defText.slice(0, headerEnd);
96
- header = header.replace(/MAUGLI_CONFIG_VERSION\s*=\s*['\"][^'\"]*['\"]/, `MAUGLI_CONFIG_VERSION = '${newVersion}'`);
96
+ // Не обновляем MAUGLI_CONFIG_VERSION автоматически - только вручную при добавлении новых полей
97
97
  let bracePos = defText.indexOf('{', headerEnd);
98
98
  let count = 0,
99
99
  i = bracePos;
@@ -0,0 +1,126 @@
1
+ {
2
+ "buttons": {
3
+ "share": "Teilen",
4
+ "subscribe": "Abonnieren",
5
+ "moreAboutProduct": "Mehr über das Produkt",
6
+ "copied": "Kopiert!",
7
+ "copyLink": "Link kopieren",
8
+ "copyLinkToArticle": "Link zum Artikel kopieren",
9
+ "morePosts": "Weitere Artikel"
10
+ },
11
+ "form": {
12
+ "emailPlaceholder": "E-Mail",
13
+ "emailLabel": "E-Mail",
14
+ "subscribeAriaLabel": "Abonnement-Formular"
15
+ },
16
+
17
+ "nav": {
18
+ "blog": "Blog",
19
+ "products": "Produkte",
20
+ "projects": "Fälle",
21
+ "authors": "Autoren",
22
+ "tags": "Kategorien",
23
+ "openMenu": "Menü öffnen",
24
+ "closeMenu": "Menü schließen"
25
+ },
26
+ "pages": {
27
+ "authors": {
28
+ "title": "Autoren",
29
+ "description": "Lernen Sie unser Expertenteam kennen, das für {brand} schreibt",
30
+ "goToAuthor": "Zum Autor gehen",
31
+ "avatarAlt": "Avatar",
32
+ "onPlatform": "auf"
33
+ },
34
+ "tags": {
35
+ "title": "Kategorien",
36
+ "description": "Alle Artikel nach Kategorie",
37
+ "blogRubrics": "Blog-Kategorien"
38
+ },
39
+ "index": {
40
+ "title": "<Blog>",
41
+ "description": "Blog über Automatisierung aus Sicht der KI",
42
+ "articles": "Artikel",
43
+ "minutes": "Min"
44
+ },
45
+ "products": {
46
+ "title": "Produkte",
47
+ "description": "Alle Maugli-Produkte"
48
+ },
49
+ "projects": {
50
+ "tagTitle": "Services nach Tag",
51
+ "title": "Services"
52
+ },
53
+ "blog": {
54
+ "moreByTag": "Mehr zum Thema"
55
+ },
56
+ "productsId": {
57
+ "articlesByTag": "Artikel zum Thema",
58
+ "casesByTag": "Fälle zum Thema"
59
+ }
60
+ },
61
+ "socials": {
62
+ "email": "E-Mail",
63
+ "linkedin": "LinkedIn",
64
+ "twitter": "Twitter",
65
+ "telegram": "Telegram",
66
+ "reddit": "Reddit",
67
+ "medium": "Medium",
68
+ "mastodon": "Mastodon",
69
+ "bluesky": "Bluesky"
70
+ },
71
+ "footer": {
72
+ "allRightsReserved": "Alle Rechte vorbehalten"
73
+ },
74
+ "shareIconAriaLabel": {
75
+ "twitter": "Auf Twitter teilen",
76
+ "copy": "Link kopieren",
77
+ "telegram": "Auf Telegram teilen",
78
+ "linkedin": "Auf LinkedIn teilen",
79
+ "whatsapp": "Auf WhatsApp teilen",
80
+ "facebook": "Auf Facebook teilen",
81
+ "copied": "Link kopiert"
82
+ },
83
+ "date": {
84
+ "today": "heute",
85
+ "yesterday": "gestern"
86
+ },
87
+ "sidebarAriaLabel": "Seitenleiste",
88
+ "summaryFAQCard": {
89
+ "ariaLabel": "Zusammenfassung und FAQ",
90
+ "summaryLabel": "Zusammenfassung:",
91
+ "faqLabel": "FAQ:"
92
+ },
93
+ "tableOfContents": {
94
+ "title": "Inhalt",
95
+ "ariaLabel": "Inhalt"
96
+ },
97
+ "tagPill": {
98
+ "ariaLabel": "Tag: {tag}"
99
+ },
100
+ "tagPills": {
101
+ "ariaLabel": "Tag: {name} ({count})"
102
+ },
103
+ "tagsSection": {
104
+ "allCases": "Alle Fälle",
105
+ "allArticles": "Alle Artikel",
106
+ "allTags": "Alle Tags",
107
+ "rubricAlt": "Kategorie",
108
+ "tagAriaLabel": "Tag: {name} ({count})"
109
+ },
110
+ "themeToggle": {
111
+ "ariaLabel": "Farbschema wechseln"
112
+ },
113
+ "pagination": {
114
+ "goToPage": "Gehe zu Seite {page} von {lastPage}",
115
+ "pageOf": "Seite {currentPage} von {lastPage}"
116
+ },
117
+ "subscribe": {
118
+ "heading": "Abonniere für Updates",
119
+ "mutedText": "Erhalte die neuesten Artikel und Nachrichten zuerst!"
120
+ },
121
+ "notFound": {
122
+ "title": "Seite nicht gefunden",
123
+ "description": "Entschuldigung, diese Seite existiert nicht oder wurde entfernt.",
124
+ "button": "Zur Hauptseite"
125
+ }
126
+ }
@@ -0,0 +1,126 @@
1
+ {
2
+ "buttons": {
3
+ "share": "Share",
4
+ "subscribe": "Subscribe",
5
+ "moreAboutProduct": "More about the product",
6
+ "copied": "Copied!",
7
+ "copyLink": "Copy link",
8
+ "copyLinkToArticle": "Copy link to article",
9
+ "morePosts": "More posts"
10
+ },
11
+ "form": {
12
+ "emailPlaceholder": "email",
13
+ "emailLabel": "Email",
14
+ "subscribeAriaLabel": "Subscription form"
15
+ },
16
+
17
+ "nav": {
18
+ "blog": "Blog",
19
+ "products": "Products",
20
+ "projects": "Cases",
21
+ "authors": "Authors",
22
+ "tags": "Topics",
23
+ "openMenu": "Open menu",
24
+ "closeMenu": "Close menu"
25
+ },
26
+ "pages": {
27
+ "authors": {
28
+ "title": "Authors",
29
+ "description": "Meet our team of experts writing for {brand}",
30
+ "goToAuthor": "Go to author",
31
+ "avatarAlt": "Avatar",
32
+ "onPlatform": "on"
33
+ },
34
+ "tags": {
35
+ "title": "Categories",
36
+ "description": "All articles by category",
37
+ "blogRubrics": "Blog categories"
38
+ },
39
+ "index": {
40
+ "title": "<Blog>",
41
+ "description": "Blog about automation through AI's eyes",
42
+ "articles": "Articles",
43
+ "minutes": "min"
44
+ },
45
+ "products": {
46
+ "title": "Products",
47
+ "description": "All Maugli products"
48
+ },
49
+ "projects": {
50
+ "tagTitle": "Services by tag",
51
+ "title": "Services"
52
+ },
53
+ "blog": {
54
+ "moreByTag": "More on the topic"
55
+ },
56
+ "productsId": {
57
+ "articlesByTag": "Articles on the topic",
58
+ "casesByTag": "Cases on the topic"
59
+ }
60
+ },
61
+ "socials": {
62
+ "email": "email",
63
+ "linkedin": "LinkedIn",
64
+ "twitter": "Twitter",
65
+ "telegram": "Telegram",
66
+ "reddit": "Reddit",
67
+ "medium": "Medium",
68
+ "mastodon": "Mastodon",
69
+ "bluesky": "Bluesky"
70
+ },
71
+ "footer": {
72
+ "allRightsReserved": "All rights reserved"
73
+ },
74
+ "shareIconAriaLabel": {
75
+ "twitter": "Share on Twitter",
76
+ "copy": "Copy link",
77
+ "telegram": "Share on Telegram",
78
+ "linkedin": "Share on LinkedIn",
79
+ "whatsapp": "Share on WhatsApp",
80
+ "facebook": "Share on Facebook",
81
+ "copied": "Link copied"
82
+ },
83
+ "date": {
84
+ "today": "today",
85
+ "yesterday": "yesterday"
86
+ },
87
+ "sidebarAriaLabel": "Sidebar",
88
+ "summaryFAQCard": {
89
+ "ariaLabel": "Summary and FAQ",
90
+ "summaryLabel": "Summary:",
91
+ "faqLabel": "FAQ:"
92
+ },
93
+ "tableOfContents": {
94
+ "title": "Contents",
95
+ "ariaLabel": "Contents"
96
+ },
97
+ "tagPill": {
98
+ "ariaLabel": "Tag: {tag}"
99
+ },
100
+ "tagPills": {
101
+ "ariaLabel": "Tag: {name} ({count})"
102
+ },
103
+ "tagsSection": {
104
+ "allCases": "All cases",
105
+ "allArticles": "All articles",
106
+ "allTags": "All tags",
107
+ "rubricAlt": "Category",
108
+ "tagAriaLabel": "Tag: {name} ({count})"
109
+ },
110
+ "themeToggle": {
111
+ "ariaLabel": "Change color scheme"
112
+ },
113
+ "pagination": {
114
+ "goToPage": "Go to page {page} of {lastPage}",
115
+ "pageOf": "Page {currentPage} of {lastPage}"
116
+ },
117
+ "subscribe": {
118
+ "heading": "Subscribe for updates",
119
+ "mutedText": "Get the latest articles and news first!"
120
+ },
121
+ "notFound": {
122
+ "title": "Page not found",
123
+ "description": "Sorry, this page does not exist or has been removed.",
124
+ "button": "Go to main page"
125
+ }
126
+ }
@@ -0,0 +1,126 @@
1
+ {
2
+ "buttons": {
3
+ "share": "Compartir",
4
+ "subscribe": "Suscribirse",
5
+ "moreAboutProduct": "Más sobre el producto",
6
+ "copied": "¡Copiado!",
7
+ "copyLink": "Copiar enlace",
8
+ "copyLinkToArticle": "Copiar enlace al artículo",
9
+ "morePosts": "Más artículos"
10
+ },
11
+ "form": {
12
+ "emailPlaceholder": "correo",
13
+ "emailLabel": "Correo electrónico",
14
+ "subscribeAriaLabel": "Formulario de suscripción"
15
+ },
16
+
17
+ "nav": {
18
+ "blog": "Blog",
19
+ "products": "Productos",
20
+ "projects": "Casos",
21
+ "authors": "Autores",
22
+ "tags": "Categorías",
23
+ "openMenu": "Abrir menú",
24
+ "closeMenu": "Cerrar menú"
25
+ },
26
+ "pages": {
27
+ "authors": {
28
+ "title": "Autores",
29
+ "description": "Conoce a nuestro equipo de expertos que escriben para {brand}",
30
+ "goToAuthor": "Ir al autor",
31
+ "avatarAlt": "Avatar",
32
+ "onPlatform": "en"
33
+ },
34
+ "tags": {
35
+ "title": "Categorías",
36
+ "description": "Todos los artículos por categoría",
37
+ "blogRubrics": "Categorías del blog"
38
+ },
39
+ "index": {
40
+ "title": "<Blog>",
41
+ "description": "Blog sobre automatización desde la perspectiva de la IA",
42
+ "articles": "Artículos",
43
+ "minutes": "min"
44
+ },
45
+ "products": {
46
+ "title": "Productos",
47
+ "description": "Todos los productos de Maugli"
48
+ },
49
+ "projects": {
50
+ "tagTitle": "Servicios por etiqueta",
51
+ "title": "Servicios"
52
+ },
53
+ "blog": {
54
+ "moreByTag": "Más sobre el tema"
55
+ },
56
+ "productsId": {
57
+ "articlesByTag": "Artículos sobre el tema",
58
+ "casesByTag": "Casos sobre el tema"
59
+ }
60
+ },
61
+ "socials": {
62
+ "email": "correo",
63
+ "linkedin": "LinkedIn",
64
+ "twitter": "Twitter",
65
+ "telegram": "Telegram",
66
+ "reddit": "Reddit",
67
+ "medium": "Medium",
68
+ "mastodon": "Mastodon",
69
+ "bluesky": "Bluesky"
70
+ },
71
+ "footer": {
72
+ "allRightsReserved": "Todos los derechos reservados"
73
+ },
74
+ "shareIconAriaLabel": {
75
+ "twitter": "Compartir en Twitter",
76
+ "copy": "Copiar enlace",
77
+ "telegram": "Compartir en Telegram",
78
+ "linkedin": "Compartir en LinkedIn",
79
+ "whatsapp": "Compartir en WhatsApp",
80
+ "facebook": "Compartir en Facebook",
81
+ "copied": "Enlace copiado"
82
+ },
83
+ "date": {
84
+ "today": "hoy",
85
+ "yesterday": "ayer"
86
+ },
87
+ "sidebarAriaLabel": "Barra lateral",
88
+ "summaryFAQCard": {
89
+ "ariaLabel": "Resumen y FAQ",
90
+ "summaryLabel": "Resumen:",
91
+ "faqLabel": "FAQ:"
92
+ },
93
+ "tableOfContents": {
94
+ "title": "Contenido",
95
+ "ariaLabel": "Contenido"
96
+ },
97
+ "tagPill": {
98
+ "ariaLabel": "Etiqueta: {tag}"
99
+ },
100
+ "tagPills": {
101
+ "ariaLabel": "Etiqueta: {name} ({count})"
102
+ },
103
+ "tagsSection": {
104
+ "allCases": "Todos los casos",
105
+ "allArticles": "Todos los artículos",
106
+ "allTags": "Todas las etiquetas",
107
+ "rubricAlt": "Categoría",
108
+ "tagAriaLabel": "Etiqueta: {name} ({count})"
109
+ },
110
+ "themeToggle": {
111
+ "ariaLabel": "Cambiar esquema de color"
112
+ },
113
+ "pagination": {
114
+ "goToPage": "Ir a la página {page} de {lastPage}",
115
+ "pageOf": "Página {currentPage} de {lastPage}"
116
+ },
117
+ "subscribe": {
118
+ "heading": "Suscríbete para recibir actualizaciones",
119
+ "mutedText": "¡Recibe los últimos artículos y noticias primero!"
120
+ },
121
+ "notFound": {
122
+ "title": "Página no encontrada",
123
+ "description": "Lo sentimos, esta página no existe o ha sido eliminada.",
124
+ "button": "A la página principal"
125
+ }
126
+ }