diff --git a/package.json b/package.json
index 061d5c7..bfa32c4 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "embroidery-viewer",
"private": true,
- "version": "3.0.2",
+ "version": "3.0.3",
"type": "module",
"scripts": {
"dev": "vite dev",
diff --git a/src/app.html b/src/app.html
index 6340008..c197de8 100644
--- a/src/app.html
+++ b/src/app.html
@@ -14,23 +14,31 @@ Buy me a coffee and help keep it running ☕"
data-x_margin="18"
data-y_margin="18"
>
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
%sveltekit.head%
diff --git a/src/lib/components/Head.svelte b/src/lib/components/Head.svelte
new file mode 100644
index 0000000..05e87b1
--- /dev/null
+++ b/src/lib/components/Head.svelte
@@ -0,0 +1,89 @@
+
+
+
+
+ {translatedTitle}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/lib/components/Seo.svelte b/src/lib/components/Seo.svelte
deleted file mode 100644
index c44773c..0000000
--- a/src/lib/components/Seo.svelte
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
- {$t(title)}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/lib/translations/en-US/home.json b/src/lib/translations/en-US/home.json
index 59e8dd5..0287277 100644
--- a/src/lib/translations/en-US/home.json
+++ b/src/lib/translations/en-US/home.json
@@ -2,6 +2,5 @@
"seo.title": "Free Online Embroidery File Viewer - Fast, Private & No Signup",
"seo.description": "Upload and preview embroidery files instantly with Embroidery Viewer. Supports DST, PES, JEF, EXP, VP3 and more. No installs, no uploads – 100% browser-based and free.",
"seo.keywords": "embroidery viewer, online embroidery viewer, embroidery file preview, DST viewer, PES viewer, free embroidery tool, JEF viewer, EXP embroidery, VP3 embroidery viewer, embroidery preview tool, browser embroidery renderer, convert embroidery to PNG",
- "seo.url": "https://embroideryviewer.xyz",
- "seo.image": "https://embroideryviewer.xyz/og/"
+ "seo.url": "https://embroideryviewer.xyz"
}
diff --git a/src/lib/translations/pt-BR/home.json b/src/lib/translations/pt-BR/home.json
index fa8244b..7ad5c33 100644
--- a/src/lib/translations/pt-BR/home.json
+++ b/src/lib/translations/pt-BR/home.json
@@ -2,6 +2,5 @@
"seo.title": "Visualizador de Bordado Online Grátis - Rápido, Privado e Sem Cadastro",
"seo.description": "Envie e visualize arquivos de bordado instantaneamente com o Embroidery Viewer. Compatível com DST, PES, JEF, EXP, VP3 e mais. Sem instalações, sem uploads – 100% no navegador e gratuito.",
"seo.keywords": "visualizador de bordado, visualizador online de bordado, visualizar arquivos de bordado, visualizar DST, visualizar PES, ferramenta gratuita de bordado, visualizador JEF, bordado EXP, visualizador VP3, pré-visualização de bordado, renderizador de bordado no navegador, converter bordado em PNG",
- "seo.url": "https://embroideryviewer.xyz",
- "seo.image": "https://embroideryviewer.xyz/og/"
+ "seo.url": "https://embroideryviewer.xyz"
}
diff --git a/src/lib/utils/normalizeLocaleUnderscore.js b/src/lib/utils/normalizeLocaleUnderscore.js
new file mode 100644
index 0000000..dc42dc1
--- /dev/null
+++ b/src/lib/utils/normalizeLocaleUnderscore.js
@@ -0,0 +1,15 @@
+/**
+ * Converts a locale string from hyphen format (e.g., "en-US")
+ * to underscore format (e.g., "en_US").
+ *
+ * Useful for APIs or systems that expect locales with underscores.
+ *
+ * @param {string} locale - The locale string in BCP 47 format (e.g., "en-US").
+ * @returns {string} The normalized locale string using underscores (e.g., "en_US").
+ *
+ * @example
+ * normalizeLocaleUnderscore("en-US"); // "en_US"
+ */
+export const normalizeLocaleUnderscore = (locale) => {
+ return locale.split('-').join('_');
+};
diff --git a/src/routes/+page.js b/src/routes/+page.js
deleted file mode 100644
index b0adabb..0000000
--- a/src/routes/+page.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/** @type {import('./$types').PageLoad} */
-export function load() {
- return {
- metadata: {
- title: 'home.seo.title',
- description: 'home.seo.description',
- keywords: 'home.seo.keywords',
- url: 'home.seo.url',
- image: 'home.seo.image',
- },
- };
-}
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 00e2ae0..cceb54f 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1,17 +1,17 @@
-
+
diff --git a/src/routes/about/+page.js b/src/routes/about/+page.js
deleted file mode 100644
index b7c4e00..0000000
--- a/src/routes/about/+page.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/** @type {import('./$types').PageLoad} */
-export function load() {
- return {
- metadata: {
- title: 'about.seo.title',
- description: 'about.seo.description',
- keywords: 'about.seo.keywords',
- url: 'about.seo.url',
- image: 'about.seo.image',
- },
- };
-}
diff --git a/src/routes/about/+page.svelte b/src/routes/about/+page.svelte
index 9a0f2e3..b0c00ea 100644
--- a/src/routes/about/+page.svelte
+++ b/src/routes/about/+page.svelte
@@ -1,24 +1,23 @@
-
+
import { t } from '$lib/translations';
- import Seo from '$lib/components/Seo.svelte';
-
- /** @type {import('./$types').PageProps} */
- let { data } = $props();
-
- // svelte-ignore state_referenced_locally
- const metadata = data.metadata;
+ import Head from '$lib/components/Head.svelte';
-
+
{$t('mobile.app.privacy.policy.title')}
diff --git a/src/routes/privacy-policy/+page.js b/src/routes/privacy-policy/+page.js
deleted file mode 100644
index a32f173..0000000
--- a/src/routes/privacy-policy/+page.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/** @type {import('./$types').PageLoad} */
-export function load() {
- return {
- metadata: {
- title: 'privacy.policy.seo.title',
- description: 'privacy.policy.seo.description',
- keywords: 'privacy.policy.seo.keywords',
- url: 'privacy.policy.seo.url',
- image: 'privacy.policy.seo.image',
- },
- };
-}
diff --git a/src/routes/privacy-policy/+page.svelte b/src/routes/privacy-policy/+page.svelte
index 25fb084..c4d6638 100644
--- a/src/routes/privacy-policy/+page.svelte
+++ b/src/routes/privacy-policy/+page.svelte
@@ -1,15 +1,14 @@
-
+
{$t('privacy.policy.title')}
diff --git a/src/routes/support-us/+page.js b/src/routes/support-us/+page.js
deleted file mode 100644
index 8074bda..0000000
--- a/src/routes/support-us/+page.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/** @type {import('./$types').PageLoad} */
-export function load() {
- return {
- metadata: {
- title: 'support-us.seo.title',
- description: 'support-us.seo.description',
- keywords: 'support-us.seo.keywords',
- url: 'support-us.seo.url',
- image: 'support-us.seo.image',
- },
- };
-}
diff --git a/src/routes/support-us/+page.svelte b/src/routes/support-us/+page.svelte
index fff8723..acb1619 100644
--- a/src/routes/support-us/+page.svelte
+++ b/src/routes/support-us/+page.svelte
@@ -4,20 +4,19 @@
import { isMobile } from '$lib/utils/isMobile';
import BuyMeACoffeeIcon from '$lib/components/icons/BuyMeACoffeeIcon.svelte';
- import Seo from '$lib/components/Seo.svelte';
-
- /** @type {import('./$types').PageProps} */
- let { data } = $props();
-
- // svelte-ignore state_referenced_locally
- const metadata = data.metadata;
+ import Head from '$lib/components/Head.svelte';
const backgroundImage = isMobile()
? `${PUBLIC_IMAGE_BASE_URL}/t/f_webp/embroidery-viewer/route-wallpaper-mobile.webp`
: `${PUBLIC_IMAGE_BASE_URL}/t/f_webp,w_1920,h_1080/embroidery-viewer/route-wallpaper.webp`;
-
+
import { t } from '$lib/translations';
- import Seo from '$lib/components/Seo.svelte';
-
- /** @type {import('./$types').PageProps} */
- let { data } = $props();
-
- // svelte-ignore state_referenced_locally
- const metadata = data.metadata;
+ import Head from '$lib/components/Head.svelte';
-
+
{$t('terms.of.service.title')}
diff --git a/src/routes/viewer/+page.svelte b/src/routes/viewer/+page.svelte
index 45e997c..fc7ece2 100644
--- a/src/routes/viewer/+page.svelte
+++ b/src/routes/viewer/+page.svelte
@@ -6,7 +6,7 @@
import CardList from '$lib/components/CardList.svelte';
import Dropzone from '$lib/components/Dropzone.svelte';
import FileList from '$lib/components/FileList.svelte';
- import Seo from '$lib/components/Seo.svelte';
+ import Head from '$lib/components/Head.svelte';
import { filterFiles } from '$lib/utils/filterFiles';
import { supportedFormats } from '$lib/format-readers';
@@ -78,15 +78,14 @@
if (el) el.click();
}
}
-
- /** @type {import('./$types').PageProps} */
- let { data } = $props();
-
- // svelte-ignore state_referenced_locally
- const metadata = data.metadata;
-
+