fix: adiversos ajustes e mais 1 conversor
All checks were successful
Deploy ASP.NET MVC to OCI / build-and-deploy (push) Successful in 9m32s

This commit is contained in:
Ricardo Carneiro 2025-09-14 21:26:16 -03:00
parent 18bfb020f9
commit 84b058904f
29 changed files with 3262 additions and 137 deletions

View File

@ -11,7 +11,13 @@
"Bash(dotnet run:*)",
"Bash(find:*)",
"Bash(pkill:*)",
"WebFetch(domain:localhost)"
"WebFetch(domain:localhost)",
"WebSearch",
"WebFetch(domain:products.openize.com)",
"WebFetch(domain:github.com)",
"WebFetch(domain:gist.github.com)",
"Bash(dotnet list:*)",
"Bash(dotnet build:*)"
],
"deny": [],
"ask": []

View File

@ -109,6 +109,7 @@ jobs:
-e DOTNET_USE_POLLING_FILE_WATCHER=true \
-e DOTNET_EnableDiagnostics=0 \
-e DOTNET_RUNNING_IN_CONTAINER=true \
-e Serilog__OpenSearchUrl="http://localhost:9202" \
registry.redecarneir.us/convertit:latest
# Limpa imagens não utilizadas
@ -159,6 +160,7 @@ jobs:
-e DOTNET_USE_POLLING_FILE_WATCHER=true \
-e DOTNET_EnableDiagnostics=0 \
-e DOTNET_RUNNING_IN_CONTAINER=true \
-e Serilog__OpenSearchUrl="http://localhost:9200" \
registry.redecarneir.us/convertit:latest-staging
# Limpa imagens não utilizadas

View File

