From 9fd11720319e61416b6fabf10bce6189412fb516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leonardo=20Mur=C3=A7a?= Date: Sun, 23 Mar 2025 15:08:21 -0300 Subject: [PATCH] Add i18n support with portuguese language --- package-lock.json | 4 +- package.json | 2 +- src/app.css | 13 ++++++- src/file-renderer/index.js | 11 +++--- src/file-renderer/pattern.js | 8 ++-- src/i18n/index.js | 35 ++++++++++++++++++ src/i18n/translations.js | 32 ++++++++++++++++ src/lib/CardList.svelte | 10 ++++- src/lib/Dropzone.svelte | 4 +- src/lib/FileViewer.svelte | 71 ++++++++++++++++++++++++++++++++---- src/lib/Footer.svelte | 12 ++---- src/lib/LanguageIcon.svelte | 63 ++++++++++++++++++++++++++++++++ 12 files changed, 233 insertions(+), 32 deletions(-) create mode 100644 src/i18n/index.js create mode 100644 src/i18n/translations.js create mode 100644 src/lib/LanguageIcon.svelte diff --git a/package-lock.json b/package-lock.json index 055418e..560c3e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "embroidery-viewer", - "version": "1.2.1", + "version": "1.2.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "embroidery-viewer", - "version": "1.2.1", + "version": "1.2.4", "devDependencies": { "@sveltejs/vite-plugin-svelte": "^2.4.1", "svelte": "^3.59.1", diff --git a/package.json b/package.json index ca336fb..2dd0610 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "embroidery-viewer", "private": true, - "version": "1.2.2", + "version": "1.2.4", "type": "module", "scripts": { "dev": "vite", diff --git a/src/app.css b/src/app.css index 227035f..79255df 100644 --- a/src/app.css +++ b/src/app.css @@ -47,4 +47,15 @@ input[type="submit"]:hover { cursor: pointer; background-color: black; color: white; -} \ No newline at end of file +} + +body a { + text-decoration: none; + color: #06345F; + border-bottom: 3px solid #06345F; +} + +body a:hover { + background-color: #06345F; + color: #ffffff; +} diff --git a/src/file-renderer/index.js b/src/file-renderer/index.js index 4f2a409..595fdc4 100644 --- a/src/file-renderer/index.js +++ b/src/file-renderer/index.js @@ -2,7 +2,7 @@ import { jDataView } from "./jdataview"; import { supportedFormats } from "../format-readers"; import { Pattern } from "./pattern"; -function renderFile(filename, evt, canvas, colorView, stitchesView, sizeView) { +function renderFile(filename, evt, canvas, colorView, stitchesView, sizeView, localizedStrings) { const fileExtension = filename.toLowerCase().split(".").pop(); const view = jDataView(evt.target.result, 0, evt.size); const pattern = new Pattern(); @@ -12,8 +12,8 @@ function renderFile(filename, evt, canvas, colorView, stitchesView, sizeView) { pattern.moveToPositive(); pattern.drawShapeTo(canvas); pattern.drawColorsTo(colorView); - pattern.drawStitchesCountTo(stitchesView); - pattern.drawSizeValuesTo(stitchesView); + pattern.drawStitchesCountTo(stitchesView, localizedStrings.stitches); + pattern.drawSizeValuesTo(stitchesView, localizedStrings.dimensions); } function renderAbortMessage(errorMessageRef) { @@ -56,12 +56,13 @@ export default function renderFileToCanvas( errorMessageRef, colorView, stitchesView, - sizeView + sizeView, + localizedStrings ) { const reader = new FileReader(); reader.onloadend = (evt) => - renderFile(fileObject.name, evt, canvas, colorView, stitchesView, sizeView); + renderFile(fileObject.name, evt, canvas, colorView, stitchesView, sizeView, localizedStrings); reader.abort = (/** @type {any} */ _) => renderAbortMessage(errorMessageRef); reader.onerror = (evt) => renderErrorMessage(evt.target.error.name, errorMessageRef); diff --git a/src/file-renderer/pattern.js b/src/file-renderer/pattern.js index ab58964..ec6a3d2 100644 --- a/src/file-renderer/pattern.js +++ b/src/file-renderer/pattern.js @@ -212,12 +212,12 @@ Pattern.prototype.drawColorsTo = function (colorContainer) { }); }; -Pattern.prototype.drawStitchesCountTo = function (stitchesContainer) { - stitchesContainer.innerHTML += `
Stitches: ${this.stitches.length}
`; +Pattern.prototype.drawStitchesCountTo = function (stitchesContainer, stitchesString) { + stitchesContainer.innerHTML += `
${stitchesString}: ${this.stitches.length}
`; }; -Pattern.prototype.drawSizeValuesTo = function (sizeContainer) { - sizeContainer.innerHTML += `
Size (x, y): ${Math.round( +Pattern.prototype.drawSizeValuesTo = function (sizeContainer, dimensionsString) { + sizeContainer.innerHTML += `
${dimensionsString}: ${Math.round( this.right / 10 )}mm x ${Math.round(this.bottom / 10)}mm
`; }; diff --git a/src/i18n/index.js b/src/i18n/index.js new file mode 100644 index 0000000..c465f60 --- /dev/null +++ b/src/i18n/index.js @@ -0,0 +1,35 @@ +import { derived, writable } from "svelte/store"; +import translations from "./translations"; + +const browserLocale = navigator.language || "en"; +const [baseLang, region] = browserLocale.split("-"); + +export const DEFAULT_LOCALE = translations[browserLocale] ? browserLocale : translations[baseLang] ? baseLang :"en"; +export const locale = writable(DEFAULT_LOCALE); +export const locales = Object.entries(translations).map(([key, lang]) => [key, lang.name]); + +function translate(locale, key, vars = {}) { + if (!key) throw new Error("Translation key is required."); + + const validLocale = translations[locale] + ? locale + : translations[baseLang] + ? baseLang + : "en"; + + let text = translations[validLocale][key] || translations["en"][key]; + + if (!text) { + console.error(`Missing translation for key "${key}" in locale "${validLocale}".`); + return key; + } + + return Object.entries(vars).reduce( + (str, [varKey, value]) => str.replaceAll(`{{${varKey}}}`, value), + text + ); +} + +export const t = derived(locale, ($locale) => (key, vars = {}) => + translate($locale, key, vars) +); diff --git a/src/i18n/translations.js b/src/i18n/translations.js new file mode 100644 index 0000000..d22c9cb --- /dev/null +++ b/src/i18n/translations.js @@ -0,0 +1,32 @@ +export default { + en: { + "main.title": "Upload files", + "main.languageSwitch": "Mudar para Português", + "main.fileSize": "Max file size is {{fileSize}}kb.", + "main.supportedFormats": "Accepted formats: {{supportedFormats}}.", + "main.render": "Render files", + "main.dropzone": "Drag and drop files here or click to upload.", + "main.selected": "Selected files", + "main.rejected": "Rejected files", + "main.stitches": "Stitches", + "main.dimensions": "Dimensions (x, y)", + "main.download": "Download image", + "main.copyright": "Copyright © {{year}} Leonardo Murça.
All rights reserved.", + "main.version": "Version: {{version}}" + }, + pt: { + "main.title": "Carregar arquivos", + "main.languageSwitch": "Switch to English", + "main.fileSize": "O tamanho máximo do arquivo é {{fileSize}}kb.", + "main.supportedFormats": "Formatos aceitos: {{supportedFormats}}.", + "main.render": "Renderizar arquivos", + "main.dropzone": "Arraste e solte os arquivos aqui ou clique para fazer upload.", + "main.selected": "Arquivos selecionados", + "main.rejected": "Arquivos recusados", + "main.stitches": "Pontos", + "main.dimensions": "Dimensões (x, y)", + "main.download": "Baixar imagem", + "main.copyright": "Copyright © {{year}} Leonardo Murça.
Todos os direitos reservados.", + "main.version": "Versão: {{version}}" + }, + }; \ No newline at end of file diff --git a/src/lib/CardList.svelte b/src/lib/CardList.svelte index 30f832a..23c14c5 100644 --- a/src/lib/CardList.svelte +++ b/src/lib/CardList.svelte @@ -1,4 +1,5 @@
-

Upload files

+

- Max file size is {fileRequirements.maxSize / 1000}kb. - Accepted formats: - {fileRequirements.supportedFormats.join(", ")}. + {@html $t("main.fileSize", { fileSize: fileRequirements.maxSize / 1000 })} + {@html $t("main.supportedFormats", { supportedFormats: fileRequirements.supportedFormats.join(", ") })}

- + {#if areAcceptedFilesRendered} {:else} - - + + {/if}