Cleanup-conversion-translations (#5906)

Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
This commit is contained in:
ConnorYoh
2026-03-12 20:23:13 +00:00
committed by GitHub
parent b68b406a2a
commit 0545c3f997
14 changed files with 68 additions and 57 deletions

View File

@@ -341,7 +341,8 @@ public class EmlProcessingUtils {
}
private String getFallbackStyles() {
return """
return
"""
/* Minimal fallback - main CSS resource failed to load */
body {
font-family: var(--font-family, Helvetica, sans-serif);

View File

@@ -178,7 +178,8 @@ public class ReactRoutingController {
String escapedBaseUrlJs = JavaScriptUtils.javaScriptEscape(baseUrl);
String serverUrl = "(window.location.origin + '" + escapedBaseUrlJs + "')";
return """
return
"""
<!doctype html>
<html>
<head>
@@ -237,7 +238,8 @@ public class ReactRoutingController {
String escapedBaseUrlJs = JavaScriptUtils.javaScriptEscape(baseUrl);
String serverUrl = "(window.location.origin + '" + escapedBaseUrlJs + "')";
return """
return
"""
<!doctype html>
<html>
<head>

View File

@@ -581,9 +581,10 @@ public class PdfJsonFallbackFontService {
Character.UnicodeScript script = Character.UnicodeScript.of(codePoint);
return switch (script) {
// HAN script is used by both Simplified and Traditional Chinese
// Default to Simplified (mainland China, 1.4B speakers) as it's more common
// Traditional Chinese PDFs are detected via font name aliases (MingLiU, PMingLiU, etc.)
// HAN script is used by both Simplified and Traditional Chinese
// Default to Simplified (mainland China, 1.4B speakers) as it's more common
// Traditional Chinese PDFs are detected via font name aliases (MingLiU, PMingLiU,
// etc.)
case HAN -> FALLBACK_FONT_CJK_ID;
case HIRAGANA, KATAKANA -> FALLBACK_FONT_JP_ID;
case HANGUL -> FALLBACK_FONT_KR_ID;

View File

@@ -21,8 +21,7 @@ class ApiEndpointTest {
return postNodeWithParams(description, true, names);
}
private JsonNode postNodeWithParams(
String description, boolean required, String... names) {
private JsonNode postNodeWithParams(String description, boolean required, String... names) {
ObjectNode post = mapper.createObjectNode();
post.put("description", description);
ArrayNode params = mapper.createArrayNode();

View File

@@ -103,7 +103,9 @@ class LanguageServiceBasicTest {
// Verify filtering by restrictions
assertTrue(supportedLanguages.contains("en_US"), "Allowed language should be included");
assertTrue(supportedLanguages.contains("fr_FR"), "Allowed language should be included");
assertFalse(supportedLanguages.contains("en_GB"), "en_GB should NOT be included when not in whitelist");
assertFalse(
supportedLanguages.contains("en_GB"),
"en_GB should NOT be included when not in whitelist");
assertFalse(supportedLanguages.contains("de_DE"), "Restricted language should be excluded");
}

View File

@@ -84,11 +84,13 @@ class LanguageServiceTest {
// Verify
assertEquals(
allowedLanguages,
supportedLanguages,
"Should return only whitelisted languages");
assertFalse(supportedLanguages.contains("en_GB"), "en_GB should NOT be included when not in whitelist");
assertFalse(supportedLanguages.contains("de_DE"), "de_DE should NOT be included when not in whitelist");
allowedLanguages, supportedLanguages, "Should return only whitelisted languages");
assertFalse(
supportedLanguages.contains("en_GB"),
"en_GB should NOT be included when not in whitelist");
assertFalse(
supportedLanguages.contains("de_DE"),
"de_DE should NOT be included when not in whitelist");
}
@Test

View File

@@ -161,7 +161,7 @@ public class EmailService {
String subject = "Welcome to Stirling PDF";
String body =
"""
"""
<html><body style="margin: 0; padding: 0;">
<div style="font-family: Arial, sans-serif; background-color: #f8f9fa; padding: 20px;">
<div style="max-width: 600px; margin: auto; background-color: #ffffff; border-radius: 8px; overflow: hidden; border: 1px solid #e0e0e0;">
@@ -220,7 +220,7 @@ public class EmailService {
String subject = "You've been invited to Stirling PDF";
String body =
"""
"""
<html><body style="margin: 0; padding: 0;">
<div style="font-family: Arial, sans-serif; background-color: #f8f9fa; padding: 20px;">
<div style="max-width: 600px; margin: auto; background-color: #ffffff; border-radius: 8px; overflow: hidden; border: 1px solid #e0e0e0;">
@@ -269,7 +269,8 @@ public class EmailService {
String passwordSection =
newPassword == null
? ""
: """
:
"""
<div style=\"background-color: #f8f9fa; border-left: 4px solid #007bff; padding: 15px; margin: 20px 0; border-radius: 4px;\">
<p style=\"margin: 0;\"><strong>Temporary Password:</strong> %s</p>
</div>
@@ -277,7 +278,7 @@ public class EmailService {
.formatted(newPassword);
String body =
"""
"""
<html><body style=\"margin: 0; padding: 0;\">
<div style=\"font-family: Arial, sans-serif; background-color: #f8f9fa; padding: 20px;\">
<div style=\"max-width: 600px; margin: auto; background-color: #ffffff; border-radius: 8px; overflow: hidden; border: 1px solid #e0e0e0;\">

View File

@@ -78,7 +78,7 @@ springBoot {
allprojects {
group = 'stirling.software'
version = '2.7.0'
version = '2.7.1'
configurations.configureEach {
exclude group: "org.springframework.boot", module: "spring-boot-starter-tomcat"

View File

@@ -2759,6 +2759,15 @@ webOptions = "Web to PDF Options"
wordDoc = "Word Document"
wordDocExt = "Word Document (.docx)"
zoomLevel = "Zoom Level"
cbrToPdf = "CBR → PDF"
cbzToPdf = "CBZ → PDF"
ebookToPdf = "eBook → PDF"
emlToPdf = "Email → PDF"
fileToPdf = "Office/Document → PDF"
pdfToCbr = "PDF → CBR"
pdfToCbz = "PDF → CBZ"
pdfToEpub = "PDF → EPUB"
svgToPdf = "SVG → PDF"
[convert.ebookOptions]
ebookOptions = "eBook to PDF Options"
@@ -5822,30 +5831,6 @@ showTools = "View unavailable tools ▾"
title = "Your Stirling-PDF server is unreachable"
toolNotAvailableLocally = "Your Stirling-PDF server is offline and \"{{endpoint}}\" is not available on the local backend."
[selfHosted.offline.conversionTypes]
cbr-to-pdf = "CBR → PDF"
cbz-to-pdf = "CBZ → PDF"
eml-to-pdf = "Email → PDF"
ebook-to-pdf = "eBook → PDF"
file-to-pdf = "Office/Document → PDF"
html-to-pdf = "HTML → PDF"
img-to-pdf = "Image → PDF"
markdown-to-pdf = "Markdown → PDF"
pdf-to-cbr = "PDF → CBR"
pdf-to-cbz = "PDF → CBZ"
pdf-to-csv = "PDF → CSV"
pdf-to-epub = "PDF → EPUB"
pdf-to-html = "PDF → HTML"
pdf-to-img = "PDF → Image"
pdf-to-markdown = "PDF → Markdown"
pdf-to-pdfa = "PDF → PDF/A"
pdf-to-presentation = "PDF → Presentation"
pdf-to-text = "PDF → Text"
pdf-to-word = "PDF → Word"
pdf-to-xml = "PDF → XML"
pdf-to-xlsx = "PDF → XLSX"
svg-to-pdf = "SVG → PDF"
[session]
expired = "Your session has expired. Please refresh the page and try again."
refreshPage = "Refresh Page"

View File

@@ -1,7 +1,7 @@
{
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "Stirling-PDF",
"version": "2.6.0",
"version": "2.7.1",
"identifier": "stirling.pdf.dev",
"build": {
"frontendDist": "../dist",

View File

@@ -71,6 +71,31 @@ export const ENDPOINT_NAMES = {
'text-editor-pdf': 'text-editor-to-pdf'
} as const;
/** Maps conversion endpoint → [i18n key, English fallback] for display names */
export const ENDPOINT_I18N: Record<string, [string, string]> = {
'img-to-pdf': ['imageToPDF.header', 'Image → PDF'],
'html-to-pdf': ['HTMLToPDF.header', 'HTML → PDF'],
'markdown-to-pdf': ['MarkdownToPDF.header', 'Markdown → PDF'],
'pdf-to-img': ['pdfToImage.title', 'PDF → Image'],
'pdf-to-word': ['PDFToWord.header', 'PDF → Word'],
'pdf-to-presentation': ['PDFToPresentation.header', 'PDF → Presentation'],
'pdf-to-text': ['PDFToText.header', 'PDF → Text'],
'pdf-to-csv': ['PDFToCSV.header', 'PDF → CSV'],
'pdf-to-xlsx': ['PDFToXLSX.header', 'PDF → Excel'],
'pdf-to-markdown': ['PDFToMarkdown.header', 'PDF → Markdown'],
'pdf-to-html': ['PDFToHTML.header', 'PDF → HTML'],
'pdf-to-xml': ['PDFToXML.header', 'PDF → XML'],
'pdf-to-pdfa': ['pdfToPDFA.header', 'PDF → PDF/A'],
'file-to-pdf': ['convert.fileToPdf', 'Office/Document → PDF'],
'cbr-to-pdf': ['convert.cbrToPdf', 'CBR → PDF'],
'cbz-to-pdf': ['convert.cbzToPdf', 'CBZ → PDF'],
'eml-to-pdf': ['convert.emlToPdf', 'Email → PDF'],
'ebook-to-pdf': ['convert.ebookToPdf', 'eBook → PDF'],
'svg-to-pdf': ['convert.svgToPdf', 'SVG → PDF'],
'pdf-to-cbr': ['convert.pdfToCbr', 'PDF → CBR'],
'pdf-to-cbz': ['convert.pdfToCbz', 'PDF → CBZ'],
'pdf-to-epub': ['convert.pdfToEpub', 'PDF → EPUB'],
};
// Grouped file extensions for dropdowns
export const FROM_FORMAT_OPTIONS = [

View File

@@ -38,7 +38,7 @@ const FREE_LICENSE_INFO: LicenseInfo = {
const BASE_NO_LOGIN_CONFIG: AppConfig = {
enableAnalytics: true,
appVersion: '2.6.0',
appVersion: '2.7.1',
serverCertificateEnabled: false,
enableAlphaFunctionality: false,
serverPort: 8080,

View File

@@ -8,7 +8,7 @@ import { selfHostedServerMonitor, type SelfHostedServerState } from '@app/servic
import { connectionModeService, type ConnectionMode } from '@app/services/connectionModeService';
import { tauriBackendService } from '@app/services/tauriBackendService';
import { endpointAvailabilityService } from '@app/services/endpointAvailabilityService';
import { EXTENSION_TO_ENDPOINT } from '@app/constants/convertConstants';
import { EXTENSION_TO_ENDPOINT, ENDPOINT_I18N } from '@app/constants/convertConstants';
import { ENDPOINTS as SPLIT_ENDPOINTS } from '@app/constants/splitConstants';
import type { ToolId } from '@app/types/toolId';
@@ -28,14 +28,6 @@ const SPLIT_ENDPOINT_I18N: Record<string, [string, string]> = {
'split-for-poster-print': ['split.methods.byPoster.name', 'Printable Chunks'],
};
/** Conversion endpoint keys that have translations under selfHosted.offline.conversionTypes */
const KNOWN_CONVERSION_ENDPOINTS = new Set([
'file-to-pdf', 'pdf-to-img', 'img-to-pdf', 'svg-to-pdf', 'cbz-to-pdf',
'pdf-to-cbz', 'pdf-to-word', 'pdf-to-presentation', 'pdf-to-text', 'pdf-to-csv',
'pdf-to-xlsx', 'pdf-to-markdown', 'pdf-to-html', 'pdf-to-xml', 'pdf-to-pdfa',
'html-to-pdf', 'markdown-to-pdf', 'eml-to-pdf', 'cbr-to-pdf', 'pdf-to-cbr',
'ebook-to-pdf', 'pdf-to-epub',
]);
/**
@@ -136,8 +128,9 @@ export function SelfHostedOfflineBanner() {
}
const conversionNames = [...unavailableEndpoints]
.map(ep => {
const suffix = KNOWN_CONVERSION_ENDPOINTS.has(ep)
? t(`selfHosted.offline.conversionTypes.${ep}`, ep)
const i18n = ENDPOINT_I18N[ep];
const suffix = i18n
? (i18n[0] ? t(i18n[0], i18n[1]) : i18n[1])
: ep;
return `${convertPrefix}: ${suffix}`;
})

View File

@@ -48,7 +48,7 @@ const FREE_LICENSE_INFO: LicenseInfo = {
const BASE_NO_LOGIN_CONFIG: AppConfig = {
enableAnalytics: true,
appVersion: '2.6.0',
appVersion: '2.7.1',
serverCertificateEnabled: false,
enableAlphaFunctionality: false,
enableDesktopInstallSlide: true,