@jjlmoya/utils-shared 1.0.2 → 1.2.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.
- package/package.json +7 -2
- package/src/i18n.translations.ts +30 -0
- package/src/i18n.ts +41 -0
- package/src/index.ts +1 -0
- package/src/seo/SEODiagnostic.astro +9 -6
- package/src/seo/SEOProsCons.astro +6 -3
- package/src/seo/SEORenderer.astro +1 -1
- package/src/types/index.ts +2 -2
- package/src/ui/Bibliography.astro +5 -2
- package/src/ui/FAQSection.astro +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jjlmoya/utils-shared",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Shared SEO primitives and UI components for jjlmoya ecosystem",
|
|
5
5
|
"author": "jjlmoya",
|
|
6
6
|
"license": "MIT",
|
|
@@ -32,7 +32,12 @@
|
|
|
32
32
|
"lint": "eslint src --ext .ts,.astro",
|
|
33
33
|
"lint:css": "stylelint \"src/**/*.{astro,css}\"",
|
|
34
34
|
"lint:all": "npm run check && npm run lint && npm run lint:css",
|
|
35
|
-
"prepublishOnly": "npm run lint:all"
|
|
35
|
+
"prepublishOnly": "npm run lint:all",
|
|
36
|
+
"preversion": "npm run lint:all",
|
|
37
|
+
"postversion": "git push && git push --tags",
|
|
38
|
+
"patch": "npm version patch",
|
|
39
|
+
"minor": "npm version minor",
|
|
40
|
+
"major": "npm version major"
|
|
36
41
|
},
|
|
37
42
|
"peerDependencies": {
|
|
38
43
|
"@iconify-json/mdi": "^1.0.0",
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Language } from "./i18n";
|
|
2
|
+
|
|
3
|
+
export type TranslationKeys = {
|
|
4
|
+
bibliographicReferences: string;
|
|
5
|
+
faq: string;
|
|
6
|
+
pros: string;
|
|
7
|
+
cons: string;
|
|
8
|
+
diagWarning: string;
|
|
9
|
+
diagError: string;
|
|
10
|
+
diagInfo: string;
|
|
11
|
+
diagSuccess: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const translations: Record<Language, TranslationKeys> = {
|
|
15
|
+
es: { bibliographicReferences: "Referencias Bibliográficas", faq: "Preguntas Frecuentes", pros: "Ventajas", cons: "Desventajas", diagWarning: "Advertencia", diagError: "Problema crítico", diagInfo: "A tener en cuenta", diagSuccess: "Buena práctica" },
|
|
16
|
+
en: { bibliographicReferences: "Bibliographic References", faq: "Frequently Asked Questions", pros: "Advantages", cons: "Disadvantages", diagWarning: "Warning", diagError: "Critical issue", diagInfo: "Worth noting", diagSuccess: "Best practice" },
|
|
17
|
+
fr: { bibliographicReferences: "Références Bibliographiques", faq: "Questions Fréquemment Posées", pros: "Avantages", cons: "Inconvénients", diagWarning: "Avertissement", diagError: "Problème critique", diagInfo: "À noter", diagSuccess: "Bonne pratique" },
|
|
18
|
+
nl: { bibliographicReferences: "Bibliografische Referenties", faq: "Veelgestelde Vragen", pros: "Voordelen", cons: "Nadelen", diagWarning: "Waarschuwing", diagError: "Kritiek probleem", diagInfo: "Let op", diagSuccess: "Best practice" },
|
|
19
|
+
de: { bibliographicReferences: "Bibliographische Referenzen", faq: "Häufig Gestellte Fragen", pros: "Vorteile", cons: "Nachteile", diagWarning: "Warnung", diagError: "Kritisches Problem", diagInfo: "Zu beachten", diagSuccess: "Bewährte Methode" },
|
|
20
|
+
it: { bibliographicReferences: "Riferimenti Bibliografici", faq: "Domande Frequenti", pros: "Vantaggi", cons: "Svantaggi", diagWarning: "Avviso", diagError: "Problema critico", diagInfo: "Da tenere a mente", diagSuccess: "Buona pratica" },
|
|
21
|
+
pt: { bibliographicReferences: "Referências Bibliográficas", faq: "Perguntas Frequentes", pros: "Vantagens", cons: "Desvantagens", diagWarning: "Aviso", diagError: "Problema crítico", diagInfo: "A ter em conta", diagSuccess: "Boa prática" },
|
|
22
|
+
ja: { bibliographicReferences: "参考文献", faq: "よくある質問", pros: "メリット", cons: "デメリット", diagWarning: "警告", diagError: "重大な問題", diagInfo: "注意事項", diagSuccess: "ベストプラクティス" },
|
|
23
|
+
zh: { bibliographicReferences: "参考文献", faq: "常见问题", pros: "优点", cons: "缺点", diagWarning: "警告", diagError: "严重问题", diagInfo: "注意事项", diagSuccess: "最佳实践" },
|
|
24
|
+
ko: { bibliographicReferences: "참고 문헌", faq: "자주 묻는 질문", pros: "장점", cons: "단점", diagWarning: "경고", diagError: "심각한 문제", diagInfo: "참고 사항", diagSuccess: "모범 사례" },
|
|
25
|
+
ru: { bibliographicReferences: "Библиографические ссылки", faq: "Часто задаваемые вопросы", pros: "Преимущества", cons: "Недостатки", diagWarning: "Предупреждение", diagError: "Критическая проблема", diagInfo: "Важно учесть", diagSuccess: "Хорошая практика" },
|
|
26
|
+
pl: { bibliographicReferences: "Referencje Bibliograficzne", faq: "Najczęściej Zadawane Pytania", pros: "Zalety", cons: "Wady", diagWarning: "Ostrzeżenie", diagError: "Krytyczny problem", diagInfo: "Warto wiedzieć", diagSuccess: "Dobra praktyka" },
|
|
27
|
+
tr: { bibliographicReferences: "Bibliyografik Referanslar", faq: "Sıkça Sorulan Sorular", pros: "Avantajlar", cons: "Dezavantajlar", diagWarning: "Uyarı", diagError: "Kritik sorun", diagInfo: "Dikkat edilmesi gereken", diagSuccess: "En iyi uygulama" },
|
|
28
|
+
sv: { bibliographicReferences: "Bibliografiska Referenser", faq: "Vanliga Frågor", pros: "Fördelar", cons: "Nackdelar", diagWarning: "Varning", diagError: "Kritiskt problem", diagInfo: "Värt att notera", diagSuccess: "Bästa praxis" },
|
|
29
|
+
hi: { bibliographicReferences: "ग्रंथ सूची संदर्भ", faq: "अक्सर पूछे जाने वाले प्रश्न", pros: "फायदे", cons: "नुकसान", diagWarning: "चेतावनी", diagError: "गंभीर समस्या", diagInfo: "ध्यान देने योग्य", diagSuccess: "सर्वोत्तम अभ्यास" },
|
|
30
|
+
};
|
package/src/i18n.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { translations } from "./i18n.translations";
|
|
2
|
+
|
|
3
|
+
export { translations };
|
|
4
|
+
export type { TranslationKeys } from "./i18n.translations";
|
|
5
|
+
|
|
6
|
+
export const languages = {
|
|
7
|
+
es: "Español",
|
|
8
|
+
en: "English",
|
|
9
|
+
fr: "Français",
|
|
10
|
+
nl: "Nederlands",
|
|
11
|
+
de: "Deutsch",
|
|
12
|
+
it: "Italiano",
|
|
13
|
+
pt: "Português",
|
|
14
|
+
ja: "日本語",
|
|
15
|
+
zh: "中文",
|
|
16
|
+
ko: "한국어",
|
|
17
|
+
ru: "Русский",
|
|
18
|
+
pl: "Polski",
|
|
19
|
+
tr: "Türkçe",
|
|
20
|
+
sv: "Svenska",
|
|
21
|
+
hi: "हिन्दी",
|
|
22
|
+
} as const;
|
|
23
|
+
|
|
24
|
+
export type Language = keyof typeof languages;
|
|
25
|
+
|
|
26
|
+
export const defaultLanguage: Language = "es";
|
|
27
|
+
|
|
28
|
+
export const getLanguageFromUrl = (url: URL | string): Language => {
|
|
29
|
+
const pathname = typeof url === "string" ? url : url.pathname;
|
|
30
|
+
const firstSegment = pathname.split("/").filter(Boolean)[0];
|
|
31
|
+
|
|
32
|
+
if (firstSegment && firstSegment in languages) {
|
|
33
|
+
return firstSegment as Language;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return defaultLanguage;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const getTranslation = (language: Language, key: keyof (typeof translations)[Language]): string => {
|
|
40
|
+
return translations[language]?.[key] || translations[defaultLanguage][key];
|
|
41
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { Icon } from "astro-icon/components";
|
|
3
|
+
import { getLanguageFromUrl, getTranslation } from "../i18n";
|
|
3
4
|
|
|
4
5
|
interface Props {
|
|
5
6
|
title: string;
|
|
@@ -10,14 +11,16 @@ interface Props {
|
|
|
10
11
|
|
|
11
12
|
const { title, icon, type = "info", badge } = Astro.props;
|
|
12
13
|
|
|
14
|
+
const language = getLanguageFromUrl(Astro.url);
|
|
15
|
+
|
|
13
16
|
const typeConfig = {
|
|
14
|
-
warning: { color: "var(--color-warning)", badgeText: badge ?? "
|
|
15
|
-
error: { color: "var(--color-error)",
|
|
16
|
-
info: { color: "var(--color-info)",
|
|
17
|
-
success: { color: "var(--color-success)",
|
|
18
|
-
}
|
|
17
|
+
warning: { color: "var(--color-warning)", badgeText: badge ?? getTranslation(language, "diagWarning") },
|
|
18
|
+
error: { color: "var(--color-error)", badgeText: badge ?? getTranslation(language, "diagError") },
|
|
19
|
+
info: { color: "var(--color-info)", badgeText: badge ?? getTranslation(language, "diagInfo") },
|
|
20
|
+
success: { color: "var(--color-success)", badgeText: badge ?? getTranslation(language, "diagSuccess") },
|
|
21
|
+
};
|
|
19
22
|
|
|
20
|
-
const cfg = typeConfig[type
|
|
23
|
+
const cfg = typeConfig[type];
|
|
21
24
|
---
|
|
22
25
|
|
|
23
26
|
<div class={`seo-diagnostic is-${type}`}>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { Icon } from "astro-icon/components";
|
|
3
|
+
import { getLanguageFromUrl, getTranslation } from "../i18n";
|
|
3
4
|
|
|
4
5
|
interface ProsConsItem {
|
|
5
6
|
pro: string;
|
|
@@ -9,11 +10,13 @@ interface ProsConsItem {
|
|
|
9
10
|
interface Props {
|
|
10
11
|
title?: string | undefined;
|
|
11
12
|
items: ProsConsItem[];
|
|
12
|
-
proTitle?: string | undefined;
|
|
13
|
-
conTitle?: string | undefined;
|
|
14
13
|
}
|
|
15
14
|
|
|
16
|
-
const { title, items
|
|
15
|
+
const { title, items } = Astro.props;
|
|
16
|
+
|
|
17
|
+
const language = getLanguageFromUrl(Astro.url);
|
|
18
|
+
const proTitle = getTranslation(language, "pros");
|
|
19
|
+
const conTitle = getTranslation(language, "cons");
|
|
17
20
|
---
|
|
18
21
|
|
|
19
22
|
<div class="seo-proscons-box">
|
|
@@ -71,7 +71,7 @@ const { content } = Astro.props;
|
|
|
71
71
|
);
|
|
72
72
|
}
|
|
73
73
|
if (section.type === "proscons") {
|
|
74
|
-
return <SEOProsCons title={section.title} items={section.items}
|
|
74
|
+
return <SEOProsCons title={section.title} items={section.items} />;
|
|
75
75
|
}
|
|
76
76
|
if (section.type === "summary") {
|
|
77
77
|
return <SEOSummary title={section.title} items={section.items} />;
|
package/src/types/index.ts
CHANGED
|
@@ -34,7 +34,7 @@ export type SEOSection =
|
|
|
34
34
|
| { type: "table"; headers: string[]; rows: string[][] }
|
|
35
35
|
| { type: "tip"; title?: string; html: string }
|
|
36
36
|
| { type: "card"; icon?: string; title?: string; html: string }
|
|
37
|
-
| { type: "stats"; items: { value: string; label: string; icon?: string }[]; columns?: 2 | 3 | 4 }
|
|
37
|
+
| { type: "stats"; items: { value: string; label: string; icon?: string; trend?: { value: string; positive: boolean } }[]; columns?: 2 | 3 | 4 }
|
|
38
38
|
| { type: "glossary"; items: { term: string; definition: string }[] }
|
|
39
39
|
| { type: "code"; code: string; ariaLabel?: string }
|
|
40
40
|
| {
|
|
@@ -50,7 +50,7 @@ export type SEOSection =
|
|
|
50
50
|
columns?: 2 | 3;
|
|
51
51
|
}
|
|
52
52
|
| { type: "diagnostic"; variant: "warning" | "error" | "info" | "success"; title: string; icon?: string; badge?: string; html: string }
|
|
53
|
-
| { type: "proscons"; title?: string; items: { pro: string; con: string }[]
|
|
53
|
+
| { type: "proscons"; title?: string; items: { pro: string; con: string }[] }
|
|
54
54
|
| { type: "summary"; title: string; items: string[] }
|
|
55
55
|
| { type: "grid"; columns?: 1 | 2 | 3 | 4 }
|
|
56
56
|
| { type: "message"; title?: string; ariaLabel?: string; html: string };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { Icon } from "astro-icon/components";
|
|
3
|
+
import { getLanguageFromUrl, getTranslation } from "../i18n";
|
|
3
4
|
|
|
4
5
|
interface Link {
|
|
5
6
|
name: string;
|
|
@@ -8,10 +9,12 @@ interface Link {
|
|
|
8
9
|
|
|
9
10
|
interface Props {
|
|
10
11
|
links: Link[];
|
|
11
|
-
title?: string;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const { links = []
|
|
14
|
+
const { links = [] } = Astro.props;
|
|
15
|
+
|
|
16
|
+
const language = getLanguageFromUrl(Astro.url);
|
|
17
|
+
const title = getTranslation(language, "bibliographicReferences");
|
|
15
18
|
---
|
|
16
19
|
|
|
17
20
|
<div class="bibliography">
|
package/src/ui/FAQSection.astro
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
import { Icon } from "astro-icon/components";
|
|
3
|
+
import { getLanguageFromUrl, getTranslation } from "../i18n";
|
|
3
4
|
|
|
4
5
|
interface FAQItem {
|
|
5
6
|
question: string;
|
|
@@ -8,11 +9,13 @@ interface FAQItem {
|
|
|
8
9
|
|
|
9
10
|
interface Props {
|
|
10
11
|
items: FAQItem[];
|
|
11
|
-
title?: string;
|
|
12
|
-
inLanguage?: string;
|
|
13
12
|
}
|
|
14
13
|
|
|
15
|
-
const { items = []
|
|
14
|
+
const { items = [] } = Astro.props;
|
|
15
|
+
|
|
16
|
+
const language = getLanguageFromUrl(Astro.url);
|
|
17
|
+
const title = getTranslation(language, "faq");
|
|
18
|
+
const inLanguage = language === "es" ? "es-ES" : `${language}-${language.toUpperCase()}`;
|
|
16
19
|
|
|
17
20
|
const faqSchema = {
|
|
18
21
|
"@context": "https://schema.org",
|