@ -0,0 +1,273 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using System.IO;
using HeyRed.ImageSharp.Heif;
namespace Convert_It_Online.Areas.ImageConverters.Controllers
{
[Area("ImageConverters")]
public class HeicToJpgController : Controller
{
private readonly IStringLocalizer<SharedResource> _localizer;
private readonly ILogger<HeicToJpgController> _logger;
public HeicToJpgController(IStringLocalizer<SharedResource> localizer, ILogger<HeicToJpgController> logger)
{
_localizer = localizer;
_logger = logger;
}
private void SetCommonViewBagProperties()
{
ViewBag.HomeLink = _localizer["HomeLink"];
ViewBag.TextMenuTitle = _localizer["TextMenuTitle"];
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
ViewBag.FooterText = _localizer["FooterText"];
ViewBag.About = _localizer["About"];
ViewBag.Contact = _localizer["Contact"];
ViewBag.Terms = _localizer["Terms"];
}
private void PrepareIndexView()
{
SetCommonViewBagProperties();
ViewBag.PageTitle = _localizer["HeicConverterPageTitle"];
ViewBag.PageDescription = _localizer["HeicConverterPageDescription"];
ViewBag.HeicToJpgTabTitle = _localizer["HeicToJpgTabTitle"];
ViewBag.JpgToHeicTabTitle = _localizer["JpgToHeicTabTitle"];
ViewBag.HeicFileInputLabel = _localizer["HeicFileInputLabel"];
ViewBag.JpgFileInputLabel = _localizer["JpgFileInputLabel"];
ViewBag.ConvertToJpgButton = _localizer["ConvertToJpgButton"];
ViewBag.ConvertToHeicButton = _localizer["ConvertToHeicButton"];
// FAQ properties
ViewBag.FaqWhatTitle = _localizer["HeicFaqWhatTitle"];
ViewBag.FaqWhatContent = _localizer["HeicFaqWhatContent"];
ViewBag.FaqHowTitle = _localizer["HeicFaqHowTitle"];
ViewBag.FaqHowContent = _localizer["HeicFaqHowContent"];
ViewBag.FaqWhyTitle = _localizer["HeicFaqWhyTitle"];
ViewBag.FaqWhyContent = _localizer["HeicFaqWhyContent"];
ViewBag.FaqSecurityTitle = _localizer["HeicFaqSecurityTitle"];
ViewBag.FaqSecurityContent = _localizer["HeicFaqSecurityContent"];
ViewBag.FaqLimitsTitle = _localizer["HeicFaqLimitsTitle"];
ViewBag.FaqLimitsContent = _localizer["HeicFaqLimitsContent"];
}
public IActionResult Index()
{
PrepareIndexView();
return View();
}
[HttpPost]
public async Task<IActionResult> ConvertHeicToJpg(IFormFile heicFile, bool preview = false)
{
if (heicFile == null || heicFile.Length == 0)
{
_logger.LogWarning("[HEIC-CONVERTER] Tentativa de conversão sem arquivo");
if (preview)
{
return Json(new { success = false, message = _localizer["SelectFileError"].Value });
}
ModelState.AddModelError("heicFile", _localizer["SelectFileError"]);
PrepareIndexView();
return View("Index");
}
var allowedTypes = new[] { "image/heic", "image/heif", "application/octet-stream" };
if (!allowedTypes.Contains(heicFile.ContentType) && !heicFile.FileName.ToLower().EndsWith(".heic") && !heicFile.FileName.ToLower().EndsWith(".heif"))
{
_logger.LogWarning("[HEIC-CONVERTER] Arquivo inválido: {ContentType}", heicFile.ContentType);
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidHeicFileError"].Value });
}
ModelState.AddModelError("heicFile", _localizer["InvalidHeicFileError"]);
PrepareIndexView();
return View("Index");
}
try
{
_logger.LogInformation("[HEIC-CONVERTER] Iniciando conversão HEIC→JPG: {FileName} ({Size} bytes)",
heicFile.FileName, heicFile.Length);
var originalSize = heicFile.Length;
// Limite para preview: 10MB
const long maxPreviewSize = 10 * 1024 * 1024;
using var heicStream = heicFile.OpenReadStream();
using var image = await Image.LoadAsync(heicStream);
using var memoryStream = new MemoryStream();
await image.SaveAsJpegAsync(memoryStream);
var jpegData = memoryStream.ToArray();
var convertedSize = jpegData.Length;
var fileName = Path.GetFileNameWithoutExtension(heicFile.FileName) + ".jpg";
_logger.LogInformation("[HEIC-CONVERTER] Conversão HEIC→JPG concluída: {OutputFileName} (Original: {OriginalSize}bytes → Convertido: {ConvertedSize}bytes)",
fileName, originalSize, convertedSize);
// Se é request de preview e o arquivo não é muito grande
if (preview && originalSize <= maxPreviewSize && convertedSize <= maxPreviewSize)
{
var base64 = Convert.ToBase64String(jpegData);
var base64DataUrl = $"data:image/jpeg;base64,{base64}";
return Json(new
{
success = true,
base64 = base64DataUrl,
filename = fileName,
originalSize = originalSize,
convertedSize = convertedSize
});
}
// Download normal (lógica original)
return File(jpegData, "image/jpeg", fileName);
}
catch (UnknownImageFormatException)
{
_logger.LogWarning("[HEIC-CONVERTER] O arquivo HEIC parece ser inválido ou o formato não é suportado. Verifique se a biblioteca 'libheif' está instalada no sistema.");
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidHeicFileError"].Value });
}
ModelState.AddModelError("heicFile", _localizer["InvalidHeicFileError"]);
ViewBag.ConversionError = _localizer["InvalidHeicFileError"];
PrepareIndexView();
return View("Index");
}
catch (Exception ex)
{
_logger.LogError(ex, "[HEIC-CONVERTER] Erro ao converter HEIC para JPG: {FileName}", heicFile.FileName);
if (preview)
{
return Json(new { success = false, message = _localizer["ProcessingError"].Value });
}
ModelState.AddModelError("heicFile", _localizer["ProcessingError"]);
ViewBag.ConversionError = _localizer["ProcessingError"];
PrepareIndexView();
return View("Index");
}
}
[HttpPost]
public async Task<IActionResult> ConvertJpgToHeic(IFormFile jpgFile, bool preview = false)
{
if (jpgFile == null || jpgFile.Length == 0)
{
_logger.LogWarning("[HEIC-CONVERTER] Tentativa de conversão JPG→HEIC sem arquivo");
if (preview)
{
return Json(new { success = false, message = _localizer["SelectFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["SelectFileError"]);
PrepareIndexView();
return View("Index");
}
if (jpgFile.ContentType != "image/jpeg" && !jpgFile.FileName.ToLower().EndsWith(".jpg") && !jpgFile.FileName.ToLower().EndsWith(".jpeg"))
{
_logger.LogWarning("[HEIC-CONVERTER] Arquivo JPG inválido: {ContentType}", jpgFile.ContentType);
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidJpgFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["InvalidJpgFileError"]);
PrepareIndexView();
return View("Index");
}
try
{
_logger.LogInformation("[HEIC-CONVERTER] Iniciando conversão JPG→HEIC: {FileName} ({Size} bytes)",
jpgFile.FileName, jpgFile.Length);
var originalSize = jpgFile.Length;
// Limite para preview: 10MB
const long maxPreviewSize = 10 * 1024 * 1024;
using var jpgStream = jpgFile.OpenReadStream();
using var image = await Image.LoadAsync(jpgStream);
using var memoryStream = new MemoryStream();
// Salvar como HEIC usando o encoder disponível
await image.SaveAsync(memoryStream, new HeyRed.ImageSharp.Heif.Formats.Heif.HeifEncoder());
var heicData = memoryStream.ToArray();
var convertedSize = heicData.Length;
var fileName = Path.GetFileNameWithoutExtension(jpgFile.FileName) + ".heic";
_logger.LogInformation("[HEIC-CONVERTER] Conversão JPG→HEIC concluída: {OutputFileName} (Original: {OriginalSize}bytes → Convertido: {ConvertedSize}bytes)",
fileName, originalSize, convertedSize);
// Se é request de preview e o arquivo não é muito grande
if (preview && originalSize <= maxPreviewSize && convertedSize <= maxPreviewSize)
{
var base64 = Convert.ToBase64String(heicData);
var base64DataUrl = $"data:image/heic;base64,{base64}";
return Json(new
{
success = true,
base64 = base64DataUrl,
filename = fileName,
originalSize = originalSize,
convertedSize = convertedSize
});
}
// Download normal
return File(heicData, "image/heic", fileName);
}
catch (UnknownImageFormatException)
{
_logger.LogWarning("[HEIC-CONVERTER] O arquivo JPG parece ser inválido ou o formato não é suportado.");
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidJpgFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["InvalidJpgFileError"]);
ViewBag.ConversionError = _localizer["InvalidJpgFileError"];
PrepareIndexView();
return View("Index");
}
catch (NotSupportedException)
{
_logger.LogWarning("[HEIC-CONVERTER] Conversão JPG→HEIC não é suportada pela biblioteca atual.");
var errorMsg = "Conversão JPG→HEIC ainda não está disponível. A biblioteca não suporta encoding HEIC.";
if (preview)
{
return Json(new { success = false, message = errorMsg });
}
ModelState.AddModelError("jpgFile", errorMsg);
ViewBag.ConversionError = errorMsg;
PrepareIndexView();
return View("Index");
}
catch (Exception ex)
{
_logger.LogError(ex, "[HEIC-CONVERTER] Erro ao converter JPG para HEIC: {FileName}", jpgFile.FileName);
if (preview)
{
return Json(new { success = false, message = _localizer["ProcessingError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["ProcessingError"]);
ViewBag.ConversionError = _localizer["ProcessingError"];
PrepareIndexView();
return View("Index");
}
}
}
}

View File

@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Formats.Jpeg;
namespace Convert_It_Online.Areas.ImageConverters.Controllers
{
@ -9,10 +10,12 @@ namespace Convert_It_Online.Areas.ImageConverters.Controllers
public class JpgToWebpController : Controller
{
private readonly IStringLocalizer<SharedResource> _localizer;
private readonly ILogger<JpgToWebpController> _logger;
public JpgToWebpController(IStringLocalizer<SharedResource> localizer)
public JpgToWebpController(IStringLocalizer<SharedResource> localizer, ILogger<JpgToWebpController> logger)
{
_localizer = localizer;
_logger = logger;
}
private void SetCommonViewBagProperties()
@ -28,49 +31,223 @@ namespace Convert_It_Online.Areas.ImageConverters.Controllers
ViewBag.Terms = _localizer["Terms"];
}
public IActionResult Index()
private void PrepareIndexView()
{
SetCommonViewBagProperties();
ViewBag.PageTitle = _localizer["ImageConverterPageTitle"];
ViewBag.PageDescription = _localizer["ImageConverterPageDescription"];
ViewBag.FileInputLabel = _localizer["FileInputLabel"];
ViewBag.ConvertButton = _localizer["ConvertButton"];
ViewBag.PageTitle = _localizer["JpgWebpConverterPageTitle"];
ViewBag.PageDescription = _localizer["JpgWebpConverterPageDescription"];
ViewBag.JpgToWebpTabTitle = _localizer["JpgToWebpTabTitle"];
ViewBag.WebpToJpgTabTitle = _localizer["WebpToJpgTabTitle"];
ViewBag.JpgFileInputLabel = _localizer["JpgFileInputLabel"];
ViewBag.WebpFileInputLabel = _localizer["WebpFileInputLabel"];
ViewBag.ConvertToWebpButton = _localizer["ConvertToWebpButton"];
ViewBag.ConvertToJpgButton = _localizer["ConvertToJpgButton"];
// FAQ properties
ViewBag.FaqWhatTitle = _localizer["JpgWebpFaqWhatTitle"];
ViewBag.FaqWhatContent = _localizer["JpgWebpFaqWhatContent"];
ViewBag.FaqHowTitle = _localizer["JpgWebpFaqHowTitle"];
ViewBag.FaqHowContent = _localizer["JpgWebpFaqHowContent"];
ViewBag.FaqWhyTitle = _localizer["JpgWebpFaqWhyTitle"];
ViewBag.FaqWhyContent = _localizer["JpgWebpFaqWhyContent"];
ViewBag.FaqSecurityTitle = _localizer["JpgWebpFaqSecurityTitle"];
ViewBag.FaqSecurityContent = _localizer["JpgWebpFaqSecurityContent"];
ViewBag.FaqLimitsTitle = _localizer["JpgWebpFaqLimitsTitle"];
ViewBag.FaqLimitsContent = _localizer["JpgWebpFaqLimitsContent"];
}
public IActionResult Index()
{
PrepareIndexView();
return View();
}
[HttpPost]
public async Task<IActionResult> Convert(IFormFile jpgFile)
public async Task<IActionResult> ConvertJpgToWebp(IFormFile jpgFile, bool preview = false)
{
if (jpgFile == null || jpgFile.Length == 0)
{
ModelState.AddModelError("jpgFile", "Por favor, selecione um arquivo.");
_logger.LogWarning("[JPG-WEBP-CONVERTER] Tentativa de conversão sem arquivo");
if (preview)
{
return Json(new { success = false, message = _localizer["SelectFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["SelectFileError"]);
PrepareIndexView();
return View("Index");
}
// Validação simples do tipo de arquivo
if (jpgFile.ContentType != "image/jpeg")
if (jpgFile.ContentType != "image/jpeg" && !jpgFile.FileName.ToLower().EndsWith(".jpg") && !jpgFile.FileName.ToLower().EndsWith(".jpeg"))
{
ModelState.AddModelError("jpgFile", "Arquivo inválido. Por favor, envie um arquivo JPG.");
_logger.LogWarning("[JPG-WEBP-CONVERTER] Arquivo JPG inválido: {ContentType}", jpgFile.ContentType);
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidJpgFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["InvalidJpgFileError"]);
PrepareIndexView();
return View("Index");
}
try
{
using var imageStream = jpgFile.OpenReadStream();
using var image = await Image.LoadAsync(imageStream);
_logger.LogInformation("[JPG-WEBP-CONVERTER] Iniciando conversão JPG→WebP: {FileName} ({Size} bytes)",
jpgFile.FileName, jpgFile.Length);
var originalSize = jpgFile.Length;
// Limite para preview: 10MB
const long maxPreviewSize = 10 * 1024 * 1024;
using var jpgStream = jpgFile.OpenReadStream();
using var image = await Image.LoadAsync(jpgStream);
using var memoryStream = new MemoryStream();
await image.SaveAsync(memoryStream, new WebpEncoder());
memoryStream.Position = 0;
await image.SaveAsWebpAsync(memoryStream);
var webpData = memoryStream.ToArray();
var convertedSize = webpData.Length;
var fileName = Path.GetFileNameWithoutExtension(jpgFile.FileName) + ".webp";
return File(memoryStream.ToArray(), "image/webp", fileName);
}
catch (Exception)
_logger.LogInformation("[JPG-WEBP-CONVERTER] Conversão JPG→WebP concluída: {OutputFileName} (Original: {OriginalSize}bytes → Convertido: {ConvertedSize}bytes)",
fileName, originalSize, convertedSize);
// Se é request de preview e o arquivo não é muito grande
if (preview && originalSize <= maxPreviewSize && convertedSize <= maxPreviewSize)
{
// Log do erro (não implementado aqui)
ModelState.AddModelError("jpgFile", "Ocorreu um erro ao processar a imagem.");
var base64 = Convert.ToBase64String(webpData);
var base64DataUrl = $"data:image/webp;base64,{base64}";
return Json(new
{
success = true,
base64 = base64DataUrl,
filename = fileName,
originalSize = originalSize,
convertedSize = convertedSize
});
}
// Download normal
return File(webpData, "image/webp", fileName);
}
catch (UnknownImageFormatException)
{
_logger.LogWarning("[JPG-WEBP-CONVERTER] O arquivo JPG parece ser inválido ou o formato não é suportado.");
if (preview)
{
return Json(new { success = false, message = _localizer["InvalidJpgFileError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["InvalidJpgFileError"]);
ViewBag.ConversionError = _localizer["InvalidJpgFileError"];
PrepareIndexView();
return View("Index");
}
catch (Exception ex)
{
_logger.LogError(ex, "[JPG-WEBP-CONVERTER] Erro ao converter JPG para WebP: {FileName}", jpgFile.FileName);
if (preview)
{
return Json(new { success = false, message = _localizer["ProcessingError"].Value });
}
ModelState.AddModelError("jpgFile", _localizer["ProcessingError"]);
ViewBag.ConversionError = _localizer["ProcessingError"];
PrepareIndexView();
return View("Index");
}
}
[HttpPost]
public async Task<IActionResult> ConvertWebpToJpg(IFormFile webpFile, bool preview = false)
{
if (webpFile == null || webpFile.Length == 0)
{
_logger.LogWarning("[JPG-WEBP-CONVERTER] Tentativa de conversão WebP→JPG sem arquivo");
if (preview)
{
return Json(new { success = false, message = _localizer["SelectFileError"].Value });
}
ModelState.AddModelError("webpFile", _localizer["SelectFileError"]);
PrepareIndexView();
return View("Index");
}
if (webpFile.ContentType != "image/webp" && !webpFile.FileName.ToLower().EndsWith(".webp"))
{
_logger.LogWarning("[JPG-WEBP-CONVERTER] Arquivo WebP inválido: {ContentType}", webpFile.ContentType);
if (preview)
{
return Json(new { success = false, message = "Arquivo WebP inválido ou formato não suportado." });
}
ModelState.AddModelError("webpFile", "Arquivo WebP inválido ou formato não suportado.");
PrepareIndexView();
return View("Index");
}
try
{
_logger.LogInformation("[JPG-WEBP-CONVERTER] Iniciando conversão WebP→JPG: {FileName} ({Size} bytes)",
webpFile.FileName, webpFile.Length);
var originalSize = webpFile.Length;
// Limite para preview: 10MB
const long maxPreviewSize = 10 * 1024 * 1024;
using var webpStream = webpFile.OpenReadStream();
using var image = await Image.LoadAsync(webpStream);
using var memoryStream = new MemoryStream();
await image.SaveAsJpegAsync(memoryStream);
var jpgData = memoryStream.ToArray();
var convertedSize = jpgData.Length;
var fileName = Path.GetFileNameWithoutExtension(webpFile.FileName) + ".jpg";
_logger.LogInformation("[JPG-WEBP-CONVERTER] Conversão WebP→JPG concluída: {OutputFileName} (Original: {OriginalSize}bytes → Convertido: {ConvertedSize}bytes)",
fileName, originalSize, convertedSize);
// Se é request de preview e o arquivo não é muito grande
if (preview && originalSize <= maxPreviewSize && convertedSize <= maxPreviewSize)
{
var base64 = Convert.ToBase64String(jpgData);
var base64DataUrl = $"data:image/jpeg;base64,{base64}";
return Json(new
{
success = true,
base64 = base64DataUrl,
filename = fileName,
originalSize = originalSize,
convertedSize = convertedSize
});
}
// Download normal
return File(jpgData, "image/jpeg", fileName);
}
catch (UnknownImageFormatException)
{
_logger.LogWarning("[JPG-WEBP-CONVERTER] O arquivo WebP parece ser inválido ou o formato não é suportado.");
if (preview)
{
return Json(new { success = false, message = "Arquivo WebP inválido ou formato não suportado." });
}
ModelState.AddModelError("webpFile", "Arquivo WebP inválido ou formato não suportado.");
ViewBag.ConversionError = "Arquivo WebP inválido ou formato não suportado.";
PrepareIndexView();
return View("Index");
}
catch (Exception ex)
{
_logger.LogError(ex, "[JPG-WEBP-CONVERTER] Erro ao converter WebP para JPG: {FileName}", webpFile.FileName);
if (preview)
{
return Json(new { success = false, message = _localizer["ProcessingError"].Value });
}
ModelState.AddModelError("webpFile", _localizer["ProcessingError"]);
ViewBag.ConversionError = _localizer["ProcessingError"];
PrepareIndexView();
return View("Index");
}
}

View File

@ -0,0 +1,451 @@
@{
ViewData["Title"] = ViewBag.PageTitle;
}
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="text-center mb-4">
<h1 class="display-5">@ViewBag.PageTitle</h1>
<p class="lead text-muted">@ViewBag.PageDescription</p>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-lg-10 col-xl-8">
<div class="card shadow-sm">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">
<i class="bi bi-file-earmark-image me-2"></i>Conversor de Imagens
</h5>
</div>
<div class="card-body">
@if (ViewBag.ConversionError != null)
{
<div class="alert alert-danger" role="alert">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
@ViewBag.ConversionError
</div>
}
<!-- Navigation Tabs -->
<ul class="nav nav-tabs mb-4" id="converterTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="heic-to-jpg-tab" data-bs-toggle="tab" data-bs-target="#heic-to-jpg" type="button" role="tab" aria-controls="heic-to-jpg" aria-selected="true">
<i class="bi bi-arrow-right me-2"></i>@ViewBag.HeicToJpgTabTitle
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="jpg-to-heic-tab" data-bs-toggle="tab" data-bs-target="#jpg-to-heic" type="button" role="tab" aria-controls="jpg-to-heic" aria-selected="false">
<i class="bi bi-arrow-left me-2"></i>@ViewBag.JpgToHeicTabTitle
</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content" id="converterTabContent">
<!-- HEIC to JPG Tab -->
<div class="tab-pane fade show active" id="heic-to-jpg" role="tabpanel" aria-labelledby="heic-to-jpg-tab">
<form id="heicToJpgForm" asp-action="ConvertHeicToJpg" method="post" enctype="multipart/form-data" class="needs-validation">
<div asp-validation-summary="ModelOnly" class="alert alert-danger" role="alert"></div>
<div class="mb-4">
<label for="heicFile" class="form-label fw-semibold">@ViewBag.HeicFileInputLabel</label>
<input class="form-control" type="file" id="heicFile" name="heicFile" accept=".heic,.HEIC,.heif,.HEIF" required>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>Formatos aceitos: .heic, .HEIC, .heif, .HEIF (máx. 10MB para preview)
</div>
<div class="invalid-feedback">
Por favor, selecione um arquivo HEIC válido.
</div>
</div>
<div class="d-grid gap-2">
<button type="button" id="convertPreviewBtn" class="btn btn-primary">
<i class="bi bi-eye me-2"></i>Converter e Visualizar
</button>
<button type="submit" class="btn btn-outline-secondary">
<i class="bi bi-download me-2"></i>Converter e Baixar Diretamente
</button>
</div>
</form>
</div>
<!-- JPG to HEIC Tab -->
<div class="tab-pane fade" id="jpg-to-heic" role="tabpanel" aria-labelledby="jpg-to-heic-tab">
<form id="jpgToHeicForm" asp-action="ConvertJpgToHeic" method="post" enctype="multipart/form-data" class="needs-validation">
<div asp-validation-summary="ModelOnly" class="alert alert-danger" role="alert"></div>
<div class="mb-4">
<label for="jpgFile" class="form-label fw-semibold">@ViewBag.JpgFileInputLabel</label>
<input class="form-control" type="file" id="jpgFile" name="jpgFile" accept=".jpg,.jpeg,.JPG,.JPEG" required>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>Formatos aceitos: .jpg, .jpeg (máx. 10MB para preview)
</div>
<div class="invalid-feedback">
Por favor, selecione um arquivo JPG válido.
</div>
</div>
<div class="d-grid gap-2">
<button type="button" id="convertJpgPreviewBtn" class="btn btn-primary">
<i class="bi bi-eye me-2"></i>Converter e Visualizar
</button>
<button type="submit" class="btn btn-outline-secondary">
<i class="bi bi-download me-2"></i>Converter e Baixar Diretamente
</button>
</div>
</form>
</div>
</div>
<!-- Loading Spinner -->
<div id="loadingSpinner" class="text-center mt-4" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Convertendo...</span>
</div>
<p class="mt-2 text-muted">Convertendo sua imagem...</p>
</div>
<!-- Preview Area -->
<div id="previewArea" class="mt-4" style="display: none;">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="mb-0">
<i class="bi bi-image me-2"></i>Imagem Convertida
</h6>
<button id="downloadBtn" class="btn btn-success btn-sm">
<i class="bi bi-download me-1"></i>Baixar JPG
</button>
</div>
<div class="card-body text-center">
<img id="previewImage" src="" alt="Imagem convertida" class="img-fluid rounded" style="max-height: 400px; max-width: 100%;">
<div class="mt-2">
<small id="imageInfo" class="text-muted"></small>
</div>
</div>
</div>
</div>
<!-- Error Area -->
<div id="errorArea" class="mt-4" style="display: none;">
<div class="alert alert-warning" role="alert">
<i class="bi bi-exclamation-triangle me-2"></i>
<span id="errorMessage"></span>
<button id="fallbackDownloadBtn" class="btn btn-outline-primary btn-sm ms-2">
Tentar Download Direto
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- FAQ Accordion -->
<div class="row mt-5">
<div class="col-lg-10 mx-auto">
<div class="converter-faq">
<h3 class="h4 mb-3 text-center">Perguntas Frequentes</h3>
<div class="accordion" id="heicConverterFaqAccordion">
<div class="accordion-item">
<h2 class="accordion-header" id="headingWhat">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWhat" aria-expanded="false" aria-controls="collapseWhat">
<i class="bi bi-question-circle me-2"></i>@ViewBag.FaqWhatTitle
</button>
</h2>
<div id="collapseWhat" class="accordion-collapse collapse" aria-labelledby="headingWhat" data-bs-parent="#heicConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqWhatContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingHow">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseHow" aria-expanded="false" aria-controls="collapseHow">
<i class="bi bi-gear me-2"></i>@ViewBag.FaqHowTitle
</button>
</h2>
<div id="collapseHow" class="accordion-collapse collapse" aria-labelledby="headingHow" data-bs-parent="#heicConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqHowContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingWhy">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWhy" aria-expanded="false" aria-controls="collapseWhy">
<i class="bi bi-lightbulb me-2"></i>@ViewBag.FaqWhyTitle
</button>
</h2>
<div id="collapseWhy" class="accordion-collapse collapse" aria-labelledby="headingWhy" data-bs-parent="#heicConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqWhyContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingSecurity">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSecurity" aria-expanded="false" aria-controls="collapseSecurity">
<i class="bi bi-shield-check me-2"></i>@ViewBag.FaqSecurityTitle
</button>
</h2>
<div id="collapseSecurity" class="accordion-collapse collapse" aria-labelledby="headingSecurity" data-bs-parent="#heicConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqSecurityContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingLimits">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseLimits" aria-expanded="false" aria-controls="collapseLimits">
<i class="bi bi-exclamation-triangle me-2"></i>@ViewBag.FaqLimitsTitle
</button>
</h2>
<div id="collapseLimits" class="accordion-collapse collapse" aria-labelledby="headingLimits" data-bs-parent="#heicConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqLimitsContent
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.nav-tabs .nav-link.disabled {
background-color: #f8f9fa;
border-color: #dee2e6;
color: #6c757d;
cursor: not-allowed;
}
.nav-tabs .nav-link.disabled:hover {
background-color: #f8f9fa;
border-color: #dee2e6;
color: #6c757d;
}
#previewImage {
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
border-radius: 8px;
}
.spinner-border {
width: 3rem;
height: 3rem;
}
@@media (max-width: 576px) {
#previewImage {
max-height: 250px;
}
.card-header .btn {
font-size: 0.875rem;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const convertPreviewBtn = document.getElementById('convertPreviewBtn');
const convertJpgPreviewBtn = document.getElementById('convertJpgPreviewBtn');
const downloadBtn = document.getElementById('downloadBtn');
const fallbackDownloadBtn = document.getElementById('fallbackDownloadBtn');
const heicForm = document.getElementById('heicToJpgForm');
const jpgForm = document.getElementById('jpgToHeicForm');
const heicFileInput = document.getElementById('heicFile');
const jpgFileInput = document.getElementById('jpgFile');
const loadingSpinner = document.getElementById('loadingSpinner');
const previewArea = document.getElementById('previewArea');
const errorArea = document.getElementById('errorArea');
const previewImage = document.getElementById('previewImage');
const imageInfo = document.getElementById('imageInfo');
const errorMessage = document.getElementById('errorMessage');
let convertedImageData = null;
let convertedFileName = null;
// Bootstrap form validation
const forms = document.querySelectorAll('.needs-validation');
Array.from(forms).forEach(function(form) {
form.addEventListener('submit', function(event) {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
});
});
// File input validation
heicFileInput.addEventListener('change', function() {
hideAllAreas();
if (this.files.length > 0) {
const file = this.files[0];
const maxSize = 10 * 1024 * 1024; // 10MB
if (file.size > maxSize) {
showError('Arquivo muito grande para preview (máx. 10MB). Use "Converter e Baixar Diretamente".');
convertPreviewBtn.disabled = true;
} else {
convertPreviewBtn.disabled = false;
}
}
});
jpgFileInput.addEventListener('change', function() {
hideAllAreas();
if (this.files.length > 0) {
const file = this.files[0];
const maxSize = 10 * 1024 * 1024; // 10MB
if (file.size > maxSize) {
showError('Arquivo muito grande para preview (máx. 10MB). Use "Converter e Baixar Diretamente".');
convertJpgPreviewBtn.disabled = true;
} else {
convertJpgPreviewBtn.disabled = false;
}
}
});
// Convert and Preview button
convertPreviewBtn.addEventListener('click', async function() {
if (!heicFileInput.files[0]) {
showError('Por favor, selecione um arquivo HEIC primeiro.');
return;
}
await convertToPreview(heicForm);
});
// Convert JPG to HEIC Preview button
convertJpgPreviewBtn.addEventListener('click', async function() {
if (!jpgFileInput.files[0]) {
showError('Por favor, selecione um arquivo JPG primeiro.');
return;
}
await convertToPreview(jpgForm);
});
// Download button (after preview)
downloadBtn.addEventListener('click', function() {
if (convertedImageData && convertedFileName) {
downloadBase64Image(convertedImageData, convertedFileName);
}
});
// Fallback download button
fallbackDownloadBtn.addEventListener('click', function() {
const activeTab = document.querySelector('.nav-link.active');
const currentForm = activeTab.id === 'heic-to-jpg-tab' ? heicForm : jpgForm;
submitFormForDownload(currentForm);
});
async function convertToPreview(form) {
showLoading();
try {
const formData = new FormData(form);
const response = await fetch(form.action + '?preview=true', {
method: 'POST',
body: formData
});
if (response.ok) {
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
// JSON response with base64
const result = await response.json();
if (result.success) {
showPreview(result.base64, result.filename, result.originalSize, result.convertedSize);
} else {
showError(result.message || 'Erro na conversão. Tentando download direto...');
setTimeout(() => submitFormForDownload(form), 2000);
}
} else {
// Binary response - fallback to download
showError('Arquivo muito grande para preview. Iniciando download direto...');
setTimeout(() => submitFormForDownload(form), 1000);
}
} else {
const errorText = await response.text();
showError('Erro na conversão: ' + (errorText || response.statusText));
}
} catch (error) {
console.error('Conversion error:', error);
showError('Erro de conexão. Tentando download direto...');
setTimeout(() => submitFormForDownload(form), 2000);
}
}
function showPreview(base64Data, filename, originalSize, convertedSize) {
hideAllAreas();
previewImage.src = base64Data;
convertedImageData = base64Data;
convertedFileName = filename;
const originalSizeMB = (originalSize / (1024 * 1024)).toFixed(2);
const convertedSizeMB = (convertedSize / (1024 * 1024)).toFixed(2);
const reduction = (((originalSize - convertedSize) / originalSize) * 100).toFixed(1);
imageInfo.textContent = `Original: ${originalSizeMB}MB → Convertido: ${convertedSizeMB}MB (${reduction}% menor)`;
previewArea.style.display = 'block';
}
function showLoading() {
hideAllAreas();
loadingSpinner.style.display = 'block';
}
function showError(message) {
hideAllAreas();
errorMessage.textContent = message;
errorArea.style.display = 'block';
}
function hideAllAreas() {
loadingSpinner.style.display = 'none';
previewArea.style.display = 'none';
errorArea.style.display = 'none';
}
function submitFormForDownload(form) {
// Submit form normally for direct download
if (form) {
form.submit();
}
}
function downloadBase64Image(base64Data, filename) {
// Convert base64 to blob and download
const base64Response = fetch(base64Data);
base64Response.then(res => res.blob()).then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
});
}
});
</script>

View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<!-- Main Page Content -->
<data name="HeicConverterPageTitle" xml:space="preserve">
<value>Conversor HEIC a JPG Online Gratis</value>
</data>
<data name="HeicConverterPageDescription" xml:space="preserve">
<value>Convierte archivos HEIC a JPG de forma rápida y segura. Herramienta gratuita, sin registro, procesamiento local.</value>
</data>
<!-- Tab Titles -->
<data name="HeicToJpgTabTitle" xml:space="preserve">
<value>HEIC → JPG</value>
</data>
<data name="JpgToHeicTabTitle" xml:space="preserve">
<value>JPG → HEIC</value>
</data>
<!-- Form Labels -->
<data name="HeicFileInputLabel" xml:space="preserve">
<value>Selecciona el archivo HEIC</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecciona el archivo JPG</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="ConvertToHeicButton" xml:space="preserve">
<value>Convertir a HEIC</value>
</data>
<!-- Error Messages -->
<data name="SelectFileError" xml:space="preserve">
<value>Por favor, selecciona un archivo.</value>
</data>
<data name="InvalidHeicFileError" xml:space="preserve">
<value>Archivo inválido. Por favor, sube un archivo HEIC válido.</value>
</data>
<data name="InvalidJpgFileError" xml:space="preserve">
<value>Archivo inválido. Por favor, sube un archivo JPG válido.</value>
</data>
<data name="ProcessingError" xml:space="preserve">
<value>Ocurrió un error al procesar la imagen. Inténtalo de nuevo.</value>
</data>
<data name="PreviewButton" xml:space="preserve">
<value>Vista previa</value>
</data>
<!-- FAQ Content -->
<data name="HeicFaqWhatTitle" xml:space="preserve">
<value>¿Qué es este conversor HEIC?</value>
</data>
<data name="HeicFaqWhatContent" xml:space="preserve">
<value>Este es un conversor online gratuito que transforma archivos HEIC (High Efficiency Image Container) al formato JPG. HEIC es el formato estándar usado por iPhones e iPads desde iOS 11, ofreciendo mejor compresión que JPG manteniendo calidad similar.</value>
</data>
<data name="HeicFaqHowTitle" xml:space="preserve">
<value>¿Cómo funciona la conversión?</value>
</data>
<data name="HeicFaqHowContent" xml:space="preserve">
<value>1. Selecciona el archivo HEIC de tu dispositivo<br/>2. Haz clic en "Convertir a JPG"<br/>3. El archivo será procesado localmente en el servidor<br/>4. Descarga automática del archivo JPG convertido<br/>5. El archivo original se elimina automáticamente después de la conversión</value>
</data>
<data name="HeicFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir HEIC a JPG?</value>
</data>
<data name="HeicFaqWhyContent" xml:space="preserve">
<value>• <strong>Compatibilidad universal:</strong> JPG es soportado por todos los dispositivos y aplicaciones<br/>• <strong>Fácil compartir:</strong> Envía fotos sin problemas de compatibilidad<br/>• <strong>Trabajo profesional:</strong> Muchos softwares aún no soportan HEIC<br/>• <strong>Web e impresión:</strong> JPG es el estándar para sitios web y gráficas</value>
</data>
<data name="HeicFaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro usar este conversor?</value>
</data>
<data name="HeicFaqSecurityContent" xml:space="preserve">
<value>✅ <strong>100% Seguro:</strong> Procesamiento local en el servidor, sin envío a terceros<br/>✅ <strong>Privacidad garantizada:</strong> Los archivos se eliminan automáticamente después de la conversión<br/>✅ <strong>Sin almacenamiento:</strong> No mantenemos copias de tus archivos<br/>✅ <strong>Sin registro:</strong> Úsalo sin crear cuenta o proporcionar datos personales<br/>✅ <strong>HTTPS:</strong> Conexión cifrada para subida/descarga</value>
</data>
<data name="HeicFaqLimitsTitle" xml:space="preserve">
<value>¿Hay limitaciones en el conversor?</value>
</data>
<data name="HeicFaqLimitsContent" xml:space="preserve">
<value>• <strong>Tamaño máximo:</strong> 50MB por archivo<br/>• <strong>Formatos aceptados:</strong> .heic, .HEIC, .JPG, .JPEG<br/>• <strong>Salida:</strong> JPG y HEIC de alta calidad<br/>• <strong>Vista previa:</strong> Límite de 10MB para visualización<br/>• <strong>Conversión bidireccional:</strong> HEIC↔JPG totalmente funcional</value>
</data>
</root>

View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<!-- Main Page Content -->
<data name="HeicConverterPageTitle" xml:space="preserve">
<value>Conversor HEIC a JPG Online Gratis</value>
</data>
<data name="HeicConverterPageDescription" xml:space="preserve">
<value>Convierte archivos HEIC a JPG de forma rápida y segura. Herramienta gratuita, sin registro, procesamiento local.</value>
</data>
<!-- Tab Titles -->
<data name="HeicToJpgTabTitle" xml:space="preserve">
<value>HEIC → JPG</value>
</data>
<data name="JpgToHeicTabTitle" xml:space="preserve">
<value>JPG → HEIC</value>
</data>
<!-- Form Labels -->
<data name="HeicFileInputLabel" xml:space="preserve">
<value>Selecciona el archivo HEIC</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecciona el archivo JPG</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="ConvertToHeicButton" xml:space="preserve">
<value>Convertir a HEIC</value>
</data>
<!-- Error Messages -->
<data name="SelectFileError" xml:space="preserve">
<value>Por favor, selecciona un archivo.</value>
</data>
<data name="InvalidHeicFileError" xml:space="preserve">
<value>Archivo inválido. Por favor, sube un archivo HEIC válido.</value>
</data>
<data name="InvalidJpgFileError" xml:space="preserve">
<value>Archivo inválido. Por favor, sube un archivo JPG válido.</value>
</data>
<data name="ProcessingError" xml:space="preserve">
<value>Ocurrió un error al procesar la imagen. Inténtalo de nuevo.</value>
</data>
<data name="PreviewButton" xml:space="preserve">
<value>Vista previa</value>
</data>
<!-- FAQ Content -->
<data name="HeicFaqWhatTitle" xml:space="preserve">
<value>¿Qué es este conversor HEIC?</value>
</data>
<data name="HeicFaqWhatContent" xml:space="preserve">
<value>Este es un conversor online gratuito que transforma archivos HEIC (High Efficiency Image Container) al formato JPG. HEIC es el formato estándar usado por iPhones e iPads desde iOS 11, ofreciendo mejor compresión que JPG manteniendo calidad similar.</value>
</data>
<data name="HeicFaqHowTitle" xml:space="preserve">
<value>¿Cómo funciona la conversión?</value>
</data>
<data name="HeicFaqHowContent" xml:space="preserve">
<value>1. Selecciona el archivo HEIC de tu dispositivo<br/>2. Haz clic en "Convertir a JPG"<br/>3. El archivo será procesado localmente en el servidor<br/>4. Descarga automática del archivo JPG convertido<br/>5. El archivo original se elimina automáticamente después de la conversión</value>
</data>
<data name="HeicFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir HEIC a JPG?</value>
</data>
<data name="HeicFaqWhyContent" xml:space="preserve">
<value>• <strong>Compatibilidad universal:</strong> JPG es soportado por todos los dispositivos y aplicaciones<br/>• <strong>Fácil compartir:</strong> Envía fotos sin problemas de compatibilidad<br/>• <strong>Trabajo profesional:</strong> Muchos softwares aún no soportan HEIC<br/>• <strong>Web e impresión:</strong> JPG es el estándar para sitios web y gráficas</value>
</data>
<data name="HeicFaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro usar este conversor?</value>
</data>
<data name="HeicFaqSecurityContent" xml:space="preserve">
<value>✅ <strong>100% Seguro:</strong> Procesamiento local en el servidor, sin envío a terceros<br/>✅ <strong>Privacidad garantizada:</strong> Los archivos se eliminan automáticamente después de la conversión<br/>✅ <strong>Sin almacenamiento:</strong> No mantenemos copias de tus archivos<br/>✅ <strong>Sin registro:</strong> Úsalo sin crear cuenta o proporcionar datos personales<br/>✅ <strong>HTTPS:</strong> Conexión cifrada para subida/descarga</value>
</data>
<data name="HeicFaqLimitsTitle" xml:space="preserve">
<value>¿Hay limitaciones en el conversor?</value>
</data>
<data name="HeicFaqLimitsContent" xml:space="preserve">
<value>• <strong>Tamaño máximo:</strong> 50MB por archivo<br/>• <strong>Formatos aceptados:</strong> .heic, .HEIC, .JPG, .JPEG<br/>• <strong>Salida:</strong> JPG y HEIC de alta calidad<br/>• <strong>Vista previa:</strong> Límite de 10MB para visualización<br/>• <strong>Conversión bidireccional:</strong> HEIC↔JPG totalmente funcional</value>
</data>
</root>

View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<!-- Main Page Content -->
<data name="HeicConverterPageTitle" xml:space="preserve">
<value>Conversor HEIC a JPG Online Gratis</value>
</data>
<data name="HeicConverterPageDescription" xml:space="preserve">
<value>Convierte archivos HEIC a JPG de forma rápida y segura. Herramienta gratuita, sin registro, procesamiento local.</value>
</data>
<!-- Tab Titles -->
<data name="HeicToJpgTabTitle" xml:space="preserve">
<value>HEIC → JPG</value>
</data>
<data name="JpgToHeicTabTitle" xml:space="preserve">
<value>JPG → HEIC</value>
</data>
<!-- Form Labels -->
<data name="HeicFileInputLabel" xml:space="preserve">
<value>Selecciona el archivo HEIC</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecciona el archivo JPG</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="ConvertToHeicButton" xml:space="preserve">
<value>Convertir a HEIC</value>
</data>
<!-- Error Messages -->
<data name="SelectFileError" xml:space="preserve">
<value>Por favor, selecciona un archivo.</value>
</data>
<data name="InvalidHeicFileError" xml:space="preserve">
<value>Archivo inválido. Por favor, sube un archivo HEIC válido.</value>
</data>
<data name="InvalidJpgFileError" xml:space="preserve">
<value>Archivo inválido. Por favor, sube un archivo JPG válido.</value>
</data>
<data name="ProcessingError" xml:space="preserve">
<value>Ocurrió un error al procesar la imagen. Inténtalo de nuevo.</value>
</data>
<data name="PreviewButton" xml:space="preserve">
<value>Vista previa</value>
</data>
<!-- FAQ Content -->
<data name="HeicFaqWhatTitle" xml:space="preserve">
<value>¿Qué es este conversor HEIC?</value>
</data>
<data name="HeicFaqWhatContent" xml:space="preserve">
<value>Este es un conversor online gratuito que transforma archivos HEIC (High Efficiency Image Container) al formato JPG. HEIC es el formato estándar usado por iPhones e iPads desde iOS 11, ofreciendo mejor compresión que JPG manteniendo calidad similar.</value>
</data>
<data name="HeicFaqHowTitle" xml:space="preserve">
<value>¿Cómo funciona la conversión?</value>
</data>
<data name="HeicFaqHowContent" xml:space="preserve">
<value>1. Selecciona el archivo HEIC de tu dispositivo<br/>2. Haz clic en "Convertir a JPG"<br/>3. El archivo será procesado localmente en el servidor<br/>4. Descarga automática del archivo JPG convertido<br/>5. El archivo original se elimina automáticamente después de la conversión</value>
</data>
<data name="HeicFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir HEIC a JPG?</value>
</data>
<data name="HeicFaqWhyContent" xml:space="preserve">
<value>• <strong>Compatibilidad universal:</strong> JPG es soportado por todos los dispositivos y aplicaciones<br/>• <strong>Fácil compartir:</strong> Envía fotos sin problemas de compatibilidad<br/>• <strong>Trabajo profesional:</strong> Muchos softwares aún no soportan HEIC<br/>• <strong>Web e impresión:</strong> JPG es el estándar para sitios web y gráficas</value>
</data>
<data name="HeicFaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro usar este conversor?</value>
</data>
<data name="HeicFaqSecurityContent" xml:space="preserve">
<value>✅ <strong>100% Seguro:</strong> Procesamiento local en el servidor, sin envío a terceros<br/>✅ <strong>Privacidad garantizada:</strong> Los archivos se eliminan automáticamente después de la conversión<br/>✅ <strong>Sin almacenamiento:</strong> No mantenemos copias de tus archivos<br/>✅ <strong>Sin registro:</strong> Úsalo sin crear cuenta o proporcionar datos personales<br/>✅ <strong>HTTPS:</strong> Conexión cifrada para subida/descarga</value>
</data>
<data name="HeicFaqLimitsTitle" xml:space="preserve">
<value>¿Hay limitaciones en el conversor?</value>
</data>
<data name="HeicFaqLimitsContent" xml:space="preserve">
<value>• <strong>Tamaño máximo:</strong> 50MB por archivo<br/>• <strong>Formatos aceptados:</strong> .heic, .HEIC, .JPG, .JPEG<br/>• <strong>Salida:</strong> JPG y HEIC de alta calidad<br/>• <strong>Vista previa:</strong> Límite de 10MB para visualización<br/>• <strong>Conversión bidireccional:</strong> HEIC↔JPG totalmente funcional</value>
</data>
</root>

View File

@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<!-- Main Page Content -->
<data name="HeicConverterPageTitle" xml:space="preserve">
<value>Conversor HEIC para JPG Online Grátis</value>
</data>
<data name="HeicConverterPageDescription" xml:space="preserve">
<value>Converta arquivos HEIC para JPG de forma rápida e segura. Ferramenta gratuita, sem cadastro, processamento local.</value>
</data>
<!-- Tab Titles -->
<data name="HeicToJpgTabTitle" xml:space="preserve">
<value>HEIC → JPG</value>
</data>
<data name="JpgToHeicTabTitle" xml:space="preserve">
<value>JPG → HEIC</value>
</data>
<!-- Form Labels -->
<data name="HeicFileInputLabel" xml:space="preserve">
<value>Selecione o arquivo HEIC</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecione o arquivo JPG</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Converter para JPG</value>
</data>
<data name="ConvertToHeicButton" xml:space="preserve">
<value>Converter para HEIC</value>
</data>
<!-- Error Messages -->
<data name="SelectFileError" xml:space="preserve">
<value>Por favor, selecione um arquivo.</value>
</data>
<data name="InvalidHeicFileError" xml:space="preserve">
<value>Arquivo inválido. Por favor, envie um arquivo HEIC válido.</value>
</data>
<data name="InvalidJpgFileError" xml:space="preserve">
<value>Arquivo inválido. Por favor, envie um arquivo JPG válido.</value>
</data>
<data name="ProcessingError" xml:space="preserve">
<value>Ocorreu um erro ao processar a imagem. Tente novamente.</value>
</data>
<data name="PreviewButton" xml:space="preserve">
<value>Visualizar</value>
</data>
<!-- FAQ Content -->
<data name="HeicFaqWhatTitle" xml:space="preserve">
<value>O que é este conversor HEIC?</value>
</data>
<data name="HeicFaqWhatContent" xml:space="preserve">
<value>Este é um conversor online gratuito que transforma arquivos HEIC (High Efficiency Image Container) em formato JPG. HEIC é o formato padrão usado por iPhones e iPads desde iOS 11, oferecendo melhor compressão que JPG mantendo qualidade similar.</value>
</data>
<data name="HeicFaqHowTitle" xml:space="preserve">
<value>Como funciona a conversão?</value>
</data>
<data name="HeicFaqHowContent" xml:space="preserve">
<value>1. Selecione o arquivo HEIC do seu dispositivo<br/>2. Clique em "Converter para JPG"<br/>3. O arquivo será processado localmente no servidor<br/>4. Download automático do arquivo JPG convertido<br/>5. O arquivo original é removido automaticamente após a conversão</value>
</data>
<data name="HeicFaqWhyTitle" xml:space="preserve">
<value>Por que converter HEIC para JPG?</value>
</data>
<data name="HeicFaqWhyContent" xml:space="preserve">
<value>• <strong>Compatibilidade universal:</strong> JPG é suportado por todos os dispositivos e aplicações<br/>• <strong>Compartilhamento fácil:</strong> Envie fotos sem problemas de compatibilidade<br/>• <strong>Trabalho profissional:</strong> Muitos softwares ainda não suportam HEIC<br/>• <strong>Web e impressão:</strong> JPG é o padrão para websites e gráficas</value>
</data>
<data name="HeicFaqSecurityTitle" xml:space="preserve">
<value>É seguro usar este conversor?</value>
</data>
<data name="HeicFaqSecurityContent" xml:space="preserve">
<value>✅ <strong>100% Seguro:</strong> Processamento local no servidor, sem envio para terceiros<br/>✅ <strong>Privacidade garantida:</strong> Arquivos são removidos automaticamente após conversão<br/>✅ <strong>Sem armazenamento:</strong> Não mantemos cópias dos seus arquivos<br/>✅ <strong>Sem cadastro:</strong> Use sem criar conta ou fornecer dados pessoais<br/>✅ <strong>HTTPS:</strong> Conexão criptografada para upload/download</value>
</data>
<data name="HeicFaqLimitsTitle" xml:space="preserve">
<value>Há limitações no conversor?</value>
</data>
<data name="HeicFaqLimitsContent" xml:space="preserve">
<value>• <strong>Tamanho máximo:</strong> 50MB por arquivo<br/>• <strong>Formatos aceitos:</strong> .heic, .HEIC, .JPG, .JPEG<br/>• <strong>Saída:</strong> JPG e HEIC de alta qualidade<br/>• <strong>Preview:</strong> Limite de 10MB para visualização<br/>• <strong>Conversão bidirecional:</strong> HEIC↔JPG totalmente funcional</value>
</data>
</root>

View File

@ -2,18 +2,449 @@
ViewData["Title"] = ViewBag.PageTitle;
}
<h1>@ViewBag.PageTitle</h1>
<p>@ViewBag.PageDescription</p>
<div class="card mt-4">
<div class="card-body">
<form asp-action="Convert" method="post" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger mb-3"></div>
<div class="mb-3">
<label for="jpgFile" class="form-label">@ViewBag.FileInputLabel</label>
<input class="form-control" type="file" id="jpgFile" name="jpgFile" accept="image/jpeg" required>
<div class="container-fluid">
<div class="row">
<div class="col-12">
<div class="text-center mb-4">
<h1 class="display-5">@ViewBag.PageTitle</h1>
<p class="lead text-muted">@ViewBag.PageDescription</p>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-lg-10 col-xl-8">
<div class="card shadow-sm">
<div class="card-header bg-primary text-white">
<h5 class="mb-0">
<i class="bi bi-file-earmark-image me-2"></i>Conversor de Imagens
</h5>
</div>
<div class="card-body">
@if (ViewBag.ConversionError != null)
{
<div class="alert alert-danger" role="alert">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
@ViewBag.ConversionError
</div>
}
<!-- Navigation Tabs -->
<ul class="nav nav-tabs mb-4" id="converterTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="jpg-to-webp-tab" data-bs-toggle="tab" data-bs-target="#jpg-to-webp" type="button" role="tab" aria-controls="jpg-to-webp" aria-selected="true">
<i class="bi bi-arrow-right me-2"></i>@ViewBag.JpgToWebpTabTitle
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="webp-to-jpg-tab" data-bs-toggle="tab" data-bs-target="#webp-to-jpg" type="button" role="tab" aria-controls="webp-to-jpg" aria-selected="false">
<i class="bi bi-arrow-left me-2"></i>@ViewBag.WebpToJpgTabTitle
</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content" id="converterTabContent">
<!-- JPG to WebP Tab -->
<div class="tab-pane fade show active" id="jpg-to-webp" role="tabpanel" aria-labelledby="jpg-to-webp-tab">
<form id="jpgToWebpForm" asp-action="ConvertJpgToWebp" method="post" enctype="multipart/form-data" class="needs-validation">
<div asp-validation-summary="ModelOnly" class="alert alert-danger" role="alert"></div>
<div class="mb-4">
<label for="jpgFile" class="form-label fw-semibold">@ViewBag.JpgFileInputLabel</label>
<input class="form-control" type="file" id="jpgFile" name="jpgFile" accept=".jpg,.jpeg,.JPG,.JPEG" required>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>Formatos aceitos: .jpg, .jpeg (máx. 10MB para preview)
</div>
<div class="invalid-feedback">
Por favor, selecione um arquivo JPG válido.
</div>
</div>
<div class="d-grid gap-2">
<button type="button" id="convertJpgPreviewBtn" class="btn btn-primary">
<i class="bi bi-eye me-2"></i>Converter e Visualizar
</button>
<button type="submit" class="btn btn-outline-secondary">
<i class="bi bi-download me-2"></i>Converter e Baixar Diretamente
</button>
</div>
<button type="submit" class="btn btn-primary">@ViewBag.ConvertButton</button>
</form>
</div>
<!-- WebP to JPG Tab -->
<div class="tab-pane fade" id="webp-to-jpg" role="tabpanel" aria-labelledby="webp-to-jpg-tab">
<form id="webpToJpgForm" asp-action="ConvertWebpToJpg" method="post" enctype="multipart/form-data" class="needs-validation">
<div asp-validation-summary="ModelOnly" class="alert alert-danger" role="alert"></div>
<div class="mb-4">
<label for="webpFile" class="form-label fw-semibold">@ViewBag.WebpFileInputLabel</label>
<input class="form-control" type="file" id="webpFile" name="webpFile" accept=".webp,.WEBP" required>
<div class="form-text">
<i class="bi bi-info-circle me-1"></i>Formatos aceitos: .webp (máx. 10MB para preview)
</div>
<div class="invalid-feedback">
Por favor, selecione um arquivo WebP válido.
</div>
</div>
<div class="d-grid gap-2">
<button type="button" id="convertWebpPreviewBtn" class="btn btn-primary">
<i class="bi bi-eye me-2"></i>Converter e Visualizar
</button>
<button type="submit" class="btn btn-outline-secondary">
<i class="bi bi-download me-2"></i>Converter e Baixar Diretamente
</button>
</div>
</form>
</div>
</div>
<!-- Loading Spinner -->
<div id="loadingSpinner" class="text-center mt-4" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Convertendo...</span>
</div>
<p class="mt-2 text-muted">Convertendo sua imagem...</p>
</div>
<!-- Preview Area -->
<div id="previewArea" class="mt-4" style="display: none;">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<h6 class="mb-0">
<i class="bi bi-image me-2"></i>Imagem Convertida
</h6>
<button id="downloadBtn" class="btn btn-success btn-sm">
<i class="bi bi-download me-1"></i>Baixar
</button>
</div>
<div class="card-body text-center">
<img id="previewImage" src="" alt="Imagem convertida" class="img-fluid rounded" style="max-height: 400px; max-width: 100%;">
<div class="mt-2">
<small id="imageInfo" class="text-muted"></small>
</div>
</div>
</div>
</div>
<!-- Error Area -->
<div id="errorArea" class="mt-4" style="display: none;">
<div class="alert alert-warning" role="alert">
<i class="bi bi-exclamation-triangle me-2"></i>
<span id="errorMessage"></span>
<button id="fallbackDownloadBtn" class="btn btn-outline-primary btn-sm ms-2">
Tentar Download Direto
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- FAQ Accordion -->
<div class="row mt-5">
<div class="col-lg-10 mx-auto">
<div class="converter-faq">
<h3 class="h4 mb-3 text-center">Perguntas Frequentes</h3>
<div class="accordion" id="jpgWebpConverterFaqAccordion">
<div class="accordion-item">
<h2 class="accordion-header" id="headingWhatJpgWebp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWhatJpgWebp" aria-expanded="false" aria-controls="collapseWhatJpgWebp">
<i class="bi bi-question-circle me-2"></i>@ViewBag.FaqWhatTitle
</button>
</h2>
<div id="collapseWhatJpgWebp" class="accordion-collapse collapse" aria-labelledby="headingWhatJpgWebp" data-bs-parent="#jpgWebpConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqWhatContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingHowJpgWebp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseHowJpgWebp" aria-expanded="false" aria-controls="collapseHowJpgWebp">
<i class="bi bi-gear me-2"></i>@ViewBag.FaqHowTitle
</button>
</h2>
<div id="collapseHowJpgWebp" class="accordion-collapse collapse" aria-labelledby="headingHowJpgWebp" data-bs-parent="#jpgWebpConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqHowContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingWhyJpgWebp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWhyJpgWebp" aria-expanded="false" aria-controls="collapseWhyJpgWebp">
<i class="bi bi-lightbulb me-2"></i>@ViewBag.FaqWhyTitle
</button>
</h2>
<div id="collapseWhyJpgWebp" class="accordion-collapse collapse" aria-labelledby="headingWhyJpgWebp" data-bs-parent="#jpgWebpConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqWhyContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingSecurityJpgWebp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSecurityJpgWebp" aria-expanded="false" aria-controls="collapseSecurityJpgWebp">
<i class="bi bi-shield-check me-2"></i>@ViewBag.FaqSecurityTitle
</button>
</h2>
<div id="collapseSecurityJpgWebp" class="accordion-collapse collapse" aria-labelledby="headingSecurityJpgWebp" data-bs-parent="#jpgWebpConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqSecurityContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingLimitsJpgWebp">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseLimitsJpgWebp" aria-expanded="false" aria-controls="collapseLimitsJpgWebp">
<i class="bi bi-exclamation-triangle me-2"></i>@ViewBag.FaqLimitsTitle
</button>
</h2>
<div id="collapseLimitsJpgWebp" class="accordion-collapse collapse" aria-labelledby="headingLimitsJpgWebp" data-bs-parent="#jpgWebpConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqLimitsContent
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<style>
.nav-tabs .nav-link.disabled {
background-color: #f8f9fa;
border-color: #dee2e6;
color: #6c757d;
cursor: not-allowed;
}
.nav-tabs .nav-link.disabled:hover {
background-color: #f8f9fa;
border-color: #dee2e6;
color: #6c757d;
}
#previewImage {
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
border-radius: 8px;
}
.spinner-border {
width: 3rem;
height: 3rem;
}
@@media (max-width: 576px) {
#previewImage {
max-height: 250px;
}
.card-header .btn {
font-size: 0.875rem;
}
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
const convertJpgPreviewBtn = document.getElementById('convertJpgPreviewBtn');
const convertWebpPreviewBtn = document.getElementById('convertWebpPreviewBtn');
const downloadBtn = document.getElementById('downloadBtn');
const fallbackDownloadBtn = document.getElementById('fallbackDownloadBtn');
const jpgForm = document.getElementById('jpgToWebpForm');
const webpForm = document.getElementById('webpToJpgForm');
const jpgFileInput = document.getElementById('jpgFile');
const webpFileInput = document.getElementById('webpFile');
const loadingSpinner = document.getElementById('loadingSpinner');
const previewArea = document.getElementById('previewArea');
const errorArea = document.getElementById('errorArea');
const previewImage = document.getElementById('previewImage');
const imageInfo = document.getElementById('imageInfo');
const errorMessage = document.getElementById('errorMessage');
let convertedImageData = null;
let convertedFileName = null;
// Bootstrap form validation
const forms = document.querySelectorAll('.needs-validation');
Array.from(forms).forEach(function(form) {
form.addEventListener('submit', function(event) {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
});
});
// File input validation
jpgFileInput.addEventListener('change', function() {
hideAllAreas();
if (this.files.length > 0) {
const file = this.files[0];
const maxSize = 10 * 1024 * 1024; // 10MB
if (file.size > maxSize) {
showError('Arquivo muito grande para preview (máx. 10MB). Use "Converter e Baixar Diretamente".');
convertJpgPreviewBtn.disabled = true;
} else {
convertJpgPreviewBtn.disabled = false;
}
}
});
webpFileInput.addEventListener('change', function() {
hideAllAreas();
if (this.files.length > 0) {
const file = this.files[0];
const maxSize = 10 * 1024 * 1024; // 10MB
if (file.size > maxSize) {
showError('Arquivo muito grande para preview (máx. 10MB). Use "Converter e Baixar Diretamente".');
convertWebpPreviewBtn.disabled = true;
} else {
convertWebpPreviewBtn.disabled = false;
}
}
});
// Convert and Preview buttons
convertJpgPreviewBtn.addEventListener('click', async function() {
if (!jpgFileInput.files[0]) {
showError('Por favor, selecione um arquivo JPG primeiro.');
return;
}
await convertToPreview(jpgForm);
});
convertWebpPreviewBtn.addEventListener('click', async function() {
if (!webpFileInput.files[0]) {
showError('Por favor, selecione um arquivo WebP primeiro.');
return;
}
await convertToPreview(webpForm);
});
// Download button (after preview)
downloadBtn.addEventListener('click', function() {
if (convertedImageData && convertedFileName) {
downloadBase64Image(convertedImageData, convertedFileName);
}
});
// Fallback download button
fallbackDownloadBtn.addEventListener('click', function() {
const activeTab = document.querySelector('.nav-link.active');
const currentForm = activeTab.id === 'jpg-to-webp-tab' ? jpgForm : webpForm;
submitFormForDownload(currentForm);
});
async function convertToPreview(form) {
showLoading();
try {
const formData = new FormData(form);
const response = await fetch(form.action + '?preview=true', {
method: 'POST',
body: formData
});
if (response.ok) {
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
// JSON response with base64
const result = await response.json();
if (result.success) {
showPreview(result.base64, result.filename, result.originalSize, result.convertedSize);
} else {
showError(result.message || 'Erro na conversão. Tentando download direto...');
setTimeout(() => submitFormForDownload(form), 2000);
}
} else {
// Binary response - fallback to download
showError('Arquivo muito grande para preview. Iniciando download direto...');
setTimeout(() => submitFormForDownload(form), 1000);
}
} else {
const errorText = await response.text();
showError('Erro na conversão: ' + (errorText || response.statusText));
}
} catch (error) {
console.error('Conversion error:', error);
showError('Erro de conexão. Tentando download direto...');
setTimeout(() => submitFormForDownload(form), 2000);
}
}
function showPreview(base64Data, filename, originalSize, convertedSize) {
hideAllAreas();
previewImage.src = base64Data;
convertedImageData = base64Data;
convertedFileName = filename;
const originalSizeMB = (originalSize / (1024 * 1024)).toFixed(2);
const convertedSizeMB = (convertedSize / (1024 * 1024)).toFixed(2);
const reduction = (((originalSize - convertedSize) / originalSize) * 100).toFixed(1);
imageInfo.textContent = `Original: ${originalSizeMB}MB → Convertido: ${convertedSizeMB}MB (${reduction}% menor)`;
previewArea.style.display = 'block';
}
function showLoading() {
hideAllAreas();
loadingSpinner.style.display = 'block';
}
function showError(message) {
hideAllAreas();
errorMessage.textContent = message;
errorArea.style.display = 'block';
}
function hideAllAreas() {
loadingSpinner.style.display = 'none';
previewArea.style.display = 'none';
errorArea.style.display = 'none';
}
function submitFormForDownload(form) {
// Submit form normally for direct download
if (form) {
form.submit();
}
}
function downloadBase64Image(base64Data, filename) {
// Convert base64 to blob and download
const base64Response = fetch(base64Data);
base64Response.then(res => res.blob()).then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
});
}
});
</script>

