@jjlmoya/utils-converters 1.8.0 → 1.10.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 +1 -1
- package/src/category/i18n/de.ts +90 -0
- package/src/category/i18n/id.ts +90 -0
- package/src/category/i18n/it.ts +90 -0
- package/src/category/i18n/ja.ts +90 -0
- package/src/category/i18n/ko.ts +90 -0
- package/src/category/i18n/nl.ts +90 -0
- package/src/category/i18n/pl.ts +90 -0
- package/src/category/i18n/pt.ts +90 -0
- package/src/category/i18n/ru.ts +90 -0
- package/src/category/i18n/sv.ts +90 -0
- package/src/category/i18n/tr.ts +90 -0
- package/src/category/i18n/zh.ts +90 -0
- package/src/category/index.ts +13 -1
- package/src/tests/category_validation.test.ts +73 -0
- package/src/tests/slug_language_code_format.test.ts +23 -0
- package/src/tests/slug_uniqueness.test.ts +81 -0
- package/src/tool/avifAJpg/i18n/ja.ts +1 -1
- package/src/tool/avifAJpg/i18n/ko.ts +1 -1
- package/src/tool/avifAJpg/i18n/zh.ts +1 -1
- package/src/tool/avifAPng/i18n/ja.ts +1 -1
- package/src/tool/avifAPng/i18n/ko.ts +1 -1
- package/src/tool/avifAPng/i18n/zh.ts +1 -1
- package/src/tool/avifAWebp/i18n/ja.ts +1 -1
- package/src/tool/avifAWebp/i18n/ko.ts +1 -1
- package/src/tool/avifAWebp/i18n/zh.ts +1 -1
- package/src/tool/bmpAJpg/i18n/ja.ts +1 -1
- package/src/tool/bmpAJpg/i18n/ko.ts +1 -1
- package/src/tool/bmpAJpg/i18n/zh.ts +1 -1
- package/src/tool/bmpAPng/i18n/ja.ts +1 -1
- package/src/tool/bmpAPng/i18n/ko.ts +1 -1
- package/src/tool/bmpAPng/i18n/zh.ts +1 -1
- package/src/tool/bmpAWebp/i18n/ja.ts +1 -1
- package/src/tool/bmpAWebp/i18n/ko.ts +1 -1
- package/src/tool/bmpAWebp/i18n/zh.ts +1 -1
- package/src/tool/gifAJpg/i18n/ja.ts +1 -1
- package/src/tool/gifAJpg/i18n/ko.ts +1 -1
- package/src/tool/gifAJpg/i18n/zh.ts +1 -1
- package/src/tool/gifAPng/i18n/ja.ts +1 -1
- package/src/tool/gifAPng/i18n/ko.ts +1 -1
- package/src/tool/gifAPng/i18n/zh.ts +1 -1
- package/src/tool/gifAWebp/i18n/ja.ts +1 -1
- package/src/tool/gifAWebp/i18n/ko.ts +1 -1
- package/src/tool/gifAWebp/i18n/zh.ts +1 -1
- package/src/tool/jpgAPng/i18n/ja.ts +1 -1
- package/src/tool/jpgAPng/i18n/ko.ts +1 -1
- package/src/tool/jpgAPng/i18n/zh.ts +1 -1
- package/src/tool/pngAJpg/i18n/ko.ts +1 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { convertersCategory 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 = ['ja', 'ko', 'zh'];
|
|
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
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ALL_TOOLS } from '../tools';
|
|
3
|
+
import type { ToolLocaleContent } from '../types';
|
|
4
|
+
|
|
5
|
+
describe('Slug Language Code Format Validation', () => {
|
|
6
|
+
ALL_TOOLS.forEach((tool) => {
|
|
7
|
+
describe(`Tool: ${tool.entry.id}`, () => {
|
|
8
|
+
it('slug should not end with 2-letter language codes like -ja, -ru, -ko', async () => {
|
|
9
|
+
const locales = Object.keys(tool.entry.i18n);
|
|
10
|
+
|
|
11
|
+
for (const locale of locales) {
|
|
12
|
+
const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
|
|
13
|
+
const content = (await loader?.()) as ToolLocaleContent;
|
|
14
|
+
|
|
15
|
+
expect(
|
|
16
|
+
content.slug,
|
|
17
|
+
`Tool "${tool.entry.id}" locale "${locale}" slug ("${content.slug}") cannot end with a 2-letter language code (e.g., -ja, -ru, -ko).`,
|
|
18
|
+
).not.toMatch(/-[a-z]{2}$/);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { ALL_TOOLS } from '../tools';
|
|
3
|
+
import type { ToolLocaleContent } from '../types';
|
|
4
|
+
|
|
5
|
+
const sharingLocales = ['ja', 'ko', 'zh'];
|
|
6
|
+
|
|
7
|
+
interface ValidateParams {
|
|
8
|
+
toolId: string;
|
|
9
|
+
locale: string;
|
|
10
|
+
content: ToolLocaleContent;
|
|
11
|
+
enSlug: string;
|
|
12
|
+
slugs: Map<string, string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const validateLocaleSlug = ({
|
|
16
|
+
toolId,
|
|
17
|
+
locale,
|
|
18
|
+
content,
|
|
19
|
+
enSlug,
|
|
20
|
+
slugs,
|
|
21
|
+
}: ValidateParams) => {
|
|
22
|
+
expect(
|
|
23
|
+
content.slug,
|
|
24
|
+
`Tool "${toolId}" locale "${locale}" has an invalid slug ("${content.slug}"). Slugs must be transliterated (only a-z, 0-9, and -).`,
|
|
25
|
+
).toMatch(/^[a-z0-9-]+$/);
|
|
26
|
+
|
|
27
|
+
if (locale === 'en') {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (sharingLocales.includes(locale)) {
|
|
32
|
+
expect(
|
|
33
|
+
content.slug,
|
|
34
|
+
`Tool "${toolId}" locale "${locale}" must use the same slug as "en" ("${enSlug}").`,
|
|
35
|
+
).toBe(enSlug);
|
|
36
|
+
} else {
|
|
37
|
+
expect(
|
|
38
|
+
content.slug,
|
|
39
|
+
`Tool "${toolId}" locale "${locale}" has the same slug as "en" ("${enSlug}"). Cada slug tiene que estar en su propia idioma`,
|
|
40
|
+
).not.toBe(enSlug);
|
|
41
|
+
|
|
42
|
+
if (slugs.has(content.slug)) {
|
|
43
|
+
const previousLocale = slugs.get(content.slug);
|
|
44
|
+
expect(
|
|
45
|
+
false,
|
|
46
|
+
`Tool "${toolId}" locales "${locale}" and "${previousLocale}" share the same slug ("${content.slug}"). Cada slug tiene que estar en su propia idioma`,
|
|
47
|
+
).toBe(true);
|
|
48
|
+
}
|
|
49
|
+
slugs.set(content.slug, locale);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
describe('Slug Localization and Uniqueness Validation', () => {
|
|
54
|
+
ALL_TOOLS.forEach((tool) => {
|
|
55
|
+
describe(`Tool: ${tool.entry.id}`, () => {
|
|
56
|
+
it('every locale should have a unique, translated slug', async () => {
|
|
57
|
+
const slugs = new Map<string, string>();
|
|
58
|
+
const locales = Object.keys(tool.entry.i18n);
|
|
59
|
+
|
|
60
|
+
let enSlug = '';
|
|
61
|
+
if (locales.includes('en')) {
|
|
62
|
+
const enLoader = tool.entry.i18n['en' as keyof typeof tool.entry.i18n];
|
|
63
|
+
const enContent = (await enLoader?.()) as ToolLocaleContent;
|
|
64
|
+
enSlug = enContent.slug;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (const locale of locales) {
|
|
68
|
+
const loader = tool.entry.i18n[locale as keyof typeof tool.entry.i18n];
|
|
69
|
+
const content = (await loader?.()) as ToolLocaleContent;
|
|
70
|
+
validateLocaleSlug({
|
|
71
|
+
toolId: tool.entry.id,
|
|
72
|
+
locale,
|
|
73
|
+
content,
|
|
74
|
+
enSlug,
|
|
75
|
+
slugs,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-jpg-converter';
|
|
6
6
|
const title = 'AVIFをJPGにオンラインで変換';
|
|
7
7
|
const description =
|
|
8
8
|
'お使いのブラウザでAVIF画像をJPGに変換します。サーバーを介さず、100%プライベートなローカル処理を行います。無料で無制限に使用できます。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-jpg-converter';
|
|
6
6
|
const title = 'AVIF를 JPG로 온라인 변환';
|
|
7
7
|
const description =
|
|
8
8
|
'브라우저에서 AVIF 이미지를 JPG로 변환하세요. 서버를 거치지 않는 100% 개인 로컬 처리 방식입니다. 무료이며 무제한으로 사용할 수 있습니다.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-jpg-converter';
|
|
6
6
|
const title = '在线将 AVIF 转换为 JPG';
|
|
7
7
|
const description =
|
|
8
8
|
'在浏览器中将 AVIF 图像转换为 JPG。无需服务器。100% 私密本地处理。免费且无限制。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-png-converter';
|
|
6
6
|
const title = 'AVIFをPNGにオンラインで変換';
|
|
7
7
|
const description =
|
|
8
8
|
'透明度を維持しながらAVIF画像をPNGに変換します。ファイルをアップロードする必要はありません。ブラウザ上でのローカル処理で、無料で無制限に使用できます。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-png-converter';
|
|
6
6
|
const title = 'AVIF를 PNG로 온라인 변환';
|
|
7
7
|
const description =
|
|
8
8
|
'투명도를 유지하면서 AVIF 이미지를 PNG로 변환하세요. 파일을 업로드할 필요가 없습니다. 브라우저에서의 로컬 처리 방식으로 무료이며 무제한으로 사용할 수 있습니다.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-png-converter';
|
|
6
6
|
const title = '在线将 AVIF 转换为 PNG';
|
|
7
7
|
const description =
|
|
8
8
|
'在保持透明度的同时,将 AVIF 图像转换为 PNG。无需上传文件。在您的浏览器中完成本地处理。免费且无限制。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-webp-converter';
|
|
6
6
|
const title = 'AVIFをWebPにオンラインで変換';
|
|
7
7
|
const description =
|
|
8
8
|
'互換性を高めるためにAVIF画像をWebPに変換します。サーバーを介さないローカル処理。無料でプライベート、かつ無制限に使用できます。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-webp-converter';
|
|
6
6
|
const title = 'AVIF를 WebP로 온라인 변환';
|
|
7
7
|
const description =
|
|
8
8
|
'호환성을 높이기 위해 AVIF 이미지를 WebP로 변환하세요. 서버 없는 로컬 처리 방식입니다. 무료이며 프라이빗하며 무제한으로 사용할 수 있습니다.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { AvifAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'avif-to-webp-converter';
|
|
6
6
|
const title = '在线将 AVIF 转换为 WebP';
|
|
7
7
|
const description =
|
|
8
8
|
'为了获得更好的兼容性,将 AVIF 图像转换为 WebP 格式。无需服务器,本地完成处理。免费、私密且无限制。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-jpg-converter';
|
|
6
6
|
const title = 'BMPをJPGにオンラインで変換';
|
|
7
7
|
const description =
|
|
8
8
|
'ブラウザ上でBMP画像をJPGに変換します。サイズを劇的に削減。サーバーへのファイルアップロードは不要。無料で100%プライベートに使用できます。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-jpg-converter';
|
|
6
6
|
const title = 'BMP를 JPG로 온라인 변환';
|
|
7
7
|
const description =
|
|
8
8
|
'브라우저에서 BMP 이미지를 JPG로 변환하세요. 파일 크기를 획기적으로 줄일 수 있습니다. 서버 업로드 없이 로컬에서 처리되어 무료이며 100% 안전합니다.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-jpg-converter';
|
|
6
6
|
const title = '在线将 BMP 转换为 JPG';
|
|
7
7
|
const description =
|
|
8
8
|
'在您的浏览器中将 BMP 图像转换为 JPG。大幅减小文件大小。无需将文件上传到服务器。免费且 100% 私密。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-png-converter';
|
|
6
6
|
const title = 'BMPからPNGへのコンバーター';
|
|
7
7
|
const description =
|
|
8
8
|
'BMP画像を品質を損なうことなくPNGに変換します。ノイズのないモダンな圧縮。ファイルのアップロードは不要。無料で100%プライベートに使用できます。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-png-converter';
|
|
6
6
|
const title = 'BMP PNG 변환기';
|
|
7
7
|
const description =
|
|
8
8
|
'품질 저하 없이 BMP 이미지를 PNG로 변환하세요. 노이즈 없는 현대적인 압축 기술. 파일 업로드 없음. 무료이며 100% 안전한 로컬 변환.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-png-converter';
|
|
6
6
|
const title = 'BMP 转 PNG 转换器';
|
|
7
7
|
const description =
|
|
8
8
|
'无损地将 BMP 图像转换为 PNG。现代压缩技术,无伪影。无需上传文件。免费且 100% 私密。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-webp-converter';
|
|
6
6
|
const title = 'BMPをWebPに無料で変換';
|
|
7
7
|
const description =
|
|
8
8
|
'BMP画像をオフラインでWebPに変換します。巨大なファイルをキロバイト単位に削減。ファイルのアップロードは不要。無料でオフライン、完全にプライベートに使用できます。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-webp-converter';
|
|
6
6
|
const title = 'BMP WebP 무료 변환기';
|
|
7
7
|
const description =
|
|
8
8
|
'BMP 이미지를 오프라인에서 WebP로 변환하세요. 방대한 파일을 킬로바이트 단위로 대폭 압축합니다. 파일 업로드 없음. 무료, 오프라인, 100% 안전한 로컬 처리.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { BmpAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'bmp-to-webp-converter';
|
|
6
6
|
const title = '免费将 BMP 转换为 WebP';
|
|
7
7
|
const description =
|
|
8
8
|
'离线将 BMP 图像转换为 WebP。将巨大文件缩减至千字节。无需上传文件。免费、离线且完全私密。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-jpg-converter';
|
|
6
6
|
const title = 'GIFをJPGにオンラインで変換';
|
|
7
7
|
const description =
|
|
8
8
|
'GIFファイルから最初のフレームを抽出してJPGに変換します。サーバーを介さず、ブラウザ内でローカル処理を行います。無料で無制限に使用できます。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-jpg-converter';
|
|
6
6
|
const title = 'GIF JPG 온라인 변환기';
|
|
7
7
|
const description =
|
|
8
8
|
'GIF 파일에서 첫 번째 프레임을 추출하여 JPG로 변환하세요. 서버 전송 없음. 브라우저 내 로컬 처리. 무료 및 무제한 이용 가능.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-jpg-converter';
|
|
6
6
|
const title = '在线将 GIF 转换为 JPG';
|
|
7
7
|
const description =
|
|
8
8
|
'从 GIF 中提取第一帧并将其转换为 JPG。无需服务器。在您的浏览器中进行本地处理。免费且无限制。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-png-converter';
|
|
6
6
|
const title = 'GIFをPNGにオンラインで変換';
|
|
7
7
|
const description =
|
|
8
8
|
'GIFファイルから最初のフレームを抽出し、透明度を維持したままPNGに変換します。サーバー不要。ブラウザ内ローカル処理。無料。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-png-converter';
|
|
6
6
|
const title = 'GIF PNG 온라인 변환기';
|
|
7
7
|
const description =
|
|
8
8
|
'GIF 파일에서 첫 번째 프레임을 추출하고 투명도를 유지하여 PNG로 변환하세요. 서버 필요 없음. 로컬 처리. 무료 이용 가능.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-png-converter';
|
|
6
6
|
const title = '在线将 GIF 转换为 PNG';
|
|
7
7
|
const description =
|
|
8
8
|
'从 GIF 中提取第一帧并将其转换为 PNG,同时保留透明度。无需服务器。本地处理。免费。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-webp-converter';
|
|
6
6
|
const title = 'GIFを静的WebPにオンライン変換';
|
|
7
7
|
const description =
|
|
8
8
|
'アニメーションGIFを静的WebPに変換します。透明度を維持。サーバー不要。ブラウザ内でローカルに処理。無料。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-webp-converter';
|
|
6
6
|
const title = 'GIF를 정적 WebP로 온라인 변환';
|
|
7
7
|
const description =
|
|
8
8
|
'애니메이션 GIF를 정적 WebP로 변환하세요. 투명도를 유지합니다. 서버 불필요. 브라우저에서 로컬로 처리됩니다. 무료.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { GifAWebpLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'gif-to-webp-converter';
|
|
6
6
|
const title = '在线将 GIF 转换为静态 WebP';
|
|
7
7
|
const description =
|
|
8
8
|
'将动态 GIF 转换为静态 WebP。保留透明度。无需服务器。在浏览器中本地处理。免费。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { JpgAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'jpg-to-png-converter';
|
|
6
6
|
const title = 'JPGをPNGにオンラインで無料で変換';
|
|
7
7
|
const description =
|
|
8
8
|
'ブラウザ上でファイルをアップロードせずにJPG画像をPNGに変換します。ロスレス変換、無料で完全にプライベートに使用できます。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { JpgAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'jpg-to-png-converter';
|
|
6
6
|
const title = 'JPG를 PNG로 온라인 무료 변환';
|
|
7
7
|
const description =
|
|
8
8
|
'파일 업로드 없이 브라우저에서 JPG 이미지를 PNG로 변환하세요. 로컬에서 처리되는 무손실 변환으로 무료이며 100% 안전합니다.';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { JpgAPngLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'jpg-to-png-converter';
|
|
6
6
|
const title = '在线免费将 JPG 转换为 PNG';
|
|
7
7
|
const description =
|
|
8
8
|
'在您的浏览器中完成 JPG 到 PNG 的转换,无需上传文件。无损转换、免费且完全私密。';
|
|
@@ -2,7 +2,7 @@ import type { ImageConverterUI } from '../../../shared/ImageConverter.astro';
|
|
|
2
2
|
import { generateSchemas } from '../../../shared/logic/schemas';
|
|
3
3
|
import type { PngAJpgLocaleContent } from '../index';
|
|
4
4
|
|
|
5
|
-
const slug = '
|
|
5
|
+
const slug = 'png-to-jpg-converter';
|
|
6
6
|
const title = 'PNG를 JPG로 온라인 변환';
|
|
7
7
|
const description =
|
|
8
8
|
'PNG 이미지를 즉시 사용자 컴퓨터에서 빠른 압축 JPG 형식으로 변환하세요. 인터넷에 사진을 업로드할 필요가 없습니다. 일괄 최적화가 가능합니다.';
|