@jjlmoya/utils-converters 1.19.0 → 1.21.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/tests/spanish_leakage.test.ts +153 -0
- package/src/tests/translation_copy.test.ts +123 -0
- package/src/tool/pngAJpg/i18n/de.ts +10 -118
- package/src/tool/pngAJpg/i18n/fr.ts +40 -40
- package/src/tool/pngAJpg/i18n/id.ts +40 -40
- package/src/tool/pngAJpg/i18n/it.ts +40 -40
- package/src/tool/pngAJpg/i18n/nl.ts +10 -118
- package/src/tool/pngAJpg/i18n/pl.ts +40 -40
- package/src/tool/pngAJpg/i18n/pt.ts +40 -40
- package/src/tool/pngAJpg/i18n/sv.ts +40 -40
- package/src/tool/pngAJpg/i18n/tr.ts +40 -40
- package/src/tool/pngAJpg/seo.ts +75 -0
|
@@ -21,24 +21,24 @@ const ui: ImageConverterUI = {
|
|
|
21
21
|
|
|
22
22
|
const faq: PngAJpgLocaleContent['faq'] = [
|
|
23
23
|
{
|
|
24
|
-
question: '
|
|
24
|
+
question: "Yerel PNG'den JPG'ye dönüştürücümüzü neden seçmelisiniz?",
|
|
25
25
|
answer:
|
|
26
|
-
'
|
|
26
|
+
'Geleneksel hizmetlerin aksine bu araç dosyaları tamamen tarayıcıda işler. Görselleriniz uzak bir diske gönderilmez; verileriniz üzerindeki kontrol ve gizlilik korunur.',
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
|
-
question: '
|
|
29
|
+
question: 'JPG mi PNG mi: hangisi ne zaman kullanılmalı?',
|
|
30
30
|
answer:
|
|
31
|
-
'
|
|
31
|
+
'PNG logolar ve saydam öğeler için uygundur. JPG ise fotoğraflarda ve web bannerlarında daha küçük dosyalar oluşturarak sayfa yükleme hızını artırır.',
|
|
32
32
|
},
|
|
33
33
|
{
|
|
34
|
-
question: '
|
|
34
|
+
question: 'Dosya yüklemeden teknik dönüşüm nasıl çalışır?',
|
|
35
35
|
answer:
|
|
36
|
-
'
|
|
36
|
+
'HTML5 Canvas kullanılır. Tarayıcı görüntüyü görünmez bir sanal alanda yeniden oluşturur, saydam bölgeleri beyazla doldurur ve indirilecek JPEG verisini doğrudan üretir.',
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
|
-
question: '
|
|
39
|
+
question: 'Gizli belgeler için güvenli mi?',
|
|
40
40
|
answer:
|
|
41
|
-
|
|
41
|
+
"Evet. Bankacılık, sağlık ve hukuk dosyalarını üçüncü taraflara göndermemek daha güvenlidir; işlem cihazın RAM'inde kalır ve sekme kapatılınca sona erer.",
|
|
42
42
|
},
|
|
43
43
|
];
|
|
44
44
|
|
|
@@ -60,110 +60,110 @@ const howTo: PngAJpgLocaleContent['howTo'] = [
|
|
|
60
60
|
const seo: PngAJpgLocaleContent['seo'] = [
|
|
61
61
|
{
|
|
62
62
|
type: 'title',
|
|
63
|
-
text: '
|
|
63
|
+
text: "PNG'den JPG'ye Dönüştürme: Görsel Optimizasyonu Rehberi",
|
|
64
64
|
level: 2,
|
|
65
65
|
},
|
|
66
66
|
{
|
|
67
67
|
type: 'paragraph',
|
|
68
|
-
html: '
|
|
68
|
+
html: 'Dijital tasarım ve web geliştirmede hız önemlidir. PNG saydamlığı ve kayıpsız kaliteyi korur, ancak dosyalar ağır olabilir. Hızlı sayfalar ve küçük ekler için JPG pratik bir seçenektir.',
|
|
69
69
|
},
|
|
70
70
|
{
|
|
71
71
|
type: 'title',
|
|
72
|
-
text: '
|
|
72
|
+
text: 'JPG mi PNG mi: hangisi seçilmeli?',
|
|
73
73
|
level: 3,
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
type: 'paragraph',
|
|
77
|
-
html: '
|
|
77
|
+
html: 'Her durumda üstün tek bir format yoktur. PNG arayüzler, logolar ve saydam arka planlar için uygundur; kayıpsız sıkıştırma ise daha büyük dosyalar oluşturabilir.',
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
type: 'paragraph',
|
|
81
|
-
html: '
|
|
81
|
+
html: 'JPG gözün zor fark ettiği ayrıntıları azaltarak hafif görseller üretir. Fotoğraf, banner ve sosyal medya için küçük bir kalite ödününü daha hızlı yükleme karşılığında sunar.',
|
|
82
82
|
},
|
|
83
83
|
{
|
|
84
84
|
type: 'title',
|
|
85
|
-
text: '
|
|
85
|
+
text: 'Teknik karşılaştırma: yerel işlem ve bulut',
|
|
86
86
|
level: 3,
|
|
87
87
|
},
|
|
88
88
|
{
|
|
89
89
|
type: 'comparative',
|
|
90
90
|
items: [
|
|
91
91
|
{
|
|
92
|
-
title: '
|
|
93
|
-
description: '
|
|
92
|
+
title: 'Bulut dönüştürücüler',
|
|
93
|
+
description: 'Fotoğrafları uzak bir sunucuya yükleyen geleneksel hizmetler.',
|
|
94
94
|
icon: 'mdi:cloud-upload',
|
|
95
95
|
pointIcon: 'mdi:close-circle-outline',
|
|
96
96
|
points: [
|
|
97
|
-
'
|
|
98
|
-
'
|
|
99
|
-
'
|
|
100
|
-
'
|
|
97
|
+
'Ağ gecikmesi (yükleme/indirme)',
|
|
98
|
+
'Özel verilerin sızma riski',
|
|
99
|
+
'Dosya boyutu sınırları',
|
|
100
|
+
'Reklamlar ve izleyiciler',
|
|
101
101
|
],
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
|
-
title: '
|
|
105
|
-
description: '
|
|
104
|
+
title: 'Yerel mimarimiz',
|
|
105
|
+
description: 'Vanilla JS ile cihazınızda doğrudan işleme.',
|
|
106
106
|
icon: 'mdi:laptop-mac',
|
|
107
107
|
highlight: true,
|
|
108
108
|
points: [
|
|
109
|
-
'
|
|
110
|
-
'
|
|
111
|
-
'
|
|
112
|
-
'
|
|
109
|
+
'Ağ olmadan anında hız',
|
|
110
|
+
'Gizlilik garantisi (sıfır bayt gönderilir)',
|
|
111
|
+
'Dosya başına MB sınırı yok',
|
|
112
|
+
'Temiz ve profesyonel arayüz',
|
|
113
113
|
],
|
|
114
114
|
},
|
|
115
115
|
],
|
|
116
116
|
},
|
|
117
117
|
{
|
|
118
118
|
type: 'title',
|
|
119
|
-
text: '
|
|
119
|
+
text: 'Teknik dönüşüm nasıl çalışır?',
|
|
120
120
|
level: 3,
|
|
121
121
|
},
|
|
122
122
|
{
|
|
123
123
|
type: 'paragraph',
|
|
124
|
-
html:
|
|
124
|
+
html: "Sunucu olmadan dönüşüm, modern tarayıcı API'leriyle yapılır. Dosya seçildiğinde RAM içinde geçici bir Blob oluşturulur ve görünmez bir HTML5 Canvas üzerine çizilir.",
|
|
125
125
|
},
|
|
126
126
|
{
|
|
127
127
|
type: 'paragraph',
|
|
128
|
-
html: '
|
|
128
|
+
html: 'JPG saydamlığı desteklemediği için saydam alanlar oluşturma öncesinde beyazla doldurulur. Canvas daha sonra cihazın doğrudan kaydedebileceği JPEG verisini üretir.',
|
|
129
129
|
},
|
|
130
130
|
{
|
|
131
131
|
type: 'tip',
|
|
132
|
-
title: '
|
|
133
|
-
html:
|
|
132
|
+
title: 'SEO ipucu: ideal dosya boyutu',
|
|
133
|
+
html: "Daha küçük bir görsel LCP ve PageSpeed ölçümlerini iyileştirebilir. Büyük PNG dosyalarını JPG'ye çevirmek özellikle başlık görsellerinde ve yoğun sayfalarda faydalıdır.",
|
|
134
134
|
},
|
|
135
135
|
{
|
|
136
136
|
type: 'title',
|
|
137
|
-
text: '
|
|
137
|
+
text: 'Şirketler ve profesyoneller için güvenlik',
|
|
138
138
|
level: 3,
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
type: 'paragraph',
|
|
142
|
-
html:
|
|
142
|
+
html: "Bankacılık, sağlık ve hukukta dosyaları dış hizmetlere göndermek risk yaratabilir. Buradaki işlem tarayıcının RAM'inde kalır ve buluta yükleme gerektirmez.",
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
type: 'title',
|
|
146
|
-
text: '
|
|
146
|
+
text: 'Sonuç uyumluluğu',
|
|
147
147
|
level: 3,
|
|
148
148
|
},
|
|
149
149
|
{
|
|
150
150
|
type: 'list',
|
|
151
151
|
icon: 'mdi:check-circle',
|
|
152
152
|
items: [
|
|
153
|
-
'
|
|
154
|
-
'
|
|
155
|
-
'
|
|
156
|
-
'
|
|
153
|
+
'Windows, macOS ve mobil cihaz görüntüleyicileri.',
|
|
154
|
+
'Sosyal ağlar (Instagram, LinkedIn ve diğerleri).',
|
|
155
|
+
'Ofis araçları (Word, PowerPoint).',
|
|
156
|
+
'İçerik yönetim sistemleri (WordPress, Shopify).',
|
|
157
157
|
],
|
|
158
158
|
},
|
|
159
159
|
{
|
|
160
160
|
type: 'title',
|
|
161
|
-
text: '
|
|
161
|
+
text: 'Sonuç: bilinçli biçimde optimize edin',
|
|
162
162
|
level: 3,
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
165
|
type: 'paragraph',
|
|
166
|
-
html: '
|
|
166
|
+
html: 'Bu dönüştürücü hız ve gizliliği birleştirir. Geliştirici veya ev kullanıcısı olun, dosyalarınızı üçüncü taraflara vermeden görselleri küçültebilirsiniz.',
|
|
167
167
|
},
|
|
168
168
|
];
|
|
169
169
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { SEOSection } from '@jjlmoya/utils-shared';
|
|
2
|
+
|
|
3
|
+
type FAQ = { question: string; answer: string };
|
|
4
|
+
type Step = { name: string; text: string };
|
|
5
|
+
type Source = {
|
|
6
|
+
title: string;
|
|
7
|
+
description: string;
|
|
8
|
+
faq: FAQ[];
|
|
9
|
+
howTo: Step[];
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
type Indexed<T> = (index: number) => T;
|
|
13
|
+
|
|
14
|
+
function buildComparison(source: Source, faq: Indexed<FAQ>, step: Indexed<Step>): SEOSection {
|
|
15
|
+
return {
|
|
16
|
+
type: 'comparative',
|
|
17
|
+
items: [
|
|
18
|
+
{
|
|
19
|
+
title: faq(0).question,
|
|
20
|
+
description: faq(0).answer,
|
|
21
|
+
icon: 'mdi:cloud-upload',
|
|
22
|
+
pointIcon: 'mdi:close-circle-outline',
|
|
23
|
+
points: [step(0).name, step(1).name],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
title: source.title,
|
|
27
|
+
description: step(0).text,
|
|
28
|
+
icon: 'mdi:laptop-mac',
|
|
29
|
+
highlight: true,
|
|
30
|
+
points: [step(1).name, step(2).name],
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function buildOpeningSections(source: Source, faq: Indexed<FAQ>, step: Indexed<Step>): SEOSection[] {
|
|
37
|
+
return [
|
|
38
|
+
{ type: 'title', text: source.title, level: 2 },
|
|
39
|
+
{ type: 'paragraph', html: source.description },
|
|
40
|
+
{ type: 'title', text: faq(1).question, level: 3 },
|
|
41
|
+
{ type: 'paragraph', html: faq(1).answer },
|
|
42
|
+
{ type: 'paragraph', html: faq(2).answer },
|
|
43
|
+
{ type: 'title', text: faq(0).question, level: 3 },
|
|
44
|
+
buildComparison(source, faq, step),
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function buildClosingSections(source: Source, faq: Indexed<FAQ>, step: Indexed<Step>): SEOSection[] {
|
|
49
|
+
return [
|
|
50
|
+
{ type: 'title', text: faq(2).question, level: 3 },
|
|
51
|
+
{ type: 'paragraph', html: step(0).text },
|
|
52
|
+
{ type: 'paragraph', html: step(1).text },
|
|
53
|
+
{ type: 'tip', title: step(2).name, html: `<p>${faq(3).answer}</p>` },
|
|
54
|
+
{ type: 'title', text: faq(3).question, level: 3 },
|
|
55
|
+
{ type: 'paragraph', html: faq(3).answer },
|
|
56
|
+
{ type: 'title', text: step(0).name, level: 3 },
|
|
57
|
+
{
|
|
58
|
+
type: 'list',
|
|
59
|
+
icon: 'mdi:check-circle',
|
|
60
|
+
items: source.howTo.map(({ name, text }) => `<strong>${name}:</strong> ${text}`),
|
|
61
|
+
},
|
|
62
|
+
{ type: 'title', text: step(2).name, level: 3 },
|
|
63
|
+
{ type: 'paragraph', html: source.description },
|
|
64
|
+
];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function buildPngJpgSeo(source: Source): SEOSection[] {
|
|
68
|
+
const faq = (index: number) => source.faq[index % source.faq.length];
|
|
69
|
+
const step = (index: number) => source.howTo[index % source.howTo.length];
|
|
70
|
+
|
|
71
|
+
return [
|
|
72
|
+
...buildOpeningSections(source, faq, step),
|
|
73
|
+
...buildClosingSections(source, faq, step),
|
|
74
|
+
];
|
|
75
|
+
}
|