View File

@ -1,15 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="PageTitle" xml:space="preserve">
<value>Convertir JPG a WebP</value>
<value>Convertidor JPG ↔ WebP - Convert-It Online</value>
</data>
<data name="PageDescription" xml:space="preserve">
<value>Sube una imagen JPG para convertirla al formato WebP.</value>
<value>Convierte fácilmente entre los formatos JPG y WebP. Transforma JPG a WebP para mejor compresión o WebP a JPG para mayor compatibilidad.</value>
</data>
<data name="FileInputLabel" xml:space="preserve">
<value>Selecciona el archivo:</value>
<data name="JpgToWebpTabTitle" xml:space="preserve">
<value>JPG → WebP</value>
</data>
<data name="ConvertButton" xml:space="preserve">
<value>Convertir Ahora</value>
<data name="WebpToJpgTabTitle" xml:space="preserve">
<value>WebP → JPG</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Seleccionar archivo JPG</value>
</data>
<data name="WebpFileInputLabel" xml:space="preserve">
<value>Seleccionar archivo WebP</value>
</data>
<data name="ConvertToWebpButton" xml:space="preserve">
<value>Convertir a WebP</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="PreviewButton" xml:space="preserve">
<value>Vista previa</value>
</data>
<data name="FaqWhatTitle" xml:space="preserve">
<value>¿Qué son JPG y WebP?</value>
</data>
<data name="FaqWhatContent" xml:space="preserve">
<value>JPG es un formato clásico de compresión de imagen ampliamente compatible. WebP es un formato moderno desarrollado por Google que ofrece mejor compresión manteniendo la calidad de la imagen.</value>
</data>
<data name="FaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir entre JPG y WebP?</value>
</data>
<data name="FaqHowContent" xml:space="preserve">
<value>Es simple: 1. Elige la pestaña de la conversión deseada (JPG→WebP o WebP→JPG). 2. Haz clic en 'Seleccionar archivo' y elige tu imagen. 3. Haz clic en 'Vista previa' para preview o 'Convertir' para descarga directa.</value>
</data>
<data name="FaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir entre JPG y WebP?</value>
</data>
<data name="FaqWhyContent" xml:space="preserve">
<value>JPG→WebP: Reduce significativamente el tamaño del archivo manteniendo la calidad, ideal para web. WebP→JPG: Garantiza compatibilidad universal con cualquier dispositivo o software que no soporte WebP.</value>
</data>
<data name="FaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro convertir mis archivos aquí?</value>
</data>
<data name="FaqSecurityContent" xml:space="preserve">
<value>Absolutamente. Todas las conversiones se procesan de forma segura y tus archivos se eliminan automáticamente después del procesamiento. No almacenamos ninguna de tus imágenes.</value>
</data>
<data name="FaqLimitsTitle" xml:space="preserve">
<value>¿Hay límites de tamaño de archivo?</value>
</data>
<data name="FaqLimitsContent" xml:space="preserve">
<value>Para la funcionalidad de vista previa, el límite es de 10MB por archivo. Para conversiones directas, aceptamos archivos más grandes dentro de límites razonables para garantizar buen rendimiento.</value>
</data>
</root>

