@jjlmoya/utils-developer 1.6.0 → 1.8.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
CHANGED
package/src/category/i18n/ja.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { CategoryLocaleContent } from '../../types';
|
|
2
2
|
|
|
3
3
|
export const content: CategoryLocaleContent = {
|
|
4
|
-
slug: '
|
|
5
|
-
title: '
|
|
4
|
+
slug: 'uebu-kaihatsu-tools',
|
|
5
|
+
title: 'ウェブ開発',
|
|
6
6
|
description:
|
|
7
7
|
'フロントエンドおよびバックエンド開発者向けの無料Web開発ツール:フォーマッタ、CSS計算機、ジェネレーター、ユーティリティ。',
|
|
8
8
|
seo: [
|
package/src/category/i18n/ko.ts
CHANGED
package/src/category/i18n/ru.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CategoryLocaleContent } from '../../types';
|
|
2
2
|
|
|
3
3
|
export const content: CategoryLocaleContent = {
|
|
4
|
-
slug: '
|
|
4
|
+
slug: 'veb-razrabotka-util',
|
|
5
5
|
title: 'Веб разработка',
|
|
6
6
|
description:
|
|
7
7
|
'Бесплатные инструменты для веб-разработки: форматировщики, калькуляторы CSS, генераторы и утилиты для фронтенд- и бэкенд-разработчиков.',
|
package/src/category/i18n/zh.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { CategoryLocaleContent } from '../../types';
|
|
2
2
|
|
|
3
3
|
export const content: CategoryLocaleContent = {
|
|
4
|
-
slug: '
|
|
5
|
-
title: '
|
|
4
|
+
slug: 'wang-ye-kaifa',
|
|
5
|
+
title: '网页开发',
|
|
6
6
|
description:
|
|
7
7
|
'免费Web开发工具:面向前后端开发者的代码格式化、CSS计算器、生成器及实用工具。',
|
|
8
8
|
seo: [
|
package/src/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ export type {
|
|
|
15
15
|
ToolDefinition,
|
|
16
16
|
} from './types';
|
|
17
17
|
|
|
18
|
-
export { ALL_TOOLS } from './tools';
|
|
18
|
+
export { ALL_ENTRIES, ALL_TOOLS } from './tools';
|
|
19
19
|
|
|
20
20
|
export { JsonFormatterComponent, JsonFormatterSEO, JsonFormatterBibliography } from './tool/jsonFormatter/index';
|
|
21
21
|
export { JSON_FORMATTER_TOOL } from './tool/jsonFormatter/index';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { developerCategory as toolsCategory } from '../category/index';
|
|
3
|
+
import type { CategoryLocaleContent } from '../types';
|
|
4
|
+
|
|
5
|
+
const EXPECTED_LOCALES = [
|
|
6
|
+
'de', 'en', 'es', 'fr', 'id', 'it', 'ja', 'ko', 'nl', 'pl', 'pt', 'ru', 'sv', 'tr', 'zh'
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
const sharingLocales: string[] = [];
|
|
10
|
+
|
|
11
|
+
describe('Category Validation', () => {
|
|
12
|
+
it('should have all 15 required locales', () => {
|
|
13
|
+
const registeredLocales = Object.keys(toolsCategory.i18n);
|
|
14
|
+
EXPECTED_LOCALES.forEach((locale) => {
|
|
15
|
+
expect(
|
|
16
|
+
registeredLocales,
|
|
17
|
+
`Category is missing locale "${locale}"`,
|
|
18
|
+
).toContain(locale);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe('Category Slug Validation', () => {
|
|
23
|
+
it('every locale should have a unique, translated slug and follow format rules', async () => {
|
|
24
|
+
const slugs = new Map<string, string>();
|
|
25
|
+
const locales = Object.keys(toolsCategory.i18n);
|
|
26
|
+
|
|
27
|
+
let enSlug = '';
|
|
28
|
+
if (locales.includes('en')) {
|
|
29
|
+
const enLoader = toolsCategory.i18n['en' as keyof typeof toolsCategory.i18n];
|
|
30
|
+
const enContent = (await enLoader?.()) as CategoryLocaleContent;
|
|
31
|
+
enSlug = enContent.slug;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
for (const locale of locales) {
|
|
35
|
+
const loader = toolsCategory.i18n[locale as keyof typeof toolsCategory.i18n];
|
|
36
|
+
const content = (await loader?.()) as CategoryLocaleContent;
|
|
37
|
+
|
|
38
|
+
expect(
|
|
39
|
+
content.slug,
|
|
40
|
+
`Category locale "${locale}" has an invalid slug ("${content.slug}"). Slugs must be transliterated (only a-z, 0-9, and -).`,
|
|
41
|
+
).toMatch(/^[a-z0-9-]+$/);
|
|
42
|
+
|
|
43
|
+
expect(
|
|
44
|
+
content.slug,
|
|
45
|
+
`Category locale "${locale}" slug ("${content.slug}") cannot end with a 2-letter language code (e.g., -ja, -ru, -ko).`,
|
|
46
|
+
).not.toMatch(/-[a-z]{2}$/);
|
|
47
|
+
|
|
48
|
+
if (locale !== 'en') {
|
|
49
|
+
if (sharingLocales.includes(locale)) {
|
|
50
|
+
expect(
|
|
51
|
+
content.slug,
|
|
52
|
+
`Category locale "${locale}" must use the same slug as "en" ("${enSlug}").`,
|
|
53
|
+
).toBe(enSlug);
|
|
54
|
+
} else {
|
|
55
|
+
expect(
|
|
56
|
+
content.slug,
|
|
57
|
+
`Category locale "${locale}" has the same slug as "en" ("${enSlug}"). Cada slug tiene que estar en su propio idioma`,
|
|
58
|
+
).not.toBe(enSlug);
|
|
59
|
+
|
|
60
|
+
if (slugs.has(content.slug)) {
|
|
61
|
+
const previousLocale = slugs.get(content.slug);
|
|
62
|
+
expect(
|
|
63
|
+
false,
|
|
64
|
+
`Category locales "${locale}" and "${previousLocale}" share the same slug ("${content.slug}"). Cada slug tiene que estar en su propia idioma`,
|
|
65
|
+
).toBe(true);
|
|
66
|
+
}
|
|
67
|
+
slugs.set(content.slug, locale);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
package/src/tools.ts
CHANGED
|
@@ -25,3 +25,5 @@ import { CALCULADORA_TIEMPO_DATOS_TOOL } from './tool/calculadoraTiempoDatos/ind
|
|
|
25
25
|
import { CONVERSOR_EXCEL_CSV_HTML_TOOL } from './tool/conversorExcelCsvHtml/index';
|
|
26
26
|
|
|
27
27
|
export const ALL_TOOLS: ToolDefinition[] = [JSON_FORMATTER_TOOL, SVG_TO_CSS_TOOL, ASPECT_RATIO_TOOL, PLACEHOLDER_GENERATOR_TOOL, URL_ENCODER_DECODER_TOOL, DUPLICATE_CSS_REMOVER_TOOL, CSS_TO_INLINE_CONVERTER_TOOL, CSS_SPECIFICITY_CALCULATOR_TOOL, CRON_GENERATOR_TOOL, KEYCODE_TOOL, LLM_COST_CALCULATOR_TOOL, MUSICAL_TYPOGRAPHY_TOOL, MOBILE_MOCKUP_GENERATOR_TOOL, HASH_GENERATOR_TOOL, PROMPT_LIBRARY_TOOL, COLOR_CONVERTER_TOOL, READABILITY_CALCULATOR_TOOL, SVG_SANITIZER_TOOL, UTM_GENERATOR_TOOL, URL_CLEANER_TOOL, INSPECTOR_CERTIFICADOS_SSL_TOOL, GENERADOR_SECURITY_TXT_TOOL, CALCULADORA_TIEMPO_DATOS_TOOL, CONVERSOR_EXCEL_CSV_HTML_TOOL];
|
|
28
|
+
|
|
29
|
+
export const ALL_ENTRIES = ALL_TOOLS.map(t => t.entry);
|