View File

@ -1,15 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="PageTitle" xml:space="preserve">
<value>Convertir JPG a WebP</value>
<value>Convertidor JPG ↔ WebP - Convert-It Online</value>
</data>
<data name="PageDescription" xml:space="preserve">
<value>Suba una imagen JPG para convertirla al formato WebP.</value>
<value>Convierte fácilmente entre los formatos JPG y WebP. Transforma JPG a WebP para mejor compresión o WebP a JPG para mayor compatibilidad.</value>
</data>
<data name="FileInputLabel" xml:space="preserve">
<value>Seleccione el archivo:</value>
<data name="JpgToWebpTabTitle" xml:space="preserve">
<value>JPG → WebP</value>
</data>
<data name="ConvertButton" xml:space="preserve">
<value>Convertir Ahora</value>
<data name="WebpToJpgTabTitle" xml:space="preserve">
<value>WebP → JPG</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Seleccionar archivo JPG</value>
</data>
<data name="WebpFileInputLabel" xml:space="preserve">
<value>Seleccionar archivo WebP</value>
</data>
<data name="ConvertToWebpButton" xml:space="preserve">
<value>Convertir a WebP</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="PreviewButton" xml:space="preserve">
<value>Vista previa</value>
</data>
<data name="FaqWhatTitle" xml:space="preserve">
<value>¿Qué son JPG y WebP?</value>
</data>
<data name="FaqWhatContent" xml:space="preserve">
<value>JPG es un formato clásico de compresión de imagen ampliamente compatible. WebP es un formato moderno desarrollado por Google que ofrece mejor compresión manteniendo la calidad de la imagen.</value>
</data>
<data name="FaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir entre JPG y WebP?</value>
</data>
<data name="FaqHowContent" xml:space="preserve">
<value>Es simple: 1. Elige la pestaña de la conversión deseada (JPG→WebP o WebP→JPG). 2. Haz clic en 'Seleccionar archivo' y elige tu imagen. 3. Haz clic en 'Vista previa' para preview o 'Convertir' para descarga directa.</value>
</data>
<data name="FaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir entre JPG y WebP?</value>
</data>
<data name="FaqWhyContent" xml:space="preserve">
<value>JPG→WebP: Reduce significativamente el tamaño del archivo manteniendo la calidad, ideal para web. WebP→JPG: Garantiza compatibilidad universal con cualquier dispositivo o software que no soporte WebP.</value>
</data>
<data name="FaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro convertir mis archivos aquí?</value>
</data>
<data name="FaqSecurityContent" xml:space="preserve">
<value>Absolutamente. Todas las conversiones se procesan de forma segura y tus archivos se eliminan automáticamente después del procesamiento. No almacenamos ninguna de tus imágenes.</value>
</data>
<data name="FaqLimitsTitle" xml:space="preserve">
<value>¿Hay límites de tamaño de archivo?</value>
</data>
<data name="FaqLimitsContent" xml:space="preserve">
<value>Para la funcionalidad de vista previa, el límite es de 10MB por archivo. Para conversiones directas, aceptamos archivos más grandes dentro de límites razonables para garantizar buen rendimiento.</value>
</data>
</root>

View File

@ -1,15 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="PageTitle" xml:space="preserve">
<value>Convertir JPG a WebP</value>
<value>Convertidor JPG ↔ WebP - Convert-It Online</value>
</data>
<data name="PageDescription" xml:space="preserve">
<value>Sube una imagen JPG para convertirla al formato WebP.</value>
<value>Convertir fácilmente entre los formatos JPG y WebP. Transformar JPG a WebP para mejor compresión o WebP a JPG para mayor compatibilidad.</value>
</data>
<data name="FileInputLabel" xml:space="preserve">
<value>Selecciona el archivo:</value>
<data name="JpgToWebpTabTitle" xml:space="preserve">
<value>JPG → WebP</value>
</data>
<data name="ConvertButton" xml:space="preserve">
<value>Convertir Ahora</value>
<data name="WebpToJpgTabTitle" xml:space="preserve">
<value>WebP → JPG</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Seleccionar archivo JPG</value>
</data>
<data name="WebpFileInputLabel" xml:space="preserve">
<value>Seleccionar archivo WebP</value>
</data>
<data name="ConvertToWebpButton" xml:space="preserve">
<value>Convertir a WebP</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="PreviewButton" xml:space="preserve">
<value>Vista previa</value>
</data>
<data name="FaqWhatTitle" xml:space="preserve">
<value>¿Qué son JPG y WebP?</value>
</data>
<data name="FaqWhatContent" xml:space="preserve">
<value>JPG es un formato clásico de compresión de imagen ampliamente compatible. WebP es un formato moderno desarrollado por Google que ofrece mejor compresión manteniendo la calidad de la imagen.</value>
</data>
<data name="FaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir entre JPG y WebP?</value>
</data>
<data name="FaqHowContent" xml:space="preserve">
<value>Es simple: 1. Elegir la pestaña de la conversión deseada (JPG→WebP o WebP→JPG). 2. Hacer clic en 'Seleccionar archivo' y elegir tu imagen. 3. Hacer clic en 'Vista previa' para preview o 'Convertir' para descarga directa.</value>
</data>
<data name="FaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir entre JPG y WebP?</value>
</data>
<data name="FaqWhyContent" xml:space="preserve">
<value>JPG→WebP: Reduce significativamente el tamaño del archivo manteniendo la calidad, ideal para web. WebP→JPG: Garantiza compatibilidad universal con cualquier dispositivo o software que no soporte WebP.</value>
</data>
<data name="FaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro convertir mis archivos aquí?</value>
</data>
<data name="FaqSecurityContent" xml:space="preserve">
<value>Absolutamente. Todas las conversiones se procesan de forma segura y tus archivos se eliminan automáticamente después del procesamiento. No almacenamos ninguna de tus imágenes.</value>
</data>
<data name="FaqLimitsTitle" xml:space="preserve">
<value>¿Hay límites de tamaño de archivo?</value>
</data>
<data name="FaqLimitsContent" xml:space="preserve">
<value>Para la funcionalidad de vista previa, el límite es de 10MB por archivo. Para conversiones directas, aceptamos archivos más grandes dentro de límites razonables para garantizar buen rendimiento.</value>
</data>
</root>

View File

@ -1,15 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<data name="PageTitle" xml:space="preserve">
<value>Converter JPG para WebP</value>
<value>Conversor JPG ↔ WebP - Convert-It Online</value>
</data>
<data name="PageDescription" xml:space="preserve">
<value>Faça o upload de uma imagem JPG para convertê-la para o formato WebP.</value>
<value>Converta facilmente entre os formatos JPG e WebP. Transforme JPG em WebP para melhor compressão ou WebP em JPG para maior compatibilidade.</value>
</data>
<data name="FileInputLabel" xml:space="preserve">
<value>Selecione o arquivo:</value>
<data name="JpgToWebpTabTitle" xml:space="preserve">
<value>JPG → WebP</value>
</data>
<data name="ConvertButton" xml:space="preserve">
<value>Converter Agora</value>
<data name="WebpToJpgTabTitle" xml:space="preserve">
<value>WebP → JPG</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecionar arquivo JPG</value>
</data>
<data name="WebpFileInputLabel" xml:space="preserve">
<value>Selecionar arquivo WebP</value>
</data>
<data name="ConvertToWebpButton" xml:space="preserve">
<value>Converter para WebP</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Converter para JPG</value>
</data>
<data name="PreviewButton" xml:space="preserve">
<value>Visualizar</value>
</data>
<data name="FaqWhatTitle" xml:space="preserve">
<value>O que são JPG e WebP?</value>
</data>
<data name="FaqWhatContent" xml:space="preserve">
<value>JPG é um formato clássico de compressão de imagem amplamente compatível. WebP é um formato moderno desenvolvido pelo Google que oferece melhor compressão mantendo a qualidade da imagem.</value>
</data>
<data name="FaqHowTitle" xml:space="preserve">
<value>Como converter entre JPG e WebP?</value>
</data>
<data name="FaqHowContent" xml:space="preserve">
<value>É simples: 1. Escolha a aba da conversão desejada (JPG→WebP ou WebP→JPG). 2. Clique em 'Selecionar arquivo' e escolha sua imagem. 3. Clique em 'Visualizar' para preview ou 'Converter' para download direto.</value>
</data>
<data name="FaqWhyTitle" xml:space="preserve">
<value>Por que converter entre JPG e WebP?</value>
</data>
<data name="FaqWhyContent" xml:space="preserve">
<value>JPG→WebP: Reduz significativamente o tamanho do arquivo mantendo a qualidade, ideal para web. WebP→JPG: Garante compatibilidade universal com qualquer dispositivo ou software que não suporte WebP.</value>
</data>
<data name="FaqSecurityTitle" xml:space="preserve">
<value>É seguro converter meus arquivos aqui?</value>
</data>
<data name="FaqSecurityContent" xml:space="preserve">
<value>Absolutamente. Todas as conversões são processadas de forma segura e seus arquivos são automaticamente excluídos após o processamento. Não armazenamos nenhuma de suas imagens.</value>
</data>
<data name="FaqLimitsTitle" xml:space="preserve">
<value>Há limites de tamanho de arquivo?</value>
</data>
<data name="FaqLimitsContent" xml:space="preserve">
<value>Para a funcionalidade de preview, o limite é de 10MB por arquivo. Para conversões diretas, aceitamos arquivos maiores dentro de limites razoáveis para garantir boa performance.</value>
</data>
</root>

View File

@ -55,6 +55,18 @@ namespace Convert_It_Online.Areas.TextTools.Controllers
ViewBag.ToSentenceCaseButton = _localizer["ToSentenceCaseButton"];
ViewBag.ResultTitle = _localizer["ResultTitle"];
// FAQ properties
ViewBag.FaqWhatTitle = _localizer["CaseFaqWhatTitle"];
ViewBag.FaqWhatContent = _localizer["CaseFaqWhatContent"];
ViewBag.FaqHowTitle = _localizer["CaseFaqHowTitle"];
ViewBag.FaqHowContent = _localizer["CaseFaqHowContent"];
ViewBag.FaqWhyTitle = _localizer["CaseFaqWhyTitle"];
ViewBag.FaqWhyContent = _localizer["CaseFaqWhyContent"];
ViewBag.FaqSecurityTitle = _localizer["CaseFaqSecurityTitle"];
ViewBag.FaqSecurityContent = _localizer["CaseFaqSecurityContent"];
ViewBag.FaqLimitsTitle = _localizer["CaseFaqLimitsTitle"];
ViewBag.FaqLimitsContent = _localizer["CaseFaqLimitsContent"];
var model = new CaseConverterViewModel();
return View(model);
}

View File

@ -27,3 +27,78 @@
<h2>@ViewBag.ResultTitle</h2>
<textarea asp-for="ResultText" class="form-control" rows="8" readonly="readonly"></textarea>
}
<!-- FAQ Accordion -->
<div class="row mt-5">
<div class="col-lg-10 mx-auto">
<div class="converter-faq">
<h3 class="h4 mb-3 text-center">Perguntas Frequentes</h3>
<div class="accordion" id="caseConverterFaqAccordion">
<div class="accordion-item">
<h2 class="accordion-header" id="headingWhatCase">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWhatCase" aria-expanded="false" aria-controls="collapseWhatCase">
<i class="bi bi-question-circle me-2"></i>@ViewBag.FaqWhatTitle
</button>
</h2>
<div id="collapseWhatCase" class="accordion-collapse collapse" aria-labelledby="headingWhatCase" data-bs-parent="#caseConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqWhatContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingHowCase">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseHowCase" aria-expanded="false" aria-controls="collapseHowCase">
<i class="bi bi-gear me-2"></i>@ViewBag.FaqHowTitle
</button>
</h2>
<div id="collapseHowCase" class="accordion-collapse collapse" aria-labelledby="headingHowCase" data-bs-parent="#caseConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqHowContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingWhyCase">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseWhyCase" aria-expanded="false" aria-controls="collapseWhyCase">
<i class="bi bi-lightbulb me-2"></i>@ViewBag.FaqWhyTitle
</button>
</h2>
<div id="collapseWhyCase" class="accordion-collapse collapse" aria-labelledby="headingWhyCase" data-bs-parent="#caseConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqWhyContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingSecurityCase">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSecurityCase" aria-expanded="false" aria-controls="collapseSecurityCase">
<i class="bi bi-shield-check me-2"></i>@ViewBag.FaqSecurityTitle
</button>
</h2>
<div id="collapseSecurityCase" class="accordion-collapse collapse" aria-labelledby="headingSecurityCase" data-bs-parent="#caseConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqSecurityContent
</div>
</div>
</div>
<div class="accordion-item">
<h2 class="accordion-header" id="headingLimitsCase">
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseLimitsCase" aria-expanded="false" aria-controls="collapseLimitsCase">
<i class="bi bi-exclamation-triangle me-2"></i>@ViewBag.FaqLimitsTitle
</button>
</h2>
<div id="collapseLimitsCase" class="accordion-collapse collapse" aria-labelledby="headingLimitsCase" data-bs-parent="#caseConverterFaqAccordion">
<div class="accordion-body">
@ViewBag.FaqLimitsContent
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,100 @@
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
namespace Convert_It_Online.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
private readonly ILogger<HealthController> _logger;
private static readonly DateTime _startTime = DateTime.UtcNow;
public HealthController(ILogger<HealthController> logger)
{
_logger = logger;
}
[HttpGet]
[Route("")]
[Route("check")]
public IActionResult HealthCheck()
{
try
{
var uptimeMinutes = (DateTime.UtcNow - _startTime).TotalMinutes;
var memoryBytes = GC.GetTotalMemory(false);
var memoryMB = Math.Round(memoryBytes / 1024.0 / 1024.0, 2);
_logger.LogInformation("[HEALTH] Memory: {memoryBytes} MemoryMB: {memoryMB} ThreadPool: {threadPool} ProcessId: {processId} ActiveConnections: {activeConnections} UptimeMinutes: {uptimeMinutes}",
memoryBytes,
memoryMB,
ThreadPool.ThreadCount,
Process.GetCurrentProcess().Id,
HttpContext.Connection?.Id ?? "null",
Math.Round(uptimeMinutes, 1));
var response = new
{
status = "healthy",
timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC"),
uptime = new
{
minutes = Math.Round(uptimeMinutes, 1),
hours = Math.Round(uptimeMinutes / 60, 1),
days = Math.Round(uptimeMinutes / 60 / 24, 1)
},
memory = new
{
bytes = memoryBytes,
mb = memoryMB,
kb = Math.Round(memoryBytes / 1024.0, 2)
},
system = new
{
processId = Process.GetCurrentProcess().Id,
threadPool = ThreadPool.ThreadCount,
environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Unknown",
machineName = Environment.MachineName,
framework = Environment.Version.ToString()
},
connection = new
{
id = HttpContext.Connection?.Id ?? "null",
remoteIp = HttpContext.Connection?.RemoteIpAddress?.ToString() ?? "unknown",
localIp = HttpContext.Connection?.LocalIpAddress?.ToString() ?? "unknown"
}
};
return Ok(response);
}
catch (Exception ex)
{
_logger.LogError(ex, "[HEALTH] Health check failed");
return StatusCode(500, new { status = "unhealthy", error = ex.Message });
}
}
[HttpGet("uptime-kuma")]
public IActionResult UptimeKuma()
{
try
{
var uptimeMinutes = (DateTime.UtcNow - _startTime).TotalMinutes;
_logger.LogInformation("[HEALTH-KUMA] Uptime check: {uptimeMinutes} minutes", Math.Round(uptimeMinutes, 1));
return Ok(new {
status = "ok",
uptime = Math.Round(uptimeMinutes, 1),
timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss UTC")
});
}
catch (Exception ex)
{
_logger.LogError(ex, "[HEALTH-KUMA] Uptime Kuma check failed");
return StatusCode(500, new { status = "error", message = ex.Message });
}
}
}
}

View File

@ -7,8 +7,8 @@ namespace Convert_It_Online.Controllers
// ViewModel para representar uma ferramenta no menu da Home
public class ToolViewModel
{
public required string TitleKey { get; set; }
public required string DescriptionKey { get; set; }
public required string Title { get; set; }
public required string Description { get; set; }
public required string Area { get; set; }
public required string Controller { get; set; }
public required string IconClass { get; set; } // Propriedade para o ícone
@ -31,6 +31,7 @@ namespace Convert_It_Online.Controllers
ViewBag.ImageMenuTitle = _localizer["ImageMenuTitle"];
ViewBag.CaseConverterTitle = _localizer["CaseConverterTitle"];
ViewBag.JpgToWebpTitle = _localizer["JpgToWebpTitle"];
ViewBag.HeicToJpgTitle = _localizer["HeicToJpgTitle"];
ViewBag.FooterText = _localizer["FooterText"];
ViewBag.About = _localizer["About"];
ViewBag.Contact = _localizer["Contact"];
@ -42,38 +43,44 @@ namespace Convert_It_Online.Controllers
SetCommonViewBagProperties();
ViewBag.PageTitle = _localizer["PageTitle"];
ViewBag.Subtitle = _localizer["Subtitle"];
ViewBag.ChooseConverter = _localizer["ChooseConverter"];
ViewBag.AboutSiteTitle = _localizer["AboutSiteTitle"];
ViewBag.AboutSiteContent = _localizer["AboutSiteContent"];
ViewBag.WhyFreeTitle = _localizer["WhyFreeTitle"];
ViewBag.WhyFreeContent = _localizer["WhyFreeContent"];
ViewBag.SecurityTitle = _localizer["SecurityTitle"];
ViewBag.SecurityContent = _localizer["SecurityContent"];
ViewBag.TextToolsTitle = _localizer["TextToolsTitle"];
ViewBag.TextToolsDescription = _localizer["TextToolsDescription"];
ViewBag.ImageToolsTitle = _localizer["ImageToolsTitle"];
ViewBag.ImageToolsDescription = _localizer["ImageToolsDescription"];
var availableTools = new List<ToolViewModel>
ViewBag.AllConvertersTitle = _localizer["AllConvertersTitle"];
ViewBag.UseConverterButton = _localizer["UseConverterButton"];
var individualConverters = new List<ToolViewModel>
{
new ToolViewModel
{
TitleKey = "TextToolsTitle",
DescriptionKey = "TextToolsDescription",
Title = _localizer["CaseConverterIndividualTitle"],
Description = _localizer["CaseConverterIndividualDescription"],
Area = "TextTools",
Controller = "CaseConverter",
IconClass = "bi-fonts"
},
new ToolViewModel
{
TitleKey = "ImageToolsTitle",
DescriptionKey = "ImageToolsDescription",
Title = _localizer["JpgToWebpIndividualTitle"],
Description = _localizer["JpgToWebpIndividualDescription"],
Area = "ImageConverters",
Controller = "JpgToWebp",
IconClass = "bi-image-alt"
IconClass = "bi-file-earmark-image"
},
new ToolViewModel
{
Title = _localizer["HeicToJpgIndividualTitle"],
Description = _localizer["HeicToJpgIndividualDescription"],
Area = "ImageConverters",
Controller = "HeicToJpg",
IconClass = "bi-phone"
}
};
return View(availableTools);
return View(individualConverters);
}
public IActionResult About()

View File

@ -8,7 +8,20 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="HeyRed.ImageSharp.Heif" Version="2.1.3" />
<PackageReference Include="LibHeif.Native.win-x64" Version="1.15.1" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Settings.Configuration" Version="8.0.4" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.OpenSearch" Version="1.2.0" />
<PackageReference Include="Serilog.Sinks.Async" Version="2.1.0" />
<PackageReference Include="Serilog.Enrichers.Environment" Version="3.0.1" />
<PackageReference Include="Serilog.Enrichers.Process" Version="3.0.0" />
<PackageReference Include="Serilog.Enrichers.Thread" Version="4.0.0" />
</ItemGroup>
</Project>

View File

@ -4,9 +4,162 @@ using Microsoft.AspNetCore.Localization.Routing;
using Microsoft.Extensions.Options;
using Convert_It_Online.Services;
using Convert_It_Online.Middleware;
using Serilog;
using Serilog.Events;
using Serilog.Sinks.OpenSearch;
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats;
using HeyRed.ImageSharp.Heif.Formats.Heif;
using HeyRed.ImageSharp.Heif.Formats.Avif;
// Configurar suporte HEIF/AVIF para SixLabors.ImageSharp
Configuration.Default.Configure(new AvifConfigurationModule());
Configuration.Default.Configure(new HeifConfigurationModule());
var isDevelopment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
var hostname = Environment.MachineName;
Serilog.Debugging.SelfLog.Enable(msg =>
{
Console.WriteLine($"[SERILOG SELF] {DateTime.Now:HH:mm:ss} {msg}");
System.Diagnostics.Debug.WriteLine($"[SERILOG SELF] {msg}");
});
var builder = WebApplication.CreateBuilder(args);
var loggerConfig = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.Enrich.WithEnvironmentName()
.Enrich.WithProcessId()
.Enrich.WithThreadId()
.Enrich.WithProperty("ApplicationName", builder.Configuration["ApplicationName"] ?? "Convert-It")
.Enrich.WithProperty("Environment", builder.Environment.EnvironmentName)
.Enrich.WithProperty("Hostname", hostname);
if (isDevelopment)
{
loggerConfig
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Information)
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.WriteTo.Console(
restrictedToMinimumLevel: LogEventLevel.Debug,
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.File(
"./logs/convert-it-dev-.log",
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 2,
restrictedToMinimumLevel: LogEventLevel.Debug,
outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}");
var openSearchUrl = builder.Configuration["Serilog:OpenSearchUrl"];
if (!string.IsNullOrEmpty(openSearchUrl))
{
var indexFormat = "convert-it-dev-{0:yyyy-MM}";
try
{
loggerConfig.WriteTo.Async(a => a.OpenSearch(new OpenSearchSinkOptions(new Uri(openSearchUrl))
{
IndexFormat = indexFormat,
AutoRegisterTemplate = true,
BufferBaseFilename = "./logs/opensearch-buffer",
ModifyConnectionSettings = conn => conn
.RequestTimeout(TimeSpan.FromSeconds(8))
.PingTimeout(TimeSpan.FromSeconds(4)),
MinimumLogEventLevel = LogEventLevel.Debug,
EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog,
RegisterTemplateFailure = RegisterTemplateRecovery.IndexAnyway,
BatchPostingLimit = 10,
Period = TimeSpan.FromSeconds(2),
BufferRetainedInvalidPayloadsLimitBytes = 100 * 1024 * 1024,
BufferLogShippingInterval = TimeSpan.FromSeconds(1),
TemplateCustomSettings = new Dictionary<string, string>
{
{"number_of_shards", "1"},
{"number_of_replicas", "0"}
}
}),
bufferSize: 10000,
blockWhenFull: false);
}
catch (Exception)
{
// Falha silenciosa - logs continuam no console e arquivo
}
}
}
else
{
loggerConfig
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.Routing.EndpointMiddleware", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft.AspNetCore.StaticFiles", LogEventLevel.Warning)
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.MinimumLevel.Override("System", LogEventLevel.Warning)
.WriteTo.Console(
restrictedToMinimumLevel: LogEventLevel.Information,
outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
.WriteTo.File(
"/app/logs/convert-it-.log",
rollingInterval: RollingInterval.Day,
retainedFileCountLimit: 7,
restrictedToMinimumLevel: LogEventLevel.Warning,
outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] [{Hostname}] {Message:lj} {Properties:j}{NewLine}{Exception}");
var openSearchUrl = builder.Configuration["Serilog:OpenSearchUrl"];
if (!string.IsNullOrEmpty(openSearchUrl))
{
var environment = builder.Environment.EnvironmentName.ToLower();
var envMapping = environment switch
{
"production" => "prod",
"staging" => "release",
"development" => "dev",
_ => environment
};
var indexFormat = $"convert-it-{envMapping}-{{0:yyyy-MM}}";
try
{
loggerConfig.WriteTo.Async(a => a.OpenSearch(new OpenSearchSinkOptions(new Uri(openSearchUrl))
{
IndexFormat = indexFormat,
AutoRegisterTemplate = false,
BufferBaseFilename = "./logs/buffer",
ModifyConnectionSettings = conn => conn
.RequestTimeout(TimeSpan.FromSeconds(30))
.PingTimeout(TimeSpan.FromSeconds(10)),
MinimumLogEventLevel = LogEventLevel.Information,
EmitEventFailure = EmitEventFailureHandling.WriteToSelfLog,
RegisterTemplateFailure = RegisterTemplateRecovery.IndexAnyway,
BatchPostingLimit = 50,
Period = TimeSpan.FromSeconds(5),
}), bufferSize: 10000, blockWhenFull: false);
}
catch (Exception)
{
// Falha silenciosa em produção - logs continuam no console/arquivo
}
}
}
var logger = loggerConfig.CreateLogger();
Log.Logger = logger;
Console.WriteLine($"[STARTUP] {DateTime.Now:HH:mm:ss} - Logger configurado");
Log.Information("=== APLICAÇÃO INICIANDO ===");
Log.Information("Convert-It iniciando em {Environment} no host {Hostname}",
builder.Environment.EnvironmentName, hostname);
builder.Host.UseSerilog();
builder.Services.AddLocalization();
builder.Services.AddSingleton<IUrlTranslationService, UrlTranslationService>();
@ -48,6 +201,17 @@ app.UseRouting();
app.UseRequestLocalization(localizationOptions);
app.UseAuthorization();
// Health endpoint mapping
app.MapControllerRoute(
name: "health",
pattern: "health",
defaults: new { controller = "Health", action = "HealthCheck" });
app.MapControllerRoute(
name: "uptimeKuma",
pattern: "uptime-kuma",
defaults: new { controller = "Health", action = "UptimeKuma" });
app.MapControllerRoute(
name: "areaRoute",
pattern: "{culture:length(2,5)}/{area:exists}/{controller=Home}/{action=Index}/{id?}");
@ -61,4 +225,18 @@ app.MapControllerRoute(
pattern: "{controller=Home}/{action=Index}/{id?}",
defaults: new { culture = "pt-BR" });
app.Run();
Log.Information("=== APLICAÇÃO CONFIGURADA - INICIANDO SERVER ===");
try
{
app.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "Aplicação falhou ao iniciar");
throw;
}
finally
{
Log.CloseAndFlush();
}

View File

@ -6,7 +6,8 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:59345;http://localhost:59346"
//"applicationUrl": "http://localhost:59346;https://localhost:59345",
"applicationUrl": "http://localhost:59346"
}
}
}

View File

@ -40,22 +40,26 @@ namespace Convert_It_Online.Services
["pt-BR"] = new Dictionary<string, string>
{
["CaseConverter"] = "conversor-de-maiusculas-minusculas",
["JpgToWebp"] = "jpg-para-webp"
["JpgToWebp"] = "jpg-para-webp",
["HeicToJpg"] = "heic-para-jpg"
},
["es-MX"] = new Dictionary<string, string>
{
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
["JpgToWebp"] = "jpg-a-webp"
["JpgToWebp"] = "jpg-a-webp",
["HeicToJpg"] = "heic-a-jpg"
},
["es-CL"] = new Dictionary<string, string>
{
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
["JpgToWebp"] = "jpg-a-webp"
["JpgToWebp"] = "jpg-a-webp",
["HeicToJpg"] = "heic-a-jpg"
},
["es-PY"] = new Dictionary<string, string>
{
["CaseConverter"] = "conversor-de-mayusculas-minusculas",
["JpgToWebp"] = "jpg-a-webp"
["JpgToWebp"] = "jpg-a-webp",
["HeicToJpg"] = "heic-a-jpg"
}
};

View File

@ -1,47 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!-- Main Page Content - Chilean Spanish -->
<!-- Main Page Content - Mexican Spanish -->
<data name="PageTitle" xml:space="preserve">
<value>Convertidores Gratuitos Online</value>
<value>Convertidores Gratuitos en Línea</value>
</data>
<data name="Subtitle" xml:space="preserve">
<value>Convierte textos, imágenes y documentos gratis. Herramientas online bacanes y seguras, sin necesidad de instalar nada.</value>
<value>Convierte textos, imágenes y documentos gratis. Herramientas en línea rápidas y seguras, sin necesidad de instalar nada.</value>
</data>
<data name="ChooseConverter" xml:space="preserve">
<value>Elige tu Conversor</value>
<value>Elige tu Convertidor</value>
</data>
<data name="TextToolsTitle" xml:space="preserve">
<value>Herramientas de Texto</value>
</data>
<data name="TextToolsDescription" xml:space="preserve">
<value>Convierte, formatea y manipula textos súper fácil.</value>
<value>Convierte, formatea y manipula textos fácilmente.</value>
</data>
<data name="ImageToolsTitle" xml:space="preserve">
<value>Conversores de Imagen</value>
<value>Convertidores de Imagen</value>
</data>
<data name="ImageToolsDescription" xml:space="preserve">
<value>Optimiza y convierte imágenes a cualquier formato al tiro.</value>
<value>Optimiza y convierte imágenes a cualquier formato.</value>
</data>
<data name="AboutSiteTitle" xml:space="preserve">
<value>Sobre Convert-It Online</value>
<value>Acerca de Convert-It Online</value>
</data>
<data name="AboutSiteContent" xml:space="preserve">
<value>Convert-It Online es una plataforma gratuita que ofrece varias herramientas de conversión para que puedas hacer tu pega más fácil. Todas las conversiones son súper seguras, no guardamos tus archivos en nuestros servidores.</value>
<value>Convert-It Online es una plataforma gratuita que ofrece diversas herramientas de conversión para facilitar tu trabajo diario. Todas las conversiones se realizan de forma segura, sin almacenar tus archivos en nuestros servidores.</value>
</data>
<data name="WhyFreeTitle" xml:space="preserve">
<value>¿Por qué es gratis?</value>
</data>
<data name="WhyFreeContent" xml:space="preserve">
<value>Creemos que las herramientas útiles deberían estar al alcance de todos. Nuestro sitio se mantiene con publicidad no molesta, así puedes usar todos los conversores sin pagar ni una luca.</value>
<value>Creemos que las herramientas útiles deben ser accesibles para todos. Nuestro sitio se mantiene a través de anuncios no intrusivos, permitiendo que uses todos los convertidores sin costo alguno.</value>
</data>
<data name="SecurityTitle" xml:space="preserve">
<value>Seguridad y privacidad</value>
</data>
<data name="SecurityContent" xml:space="preserve">
<value>Tus archivos se procesan en tu navegador cuando se puede. Para conversiones que necesitan procesamiento en el servidor, los archivos se borran automáticamente después de la conversión.</value>
<value>Tus archivos se procesan localmente en tu navegador siempre que sea posible. Para conversiones que requieren procesamiento en el servidor, los archivos se eliminan automáticamente después de la conversión.</value>
</data>
<!-- Navigation Menu - Chilean Terms -->
<!-- Navigation Menu - Mexican Terms -->
<data name="HomeLink" xml:space="preserve">
<value>Inicio</value>
</data>
@ -52,7 +52,7 @@
<value>Imagen</value>
</data>
<data name="CaseConverterTitle" xml:space="preserve">
<value>Conversor de Mayúsculas/Minúsculas</value>
<value>Convertidor de Mayúsculas/Minúsculas</value>
</data>
<data name="JpgToWebpTitle" xml:space="preserve">
<value>JPG a WebP</value>
@ -60,10 +60,10 @@
<!-- Footer -->
<data name="FooterText" xml:space="preserve">
<value>© 2025 Convert-It Online. Herramientas gratis de conversión.</value>
<value>© 2025 Convert-It Online. Herramientas gratuitas de conversión.</value>
</data>
<data name="About" xml:space="preserve">
<value>Sobre nosotros</value>
<value>Acerca de</value>
</data>
<data name="Contact" xml:space="preserve">
<value>Contacto</value>
@ -72,12 +72,12 @@
<value>Términos</value>
</data>
<!-- TextTools Page - Chilean -->
<!-- TextTools Page - Mexican -->
<data name="TextToolsPageTitle" xml:space="preserve">
<value>Conversor de Texto</value>
<value>Convertidor de Texto</value>
</data>
<data name="TextAreaLabel" xml:space="preserve">
<value>Pega tu texto acá</value>
<value>Escribe tu texto aquí</value>
</data>
<data name="ToUpperButton" xml:space="preserve">
<value>MAYÚSCULAS</value>
@ -94,10 +94,10 @@
<!-- Image Converter -->
<data name="ImageConverterPageTitle" xml:space="preserve">
<value>Conversor JPG a WebP</value>
<value>Convertidor JPG a WebP</value>
</data>
<data name="ImageConverterPageDescription" xml:space="preserve">
<value>Convierte tus imágenes JPG al formato WebP al tiro y eficiente. WebP te da mejor compresión manteniendo la calidad de la imagen.</value>
<value>Convierte tus imágenes JPG al formato WebP de forma rápida y eficiente. WebP ofrece mejor compresión manteniendo la calidad de la imagen.</value>
</data>
<data name="FileInputLabel" xml:space="preserve">
<value>Selecciona un archivo JPG</value>
@ -119,4 +119,155 @@
<data name="UrlJpgToWebp" xml:space="preserve">
<value>jpg-a-webp</value>
</data>
<!-- New individual converter resources - Mexican Spanish -->
<data name="AllConvertersTitle" xml:space="preserve">
<value>Todos los Convertidores</value>
</data>
<data name="CaseConverterIndividualTitle" xml:space="preserve">
<value>Convertidor de Mayúsculas y Minúsculas</value>
</data>
<data name="CaseConverterIndividualDescription" xml:space="preserve">
<value>Convierte tu texto a mayúsculas, minúsculas o primera letra mayúscula.</value>
</data>
<data name="JpgToWebpIndividualTitle" xml:space="preserve">
<value>Convertidor JPG a WebP</value>
</data>
<data name="JpgToWebpIndividualDescription" xml:space="preserve">
<value>Convierte imágenes JPG al formato WebP moderno y eficiente.</value>
</data>
<data name="HeicToJpgIndividualTitle" xml:space="preserve">
<value>Convertidor HEIC a JPG</value>
</data>
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
</data>
<!-- HEIC converter menu item -->
<data name="HeicToJpgTitle" xml:space="preserve">
<value>HEIC a JPG</value>
</data>
<!-- HEIC Converter Page Resources -->
<data name="HeicConverterPageTitle" xml:space="preserve">
<value>Convertidor de HEIC a JPG</value>
</data>
<data name="HeicConverterPageDescription" xml:space="preserve">
<value>Convierte fácilmente tus imágenes HEIC (formato de alta eficiencia de Apple) al formato JPG, compatible con cualquier dispositivo.</value>
</data>
<data name="HeicToJpgTabTitle" xml:space="preserve">
<value>HEIC a JPG</value>
</data>
<data name="JpgToHeicTabTitle" xml:space="preserve">
<value>JPG a HEIC (Próximamente)</value>
</data>
<data name="HeicFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo HEIC</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo JPG</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="ConvertToHeicButton" xml:space="preserve">
<value>Convertir a HEIC</value>
</data>
<data name="HeicFaqWhatTitle" xml:space="preserve">
<value>¿Qué es un archivo HEIC?</value>
</data>
<data name="HeicFaqWhatContent" xml:space="preserve">
<value>HEIC (High Efficiency Image Container) es un formato de imagen moderno que ofrece alta calidad con un tamaño de archivo menor en comparación con JPG. Es el formato predeterminado para fotos en iPhones y iPads.</value>
</data>
<data name="HeicFaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir HEIC a JPG?</value>
</data>
<data name="HeicFaqHowContent" xml:space="preserve">
<value>Es simple: 1. Haz clic en el botón 'Seleccionar archivo HEIC' y elige la imagen de tu dispositivo. 2. Haz clic en 'Convertir a JPG'. 3. La imagen convertida se descargará automáticamente.</value>
</data>
<data name="HeicFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir de HEIC a JPG?</value>
</data>
<data name="HeicFaqWhyContent" xml:space="preserve">
<value>Aunque HEIC es eficiente, no es universalmente compatible. JPG es el formato de imagen más aceptado en la web, en software de edición y en diferentes sistemas operativos, garantizando que tu imagen pueda ser vista en cualquier lugar.</value>
</data>
<data name="HeicFaqSecurityTitle" xml:space="preserve">
<value>¿Es segura la conversión?</value>
</data>
<data name="HeicFaqSecurityContent" xml:space="preserve">
<value>Sí. Tu privacidad es nuestra prioridad. La conversión de HEIC a JPG se realiza directamente en tu navegador. Ningún archivo se envía a nuestros servidores, garantizando total seguridad y privacidad.</value>
</data>
<data name="HeicFaqLimitsTitle" xml:space="preserve">
<value>¿Existen límites?</value>
</data>
<data name="HeicFaqLimitsContent" xml:space="preserve">
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
</data>
<!-- Error Messages -->
<data name="SelectFileError" xml:space="preserve">
<value>Por favor, selecciona un archivo para convertir.</value>
</data>
<data name="InvalidHeicFileError" xml:space="preserve">
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
</data>
<data name="InvalidJpgFileError" xml:space="preserve">
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
</data>
<!-- JPG to WebP Converter Resources -->
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
<value>Convertidor JPG ↔ WebP Online Gratis</value>
</data>
<data name="JpgWebpConverterPageDescription" xml:space="preserve">
<value>Convierte fácilmente entre los formatos JPG y WebP. Transforma JPG a WebP para mejor compresión o WebP a JPG para mayor compatibilidad.</value>
</data>
<data name="JpgToWebpTabTitle" xml:space="preserve">
<value>JPG → WebP</value>
</data>
<data name="WebpToJpgTabTitle" xml:space="preserve">
<value>WebP → JPG</value>
</data>
<data name="WebpFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo WebP</value>
</data>
<data name="ConvertToWebpButton" xml:space="preserve">
<value>Convertir a WebP</value>
</data>
<data name="JpgWebpFaqWhatTitle" xml:space="preserve">
<value>¿Qué son JPG y WebP?</value>
</data>
<data name="JpgWebpFaqWhatContent" xml:space="preserve">
<value>JPG es un formato clásico de compresión de imagen ampliamente compatible. WebP es un formato moderno desarrollado por Google que ofrece mejor compresión manteniendo la calidad de la imagen.</value>
</data>
<data name="JpgWebpFaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir entre JPG y WebP?</value>
</data>
<data name="JpgWebpFaqHowContent" xml:space="preserve">
<value>Es simple: 1. Elige la pestaña de la conversión deseada (JPG→WebP o WebP→JPG). 2. Haz clic en 'Seleccionar archivo' y elige tu imagen. 3. Haz clic en 'Vista previa' para preview o 'Convertir' para descarga directa.</value>
</data>
<data name="JpgWebpFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir entre JPG y WebP?</value>
</data>
<data name="JpgWebpFaqWhyContent" xml:space="preserve">
<value>JPG→WebP: Reduce significativamente el tamaño del archivo manteniendo la calidad, ideal para web. WebP→JPG: Garantiza compatibilidad universal con cualquier dispositivo o software que no soporte WebP.</value>
</data>
<data name="JpgWebpFaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro convertir mis archivos aquí?</value>
</data>
<data name="JpgWebpFaqSecurityContent" xml:space="preserve">
<value>Absolutamente. Todas las conversiones se procesan de forma segura y tus archivos se eliminan automáticamente después del procesamiento. No almacenamos ninguna de tus imágenes.</value>
</data>
<data name="JpgWebpFaqLimitsTitle" xml:space="preserve">
<value>¿Hay límites de tamaño de archivo?</value>
</data>
<data name="JpgWebpFaqLimitsContent" xml:space="preserve">
<value>Para la funcionalidad de vista previa, el límite es de 10MB por archivo. Para conversiones directas, aceptamos archivos más grandes dentro de límites razonables para garantizar buen rendimiento.</value>
</data>
<!-- Button Labels -->
<data name="UseConverterButton" xml:space="preserve">
<value>Acceder al Convertidor</value>
</data>
<data name="ProcessingError" xml:space="preserve">
<value>Ocurrió un error al procesar tu solicitud. Inténtalo de nuevo más tarde.</value>
</data>
</root>

View File

@ -119,4 +119,155 @@
<data name="UrlJpgToWebp" xml:space="preserve">
<value>jpg-a-webp</value>
</data>
<!-- New individual converter resources - Mexican Spanish -->
<data name="AllConvertersTitle" xml:space="preserve">
<value>Todos los Convertidores</value>
</data>
<data name="CaseConverterIndividualTitle" xml:space="preserve">
<value>Convertidor de Mayúsculas y Minúsculas</value>
</data>
<data name="CaseConverterIndividualDescription" xml:space="preserve">
<value>Convierte tu texto a mayúsculas, minúsculas o primera letra mayúscula.</value>
</data>
<data name="JpgToWebpIndividualTitle" xml:space="preserve">
<value>Convertidor JPG a WebP</value>
</data>
<data name="JpgToWebpIndividualDescription" xml:space="preserve">
<value>Convierte imágenes JPG al formato WebP moderno y eficiente.</value>
</data>
<data name="HeicToJpgIndividualTitle" xml:space="preserve">
<value>Convertidor HEIC a JPG</value>
</data>
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
</data>
<!-- HEIC converter menu item -->
<data name="HeicToJpgTitle" xml:space="preserve">
<value>HEIC a JPG</value>
</data>
<!-- HEIC Converter Page Resources -->
<data name="HeicConverterPageTitle" xml:space="preserve">
<value>Convertidor de HEIC a JPG</value>
</data>
<data name="HeicConverterPageDescription" xml:space="preserve">
<value>Convierte fácilmente tus imágenes HEIC (formato de alta eficiencia de Apple) al formato JPG, compatible con cualquier dispositivo.</value>
</data>
<data name="HeicToJpgTabTitle" xml:space="preserve">
<value>HEIC a JPG</value>
</data>
<data name="JpgToHeicTabTitle" xml:space="preserve">
<value>JPG a HEIC (Próximamente)</value>
</data>
<data name="HeicFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo HEIC</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo JPG</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="ConvertToHeicButton" xml:space="preserve">
<value>Convertir a HEIC</value>
</data>
<data name="HeicFaqWhatTitle" xml:space="preserve">
<value>¿Qué es un archivo HEIC?</value>
</data>
<data name="HeicFaqWhatContent" xml:space="preserve">
<value>HEIC (High Efficiency Image Container) es un formato de imagen moderno que ofrece alta calidad con un tamaño de archivo menor en comparación con JPG. Es el formato predeterminado para fotos en iPhones y iPads.</value>
</data>
<data name="HeicFaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir HEIC a JPG?</value>
</data>
<data name="HeicFaqHowContent" xml:space="preserve">
<value>Es simple: 1. Haz clic en el botón 'Seleccionar archivo HEIC' y elige la imagen de tu dispositivo. 2. Haz clic en 'Convertir a JPG'. 3. La imagen convertida se descargará automáticamente.</value>
</data>
<data name="HeicFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir de HEIC a JPG?</value>
</data>
<data name="HeicFaqWhyContent" xml:space="preserve">
<value>Aunque HEIC es eficiente, no es universalmente compatible. JPG es el formato de imagen más aceptado en la web, en software de edición y en diferentes sistemas operativos, garantizando que tu imagen pueda ser vista en cualquier lugar.</value>
</data>
<data name="HeicFaqSecurityTitle" xml:space="preserve">
<value>¿Es segura la conversión?</value>
</data>
<data name="HeicFaqSecurityContent" xml:space="preserve">
<value>Sí. Tu privacidad es nuestra prioridad. La conversión de HEIC a JPG se realiza directamente en tu navegador. Ningún archivo se envía a nuestros servidores, garantizando total seguridad y privacidad.</value>
</data>
<data name="HeicFaqLimitsTitle" xml:space="preserve">
<value>¿Existen límites?</value>
</data>
<data name="HeicFaqLimitsContent" xml:space="preserve">
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
</data>
<!-- Error Messages -->
<data name="SelectFileError" xml:space="preserve">
<value>Por favor, selecciona un archivo para convertir.</value>
</data>
<data name="InvalidHeicFileError" xml:space="preserve">
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
</data>
<data name="InvalidJpgFileError" xml:space="preserve">
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
</data>
<!-- JPG to WebP Converter Resources -->
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
<value>Convertidor JPG ↔ WebP Online Gratis</value>
</data>
<data name="JpgWebpConverterPageDescription" xml:space="preserve">
<value>Convierte fácilmente entre los formatos JPG y WebP. Transforma JPG a WebP para mejor compresión o WebP a JPG para mayor compatibilidad.</value>
</data>
<data name="JpgToWebpTabTitle" xml:space="preserve">
<value>JPG → WebP</value>
</data>
<data name="WebpToJpgTabTitle" xml:space="preserve">
<value>WebP → JPG</value>
</data>
<data name="WebpFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo WebP</value>
</data>
<data name="ConvertToWebpButton" xml:space="preserve">
<value>Convertir a WebP</value>
</data>
<data name="JpgWebpFaqWhatTitle" xml:space="preserve">
<value>¿Qué son JPG y WebP?</value>
</data>
<data name="JpgWebpFaqWhatContent" xml:space="preserve">
<value>JPG es un formato clásico de compresión de imagen ampliamente compatible. WebP es un formato moderno desarrollado por Google que ofrece mejor compresión manteniendo la calidad de la imagen.</value>
</data>
<data name="JpgWebpFaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir entre JPG y WebP?</value>
</data>
<data name="JpgWebpFaqHowContent" xml:space="preserve">
<value>Es simple: 1. Elige la pestaña de la conversión deseada (JPG→WebP o WebP→JPG). 2. Haz clic en 'Seleccionar archivo' y elige tu imagen. 3. Haz clic en 'Vista previa' para preview o 'Convertir' para descarga directa.</value>
</data>
<data name="JpgWebpFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir entre JPG y WebP?</value>
</data>
<data name="JpgWebpFaqWhyContent" xml:space="preserve">
<value>JPG→WebP: Reduce significativamente el tamaño del archivo manteniendo la calidad, ideal para web. WebP→JPG: Garantiza compatibilidad universal con cualquier dispositivo o software que no soporte WebP.</value>
</data>
<data name="JpgWebpFaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro convertir mis archivos aquí?</value>
</data>
<data name="JpgWebpFaqSecurityContent" xml:space="preserve">
<value>Absolutamente. Todas las conversiones se procesan de forma segura y tus archivos se eliminan automáticamente después del procesamiento. No almacenamos ninguna de tus imágenes.</value>
</data>
<data name="JpgWebpFaqLimitsTitle" xml:space="preserve">
<value>¿Hay límites de tamaño de archivo?</value>
</data>
<data name="JpgWebpFaqLimitsContent" xml:space="preserve">
<value>Para la funcionalidad de vista previa, el límite es de 10MB por archivo. Para conversiones directas, aceptamos archivos más grandes dentro de límites razonables para garantizar buen rendimiento.</value>
</data>
<!-- Button Labels -->
<data name="UseConverterButton" xml:space="preserve">
<value>Acceder al Convertidor</value>
</data>
<data name="ProcessingError" xml:space="preserve">
<value>Ocurrió un error al procesar tu solicitud. Inténtalo de nuevo más tarde.</value>
</data>
</root>

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!-- Main Page Content - Paraguayan Spanish with Guaraní influences -->
<!-- Main Page Content - Mexican Spanish -->
<data name="PageTitle" xml:space="preserve">
<value>Convertidores Gratuitos en Línea</value>
</data>
<data name="Subtitle" xml:space="preserve">
<value>Convierte textos, imágenes y documentos gratis. Herramientas en línea rápidas y seguras, sin necesidad de instalar nada che.</value>
<value>Convierte textos, imágenes y documentos gratis. Herramientas en línea rápidas y seguras, sin necesidad de instalar nada.</value>
</data>
<data name="ChooseConverter" xml:space="preserve">
<value>Elige tu Convertidor</value>
@ -14,34 +14,34 @@
<value>Herramientas de Texto</value>
</data>
<data name="TextToolsDescription" xml:space="preserve">
<value>Convierte, formatea y manipula textos facilito.</value>
<value>Convierte, formatea y manipula textos fácilmente.</value>
</data>
<data name="ImageToolsTitle" xml:space="preserve">
<value>Convertidores de Imagen</value>
</data>
<data name="ImageToolsDescription" xml:space="preserve">
<value>Optimiza y convierte imágenes a cualquier formato al toque.</value>
<value>Optimiza y convierte imágenes a cualquier formato.</value>
</data>
<data name="AboutSiteTitle" xml:space="preserve">
<value>Acerca de Convert-It Online</value>
</data>
<data name="AboutSiteContent" xml:space="preserve">
<value>Convert-It Online es una plataforma gratuita que ofrece diversas herramientas de conversión para facilitar tu trabajo diario che. Todas las conversiones se realizan de forma segura, sin guardar tus archivos en nuestros servidores.</value>
<value>Convert-It Online es una plataforma gratuita que ofrece diversas herramientas de conversión para facilitar tu trabajo diario. Todas las conversiones se realizan de forma segura, sin almacenar tus archivos en nuestros servidores.</value>
</data>
<data name="WhyFreeTitle" xml:space="preserve">
<value>¿Por qué es gratis?</value>
</data>
<data name="WhyFreeContent" xml:space="preserve">
<value>Creemos que las herramientas útiles deben estar al alcance de todos. Nuestro sitio se mantiene a través de publicidad no molesta, así podés usar todos los convertidores sin pagar nada che.</value>
<value>Creemos que las herramientas útiles deben ser accesibles para todos. Nuestro sitio se mantiene a través de anuncios no intrusivos, permitiendo que uses todos los convertidores sin costo alguno.</value>
</data>
<data name="SecurityTitle" xml:space="preserve">
<value>Seguridad y privacidad</value>
</data>
<data name="SecurityContent" xml:space="preserve">
<value>Tus archivos se procesan localmente en tu navegador cuando es posible. Para conversiones que necesitan procesamiento en el servidor, los archivos se borran automáticamente después de la conversión.</value>
<value>Tus archivos se procesan localmente en tu navegador siempre que sea posible. Para conversiones que requieren procesamiento en el servidor, los archivos se eliminan automáticamente después de la conversión.</value>
</data>
<!-- Navigation Menu - Paraguayan Terms -->
<!-- Navigation Menu - Mexican Terms -->
<data name="HomeLink" xml:space="preserve">
<value>Inicio</value>
</data>
@ -72,12 +72,12 @@
<value>Términos</value>
</data>
<!-- TextTools Page - Paraguayan -->
<!-- TextTools Page - Mexican -->
<data name="TextToolsPageTitle" xml:space="preserve">
<value>Convertidor de Texto</value>
</data>
<data name="TextAreaLabel" xml:space="preserve">
<value>Escribí tu texto acá</value>
<value>Escribe tu texto aquí</value>
</data>
<data name="ToUpperButton" xml:space="preserve">
<value>MAYÚSCULAS</value>
@ -97,10 +97,10 @@
<value>Convertidor JPG a WebP</value>
</data>
<data name="ImageConverterPageDescription" xml:space="preserve">
<value>Convertí tus imágenes JPG al formato WebP de forma rápida y eficiente che. WebP ofrece mejor compresión manteniendo la calidad de la imagen.</value>
<value>Convierte tus imágenes JPG al formato WebP de forma rápida y eficiente. WebP ofrece mejor compresión manteniendo la calidad de la imagen.</value>
</data>
<data name="FileInputLabel" xml:space="preserve">
<value>Seleccioná un archivo JPG</value>
<value>Selecciona un archivo JPG</value>
</data>
<data name="ConvertButton" xml:space="preserve">
<value>Convertir a WebP</value>
@ -119,4 +119,155 @@
<data name="UrlJpgToWebp" xml:space="preserve">
<value>jpg-a-webp</value>
</data>
<!-- New individual converter resources - Mexican Spanish -->
<data name="AllConvertersTitle" xml:space="preserve">
<value>Todos los Convertidores</value>
</data>
<data name="CaseConverterIndividualTitle" xml:space="preserve">
<value>Convertidor de Mayúsculas y Minúsculas</value>
</data>
<data name="CaseConverterIndividualDescription" xml:space="preserve">
<value>Convierte tu texto a mayúsculas, minúsculas o primera letra mayúscula.</value>
</data>
<data name="JpgToWebpIndividualTitle" xml:space="preserve">
<value>Convertidor JPG a WebP</value>
</data>
<data name="JpgToWebpIndividualDescription" xml:space="preserve">
<value>Convierte imágenes JPG al formato WebP moderno y eficiente.</value>
</data>
<data name="HeicToJpgIndividualTitle" xml:space="preserve">
<value>Convertidor HEIC a JPG</value>
</data>
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
<value>Convierte fotos HEIC del iPhone al formato JPG universalmente compatible.</value>
</data>
<!-- HEIC converter menu item -->
<data name="HeicToJpgTitle" xml:space="preserve">
<value>HEIC a JPG</value>
</data>
<!-- HEIC Converter Page Resources -->
<data name="HeicConverterPageTitle" xml:space="preserve">
<value>Convertidor de HEIC a JPG</value>
</data>
<data name="HeicConverterPageDescription" xml:space="preserve">
<value>Convierte fácilmente tus imágenes HEIC (formato de alta eficiencia de Apple) al formato JPG, compatible con cualquier dispositivo.</value>
</data>
<data name="HeicToJpgTabTitle" xml:space="preserve">
<value>HEIC a JPG</value>
</data>
<data name="JpgToHeicTabTitle" xml:space="preserve">
<value>JPG a HEIC (Próximamente)</value>
</data>
<data name="HeicFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo HEIC</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo JPG</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Convertir a JPG</value>
</data>
<data name="ConvertToHeicButton" xml:space="preserve">
<value>Convertir a HEIC</value>
</data>
<data name="HeicFaqWhatTitle" xml:space="preserve">
<value>¿Qué es un archivo HEIC?</value>
</data>
<data name="HeicFaqWhatContent" xml:space="preserve">
<value>HEIC (High Efficiency Image Container) es un formato de imagen moderno que ofrece alta calidad con un tamaño de archivo menor en comparación con JPG. Es el formato predeterminado para fotos en iPhones y iPads.</value>
</data>
<data name="HeicFaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir HEIC a JPG?</value>
</data>
<data name="HeicFaqHowContent" xml:space="preserve">
<value>Es simple: 1. Haz clic en el botón 'Seleccionar archivo HEIC' y elige la imagen de tu dispositivo. 2. Haz clic en 'Convertir a JPG'. 3. La imagen convertida se descargará automáticamente.</value>
</data>
<data name="HeicFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir de HEIC a JPG?</value>
</data>
<data name="HeicFaqWhyContent" xml:space="preserve">
<value>Aunque HEIC es eficiente, no es universalmente compatible. JPG es el formato de imagen más aceptado en la web, en software de edición y en diferentes sistemas operativos, garantizando que tu imagen pueda ser vista en cualquier lugar.</value>
</data>
<data name="HeicFaqSecurityTitle" xml:space="preserve">
<value>¿Es segura la conversión?</value>
</data>
<data name="HeicFaqSecurityContent" xml:space="preserve">
<value>Sí. Tu privacidad es nuestra prioridad. La conversión de HEIC a JPG se realiza directamente en tu navegador. Ningún archivo se envía a nuestros servidores, garantizando total seguridad y privacidad.</value>
</data>
<data name="HeicFaqLimitsTitle" xml:space="preserve">
<value>¿Existen límites?</value>
</data>
<data name="HeicFaqLimitsContent" xml:space="preserve">
<value>No hay límites en la cantidad de conversiones. Para garantizar un buen rendimiento, recomendamos archivos de hasta 10MB. El procesamiento es más rápido en computadoras modernas.</value>
</data>
<!-- Error Messages -->
<data name="SelectFileError" xml:space="preserve">
<value>Por favor, selecciona un archivo para convertir.</value>
</data>
<data name="InvalidHeicFileError" xml:space="preserve">
<value>Archivo HEIC inválido o formato no compatible. Revisa el archivo o intenta con otro. La biblioteca nativa 'libheif' podría faltar en el sistema.</value>
</data>
<data name="InvalidJpgFileError" xml:space="preserve">
<value>Archivo JPG inválido o formato no compatible. Verifica que el archivo sea una imagen JPG válida.</value>
</data>
<!-- JPG to WebP Converter Resources -->
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
<value>Convertidor JPG ↔ WebP Online Gratis</value>
</data>
<data name="JpgWebpConverterPageDescription" xml:space="preserve">
<value>Convierte fácilmente entre los formatos JPG y WebP. Transforma JPG a WebP para mejor compresión o WebP a JPG para mayor compatibilidad.</value>
</data>
<data name="JpgToWebpTabTitle" xml:space="preserve">
<value>JPG → WebP</value>
</data>
<data name="WebpToJpgTabTitle" xml:space="preserve">
<value>WebP → JPG</value>
</data>
<data name="WebpFileInputLabel" xml:space="preserve">
<value>Selecciona un archivo WebP</value>
</data>
<data name="ConvertToWebpButton" xml:space="preserve">
<value>Convertir a WebP</value>
</data>
<data name="JpgWebpFaqWhatTitle" xml:space="preserve">
<value>¿Qué son JPG y WebP?</value>
</data>
<data name="JpgWebpFaqWhatContent" xml:space="preserve">
<value>JPG es un formato clásico de compresión de imagen ampliamente compatible. WebP es un formato moderno desarrollado por Google que ofrece mejor compresión manteniendo la calidad de la imagen.</value>
</data>
<data name="JpgWebpFaqHowTitle" xml:space="preserve">
<value>¿Cómo convertir entre JPG y WebP?</value>
</data>
<data name="JpgWebpFaqHowContent" xml:space="preserve">
<value>Es simple: 1. Elige la pestaña de la conversión deseada (JPG→WebP o WebP→JPG). 2. Haz clic en 'Seleccionar archivo' y elige tu imagen. 3. Haz clic en 'Vista previa' para preview o 'Convertir' para descarga directa.</value>
</data>
<data name="JpgWebpFaqWhyTitle" xml:space="preserve">
<value>¿Por qué convertir entre JPG y WebP?</value>
</data>
<data name="JpgWebpFaqWhyContent" xml:space="preserve">
<value>JPG→WebP: Reduce significativamente el tamaño del archivo manteniendo la calidad, ideal para web. WebP→JPG: Garantiza compatibilidad universal con cualquier dispositivo o software que no soporte WebP.</value>
</data>
<data name="JpgWebpFaqSecurityTitle" xml:space="preserve">
<value>¿Es seguro convertir mis archivos aquí?</value>
</data>
<data name="JpgWebpFaqSecurityContent" xml:space="preserve">
<value>Absolutamente. Todas las conversiones se procesan de forma segura y tus archivos se eliminan automáticamente después del procesamiento. No almacenamos ninguna de tus imágenes.</value>
</data>
<data name="JpgWebpFaqLimitsTitle" xml:space="preserve">
<value>¿Hay límites de tamaño de archivo?</value>
</data>
<data name="JpgWebpFaqLimitsContent" xml:space="preserve">
<value>Para la funcionalidad de vista previa, el límite es de 10MB por archivo. Para conversiones directas, aceptamos archivos más grandes dentro de límites razonables para garantizar buen rendimiento.</value>
</data>
<!-- Button Labels -->
<data name="UseConverterButton" xml:space="preserve">
<value>Acceder al Convertidor</value>
</data>
<data name="ProcessingError" xml:space="preserve">
<value>Ocurrió un error al procesar tu solicitud. Inténtalo de nuevo más tarde.</value>
</data>
</root>

View File

@ -231,4 +231,160 @@
<data name="Faq2Answer" xml:space="preserve">
<value>Para garantir a melhor experiência, recomendamos arquivos de até 10MB. Arquivos maiores podem ser processados, mas o tempo de conversão pode ser maior.</value>
</data>
<!-- New individual converter resources -->
<data name="AllConvertersTitle" xml:space="preserve">
<value>Todos os Conversores</value>
</data>
<data name="CaseConverterIndividualTitle" xml:space="preserve">
<value>Conversor de Maiúsculas e Minúsculas</value>
</data>
<data name="CaseConverterIndividualDescription" xml:space="preserve">
<value>Converta seu texto para maiúsculas, minúsculas ou primeira letra maiúscula.</value>
</data>
<data name="JpgToWebpIndividualTitle" xml:space="preserve">
<value>Conversor JPG para WebP</value>
</data>
<data name="JpgToWebpIndividualDescription" xml:space="preserve">
<value>Converta imagens JPG para o formato WebP moderno e eficiente.</value>
</data>
<data name="HeicToJpgIndividualTitle" xml:space="preserve">
<value>Conversor HEIC para JPG</value>
</data>
<data name="HeicToJpgIndividualDescription" xml:space="preserve">
<value>Converta fotos HEIC do iPhone para o formato JPG universalmente compatível.</value>
</data>
<!-- HEIC converter menu item -->
<data name="HeicToJpgTitle" xml:space="preserve">
<value>HEIC para JPG</value>
</data>
<!-- HEIC Converter Page Resources -->
<data name="HeicConverterPageTitle" xml:space="preserve">
<value>Conversor de HEIC para JPG</value>
</data>
<data name="HeicConverterPageDescription" xml:space="preserve">
<value>Converta facilmente suas imagens HEIC (formato de alta eficiência da Apple) para o formato JPG, compatível com qualquer dispositivo.</value>
</data>
<data name="HeicToJpgTabTitle" xml:space="preserve">
<value>HEIC para JPG</value>
</data>
<data name="JpgToHeicTabTitle" xml:space="preserve">
<value>JPG para HEIC</value>
</data>
<data name="HeicFileInputLabel" xml:space="preserve">
<value>Selecione um arquivo HEIC</value>
</data>
<data name="JpgFileInputLabel" xml:space="preserve">
<value>Selecione um arquivo JPG</value>
</data>
<data name="ConvertToJpgButton" xml:space="preserve">
<value>Converter para JPG</value>
</data>
<data name="ConvertToHeicButton" xml:space="preserve">
<value>Converter para HEIC</value>
</data>
<data name="HeicFaqWhatTitle" xml:space="preserve">
<value>O que é um arquivo HEIC?</value>
</data>
<data name="HeicFaqWhatContent" xml:space="preserve">
<value>HEIC (High Efficiency Image Container) é um formato de imagem moderno que oferece alta qualidade com um tamanho de arquivo menor em comparação com o JPG. É o formato padrão para fotos em iPhones e iPads.</value>
</data>
<data name="HeicFaqHowTitle" xml:space="preserve">
<value>Como converter HEIC para JPG?</value>
</data>
<data name="HeicFaqHowContent" xml:space="preserve">
<value>É simples: 1. Clique no botão 'Selecionar arquivo HEIC' e escolha a imagem do seu dispositivo. 2. Clique em 'Converter para JPG'. 3. A imagem convertida será baixada automaticamente.</value>
</data>
<data name="HeicFaqWhyTitle" xml:space="preserve">
<value>Por que converter de HEIC para JPG?</value>
</data>
<data name="HeicFaqWhyContent" xml:space="preserve">
<value>Embora o HEIC seja eficiente, ele não é universalmente compatível. O JPG é o formato de imagem mais aceito na web, em softwares de edição e em diferentes sistemas operacionais, garantindo que sua imagem possa ser visualizada em qualquer lugar.</value>
</data>
<data name="HeicFaqSecurityTitle" xml:space="preserve">
<value>A conversão é segura?</value>
</data>
<data name="HeicFaqSecurityContent" xml:space="preserve">
<value>Sim. Sua privacidade é nossa prioridade. A conversão de HEIC para JPG é feita diretamente no seu navegador. Nenhum arquivo é enviado para nossos servidores, garantindo total segurança e privacidade.</value>
</data>
<data name="HeicFaqLimitsTitle" xml:space="preserve">
<value>Existem limites?</value>
</data>
<data name="HeicFaqLimitsContent" xml:space="preserve">
<value>Não há limites para a quantidade de conversões. Para garantir um bom desempenho, recomendamos arquivos de até 10MB. O processamento é mais rápido em computadores modernos.</value>
</data>
<!-- JPG to WebP Converter Resources -->
<data name="JpgWebpConverterPageTitle" xml:space="preserve">
<value>Conversor JPG ↔ WebP Online Grátis</value>
</data>
<data name="JpgWebpConverterPageDescription" xml:space="preserve">
<value>Converta facilmente entre os formatos JPG e WebP. Transforme JPG em WebP para melhor compressão ou WebP em JPG para maior compatibilidade.</value>
</data>
<data name="JpgToWebpTabTitle" xml:space="preserve">
<value>JPG → WebP</value>
</data>
<data name="WebpToJpgTabTitle" xml:space="preserve">
<value>WebP → JPG</value>
</data>
<data name="WebpFileInputLabel" xml:space="preserve">
<value>Selecione um arquivo WebP</value>
</data>
<data name="ConvertToWebpButton" xml:space="preserve">
<value>Converter para WebP</value>
</data>
<data name="JpgWebpFaqWhatTitle" xml:space="preserve">
<value>O que são JPG e WebP?</value>
</data>
<data name="JpgWebpFaqWhatContent" xml:space="preserve">
<value>JPG é um formato clássico de compressão de imagem amplamente compatível. WebP é um formato moderno desenvolvido pelo Google que oferece melhor compressão mantendo a qualidade da imagem.</value>
</data>
<data name="JpgWebpFaqHowTitle" xml:space="preserve">
<value>Como converter entre JPG e WebP?</value>
</data>
<data name="JpgWebpFaqHowContent" xml:space="preserve">
<value>É simples: 1. Escolha a aba da conversão desejada (JPG→WebP ou WebP→JPG). 2. Clique em 'Selecionar arquivo' e escolha sua imagem. 3. Clique em 'Visualizar' para preview ou 'Converter' para download direto.</value>
</data>
<data name="JpgWebpFaqWhyTitle" xml:space="preserve">
<value>Por que converter entre JPG e WebP?</value>
</data>
<data name="JpgWebpFaqWhyContent" xml:space="preserve">
<value>JPG→WebP: Reduz significativamente o tamanho do arquivo mantendo a qualidade, ideal para web. WebP→JPG: Garante compatibilidade universal com qualquer dispositivo ou software que não suporte WebP.</value>
</data>
<data name="JpgWebpFaqSecurityTitle" xml:space="preserve">
<value>É seguro converter meus arquivos aqui?</value>
</data>
<data name="JpgWebpFaqSecurityContent" xml:space="preserve">
<value>Absolutamente. Todas as conversões são processadas de forma segura e seus arquivos são automaticamente excluídos após o processamento. Não armazenamos nenhuma de suas imagens.</value>
</data>
<data name="JpgWebpFaqLimitsTitle" xml:space="preserve">
<value>Há limites de tamanho de arquivo?</value>
</data>
<data name="JpgWebpFaqLimitsContent" xml:space="preserve">
<value>Para a funcionalidade de preview, o limite é de 10MB por arquivo. Para conversões diretas, aceitamos arquivos maiores dentro de limites razoáveis para garantir boa performance.</value>
</data>
<!-- Button Labels -->
<data name="UseConverterButton" xml:space="preserve">
<value>Acessar Conversor</value>
</data>
<!-- Error Messages -->
<data name="SelectFileError" xml:space="preserve">
<value>Por favor, selecione um arquivo para converter.</value>
</data>
<data name="InvalidHeicFileError" xml:space="preserve">
<value>Arquivo HEIC inválido ou formato não suportado. Verifique o arquivo ou tente outro. A biblioteca nativa 'libheif' pode estar faltando no sistema.</value>
</data>
<data name="InvalidJpgFileError" xml:space="preserve">
<value>Arquivo JPG inválido ou formato não suportado. Verifique se o arquivo é uma imagem JPG válida.</value>
</data>
<data name="JpgToHeicNotAvailableError" xml:space="preserve">
<value>A conversão de JPG para HEIC ainda não está disponível. Esta funcionalidade será implementada em breve.</value>
</data>
<data name="ProcessingError" xml:space="preserve">
<value>Ocorreu um erro ao processar sua solicitação. Tente novamente mais tarde.</value>
</data>
</root>

View File

@ -10,33 +10,39 @@
<p class="lead text-muted">@ViewBag.Subtitle</p>
</div>
<div class="row mb-5">
<!-- Lista Individual de Conversores -->
<div class="row mt-5">
<div class="col-12">
<h3 class="h4 mb-3 text-center">@ViewBag.ChooseConverter</h3>
<div class="converter-menu-container">
<div class="converter-menu">
@foreach (var tool in Model)
<h3 class="h4 mb-4 text-center">@ViewBag.AllConvertersTitle</h3>
<div class="row">
@foreach (var converter in Model)
{
<a href="@Html.LocalizedUrl(tool.Area, tool.Controller, tool.Action)"
class="converter-item">
<div class="converter-icon">
<i class="@tool.IconClass"></i>
<div class="col-lg-4 col-md-6 mb-4">
<div class="card h-100 shadow-sm border-0 converter-individual-card">
<div class="card-body d-flex flex-column">
<div class="text-center mb-3">
<div class="converter-icon-large bg-primary bg-gradient rounded-circle d-inline-flex align-items-center justify-content-center">
<i class="@converter.IconClass text-white fs-2"></i>
</div>
<div class="converter-content">
<h4>@(tool.TitleKey == "TextToolsTitle" ? ViewBag.TextToolsTitle : ViewBag.ImageToolsTitle)</h4>
<p>@(tool.DescriptionKey == "TextToolsDescription" ? ViewBag.TextToolsDescription : ViewBag.ImageToolsDescription)</p>
</div>
<div class="converter-arrow">
<i class="bi bi-chevron-right"></i>
</div>
<h5 class="card-title text-center">@converter.Title</h5>
<p class="card-text text-muted text-center flex-grow-1">@converter.Description</p>
<div class="text-center mt-auto">
<a href="@Html.LocalizedUrl(converter.Area, converter.Controller, converter.Action)"
class="btn btn-primary btn-sm">
<i class="bi bi-arrow-right-circle me-1"></i>
@ViewBag.UseConverterButton
</a>
}
</div>
</div>
</div>
</div>
}
</div>
</div>
</div>
<div class="row">
<div class="row mt-5">
<div class="col-lg-8 mx-auto">
<div class="accordion" id="aboutAccordion">
<div class="accordion-item">

View File

@ -29,10 +29,10 @@
</button>
<div class="collapse navbar-collapse" id="navbarColor01">
<ul class="navbar-nav me-auto">
<li class="nav-item">
<a class="nav-link" asp-area="" asp-controller="Home" asp-action="Index" asp-route-culture="@requestCulture?.RequestCulture.UICulture.Name">@ViewBag.HomeLink</a>
<li class="nav-item mx-2">
<a class="nav-link @(ViewContext.RouteData.Values["controller"] as string == "Home" && ViewContext.RouteData.Values["action"] as string == "Index" ? "active" : "")" asp-area="" asp-controller="Home" asp-action="Index" asp-route-culture="@requestCulture?.RequestCulture.UICulture.Name">@ViewBag.HomeLink</a>
</li>
<li class="nav-item dropdown">
<li class="nav-item dropdown mx-2">
<a class="nav-link dropdown-toggle" href="#" id="textToolsDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-fonts me-1"></i>@ViewBag.TextMenuTitle
</a>
@ -42,7 +42,7 @@
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<li class="nav-item dropdown mx-2">
<a class="nav-link dropdown-toggle" href="#" id="imageToolsDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-image-alt me-1"></i>@ViewBag.ImageMenuTitle
</a>
@ -50,6 +50,9 @@
<li><a class="dropdown-item" href="@Html.LocalizedUrl("ImageConverters", "JpgToWebp")">
<i class="bi bi-arrow-left-right me-2"></i>@ViewBag.JpgToWebpTitle
</a></li>
<li><a class="dropdown-item" href="@Html.LocalizedUrl("ImageConverters", "HeicToJpg")">
<i class="bi bi-phone me-2"></i>@ViewBag.HeicToJpgTitle
</a></li>
</ul>
</li>
</ul>

13
appsettings.json Normal file
View File

@ -0,0 +1,13 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ApplicationName": "Convert-It",
"AllowedHosts": "*",
"Serilog": {
"OpenSearchUrl": ""
}
}