Merge branch 'main' into disableConfigUpdater

This commit is contained in:
Anthony Stirling 2024-06-06 21:36:04 +01:00 committed by GitHub
commit d60107f48b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 110 additions and 47 deletions

View file

@ -159,7 +159,7 @@ Please view https://github.com/Stirling-Tools/Stirling-PDF/blob/main/HowToUseOCR
## Supported Languages ## Supported Languages
Stirling PDF currently supports 28! Stirling PDF currently supports 32!
| Language | Progress | | Language | Progress |
| ------------------------------------------- | -------------------------------------- | | ------------------------------------------- | -------------------------------------- |
@ -167,15 +167,15 @@ Stirling PDF currently supports 28!
| English (US) (en_US) | ![100%](https://geps.dev/progress/100) | | English (US) (en_US) | ![100%](https://geps.dev/progress/100) |
| Arabic (العربية) (ar_AR) | ![40%](https://geps.dev/progress/40) | | Arabic (العربية) (ar_AR) | ![40%](https://geps.dev/progress/40) |
| German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) | | German (Deutsch) (de_DE) | ![99%](https://geps.dev/progress/99) |
| French (Français) (fr_FR) | ![94%](https://geps.dev/progress/94) | | French (Français) (fr_FR) | ![93%](https://geps.dev/progress/93) |
| Spanish (Español) (es_ES) | ![95%](https://geps.dev/progress/95) | | Spanish (Español) (es_ES) | ![95%](https://geps.dev/progress/95) |
| Simplified Chinese (简体中文) (zh_CN) | ![95%](https://geps.dev/progress/95) | | Simplified Chinese (简体中文) (zh_CN) | ![95%](https://geps.dev/progress/95) |
| Traditional Chinese (繁體中文) (zh_TW) | ![94%](https://geps.dev/progress/94) | | Traditional Chinese (繁體中文) (zh_TW) | ![94%](https://geps.dev/progress/94) |
| Catalan (Català) (ca_CA) | ![49%](https://geps.dev/progress/49) | | Catalan (Català) (ca_CA) | ![49%](https://geps.dev/progress/49) |
| Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) | | Italian (Italiano) (it_IT) | ![98%](https://geps.dev/progress/98) |
| Swedish (Svenska) (sv_SE) | ![40%](https://geps.dev/progress/40) | | Swedish (Svenska) (sv_SE) | ![40%](https://geps.dev/progress/40) |
| Polish (Polski) (pl_PL) | ![43%](https://geps.dev/progress/43) | | Polish (Polski) (pl_PL) | ![42%](https://geps.dev/progress/42) |
| Romanian (Română) (ro_RO) | ![40%](https://geps.dev/progress/40) | | Romanian (Română) (ro_RO) | ![39%](https://geps.dev/progress/39) |
| Korean (한국어) (ko_KR) | ![87%](https://geps.dev/progress/87) | | Korean (한국어) (ko_KR) | ![87%](https://geps.dev/progress/87) |
| Portuguese Brazilian (Português) (pt_BR) | ![61%](https://geps.dev/progress/61) | | Portuguese Brazilian (Português) (pt_BR) | ![61%](https://geps.dev/progress/61) |
| Russian (Русский) (ru_RU) | ![87%](https://geps.dev/progress/87) | | Russian (Русский) (ru_RU) | ![87%](https://geps.dev/progress/87) |
@ -183,17 +183,17 @@ Stirling PDF currently supports 28!
| Japanese (日本語) (ja_JP) | ![87%](https://geps.dev/progress/87) | | Japanese (日本語) (ja_JP) | ![87%](https://geps.dev/progress/87) |
| Dutch (Nederlands) (nl_NL) | ![85%](https://geps.dev/progress/85) | | Dutch (Nederlands) (nl_NL) | ![85%](https://geps.dev/progress/85) |
| Greek (Ελληνικά) (el_GR) | ![85%](https://geps.dev/progress/85) | | Greek (Ελληνικά) (el_GR) | ![85%](https://geps.dev/progress/85) |
| Turkish (Türkçe) (tr_TR) | ![98%](https://geps.dev/progress/98) | | Turkish (Türkçe) (tr_TR) | ![97%](https://geps.dev/progress/97) |
| Indonesia (Bahasa Indonesia) (id_ID) | ![79%](https://geps.dev/progress/79) | | Indonesia (Bahasa Indonesia) (id_ID) | ![78%](https://geps.dev/progress/78) |
| Hindi (हिंदी) (hi_IN) | ![79%](https://geps.dev/progress/79) | | Hindi (हिंदी) (hi_IN) | ![79%](https://geps.dev/progress/79) |
| Hungarian (Magyar) (hu_HU) | ![78%](https://geps.dev/progress/78) | | Hungarian (Magyar) (hu_HU) | ![78%](https://geps.dev/progress/78) |
| Bulgarian (Български) (bg_BG) | ![98%](https://geps.dev/progress/98) | | Bulgarian (Български) (bg_BG) | ![98%](https://geps.dev/progress/98) |
| Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![81%](https://geps.dev/progress/81) | | Sebian Latin alphabet (Srpski) (sr_LATN_RS) | ![80%](https://geps.dev/progress/80) |
| Ukrainian (Українська) (uk_UA) | ![87%](https://geps.dev/progress/87) | | Ukrainian (Українська) (uk_UA) | ![86%](https://geps.dev/progress/86) |
| Slovakian (Slovensky) (sk_SK) | ![96%](https://geps.dev/progress/96) | | Slovakian (Slovensky) (sk_SK) | ![95%](https://geps.dev/progress/95) |
| Czech (Česky) (cs_CZ) | ![94%](https://geps.dev/progress/94) | | Czech (Česky) (cs_CZ) | ![94%](https://geps.dev/progress/94) |
| Croatian (Hrvatski) (hr_HR) | ![94%](https://geps.dev/progress/94) | | Croatian (Hrvatski) (hr_HR) | ![98%](https://geps.dev/progress/98) |
| Norwegian (Norsk) (no_NB) | ![94%](https://geps.dev/progress/94) | | Norwegian (Norsk) (no_NB) | ![98%](https://geps.dev/progress/98) |
## Contributing (creating issues, translations, fixing bugs, etc.) ## Contributing (creating issues, translations, fixing bugs, etc.)

View file

@ -1,5 +1,5 @@
apiVersion: v2 apiVersion: v2
appVersion: 0.25.1 appVersion: 0.25.2
description: locally hosted web application that allows you to perform various operations description: locally hosted web application that allows you to perform various operations
on PDF files on PDF files
home: https://github.com/Stirling-Tools/Stirling-PDF home: https://github.com/Stirling-Tools/Stirling-PDF

View file

@ -15,7 +15,10 @@ ignore = [
[cs_CZ] [cs_CZ]
ignore = [ ignore = [
'info',
'language.direction', 'language.direction',
'pipeline.header',
'text',
] ]
[de_DE] [de_DE]
@ -65,6 +68,16 @@ ignore = [
'language.direction', 'language.direction',
] ]
[hr_HR]
ignore = [
'font',
'home.pipeline.title',
'info',
'language.direction',
'pdfOrganiser.tags',
'showJS.tags',
]
[hu_HU] [hu_HU]
ignore = [ ignore = [
'language.direction', 'language.direction',
@ -103,6 +116,11 @@ ignore = [
'language.direction', 'language.direction',
] ]
[no_NB]
ignore = [
'language.direction',
]
[pl_PL] [pl_PL]
ignore = [ ignore = [
'language.direction', 'language.direction',

View file

@ -238,7 +238,7 @@ public class SecurityConfiguration {
GoogleProvider google = client.getGoogle(); GoogleProvider google = client.getGoogle();
return google != null && google.isSettingsValid() return google != null && google.isSettingsValid()
? Optional.of( ? Optional.of(
ClientRegistration.withRegistrationId("google") ClientRegistration.withRegistrationId(google.getName())
.clientId(google.getClientId()) .clientId(google.getClientId())
.clientSecret(google.getClientSecret()) .clientSecret(google.getClientSecret())
.scope(google.getScopes()) .scope(google.getScopes())
@ -246,8 +246,8 @@ public class SecurityConfiguration {
.tokenUri(google.getTokenuri()) .tokenUri(google.getTokenuri())
.userInfoUri(google.getUserinfouri()) .userInfoUri(google.getUserinfouri())
.userNameAttributeName(google.getUseAsUsername()) .userNameAttributeName(google.getUseAsUsername())
.clientName("Google") .clientName(google.getClientName())
.redirectUri("{baseUrl}/login/oauth2/code/google") .redirectUri("{baseUrl}/login/oauth2/code/" + google.getName())
.authorizationGrantType( .authorizationGrantType(
org.springframework.security.oauth2.core org.springframework.security.oauth2.core
.AuthorizationGrantType.AUTHORIZATION_CODE) .AuthorizationGrantType.AUTHORIZATION_CODE)
@ -269,12 +269,12 @@ public class SecurityConfiguration {
return keycloak != null && keycloak.isSettingsValid() return keycloak != null && keycloak.isSettingsValid()
? Optional.of( ? Optional.of(
ClientRegistrations.fromIssuerLocation(keycloak.getIssuer()) ClientRegistrations.fromIssuerLocation(keycloak.getIssuer())
.registrationId("keycloak") .registrationId(keycloak.getName())
.clientId(keycloak.getClientId()) .clientId(keycloak.getClientId())
.clientSecret(keycloak.getClientSecret()) .clientSecret(keycloak.getClientSecret())
.scope(keycloak.getScopes()) .scope(keycloak.getScopes())
.userNameAttributeName(keycloak.getUseAsUsername()) .userNameAttributeName(keycloak.getUseAsUsername())
.clientName("Keycloak") .clientName(keycloak.getClientName())
.build()) .build())
: Optional.empty(); : Optional.empty();
} }
@ -291,7 +291,7 @@ public class SecurityConfiguration {
GithubProvider github = client.getGithub(); GithubProvider github = client.getGithub();
return github != null && github.isSettingsValid() return github != null && github.isSettingsValid()
? Optional.of( ? Optional.of(
ClientRegistration.withRegistrationId("github") ClientRegistration.withRegistrationId(github.getName())
.clientId(github.getClientId()) .clientId(github.getClientId())
.clientSecret(github.getClientSecret()) .clientSecret(github.getClientSecret())
.scope(github.getScopes()) .scope(github.getScopes())
@ -299,8 +299,8 @@ public class SecurityConfiguration {
.tokenUri(github.getTokenuri()) .tokenUri(github.getTokenuri())
.userInfoUri(github.getUserinfouri()) .userInfoUri(github.getUserinfouri())
.userNameAttributeName(github.getUseAsUsername()) .userNameAttributeName(github.getUseAsUsername())
.clientName("GitHub") .clientName(github.getClientName())
.redirectUri("{baseUrl}/login/oauth2/code/github") .redirectUri("{baseUrl}/login/oauth2/code/" + github.getName())
.authorizationGrantType( .authorizationGrantType(
org.springframework.security.oauth2.core org.springframework.security.oauth2.core
.AuthorizationGrantType.AUTHORIZATION_CODE) .AuthorizationGrantType.AUTHORIZATION_CODE)

View file

@ -81,7 +81,7 @@ public class CustomOAuth2LogoutSuccessHandler extends SimpleUrlLogoutSuccessHand
logger.info("Session invalidated: " + sessionId); logger.info("Session invalidated: " + sessionId);
} }
switch (registrationId) { switch (registrationId.toLowerCase()) {
case "keycloak": case "keycloak":
// Add Keycloak specific logout URL if needed // Add Keycloak specific logout URL if needed
String logoutUrl = String logoutUrl =

View file

@ -16,6 +16,8 @@ import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import stirling.software.SPDF.config.security.LoginAttemptService; import stirling.software.SPDF.config.security.LoginAttemptService;
import stirling.software.SPDF.config.security.UserService; import stirling.software.SPDF.config.security.UserService;
import stirling.software.SPDF.model.ApplicationProperties; import stirling.software.SPDF.model.ApplicationProperties;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2;
import stirling.software.SPDF.model.ApplicationProperties.Security.OAUTH2.Client;
import stirling.software.SPDF.model.User; import stirling.software.SPDF.model.User;
public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> { public class CustomOAuth2UserService implements OAuth2UserService<OidcUserRequest, OidcUser> {
@ -41,11 +43,27 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
@Override @Override
public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException { public OidcUser loadUser(OidcUserRequest userRequest) throws OAuth2AuthenticationException {
String usernameAttribute = OAUTH2 oauth2 = applicationProperties.getSecurity().getOAUTH2();
applicationProperties.getSecurity().getOAUTH2().getUseAsUsername(); String usernameAttribute = oauth2.getUseAsUsername();
if (usernameAttribute == null || usernameAttribute.trim().isEmpty()) {
Client client = oauth2.getClient();
if (client != null && client.getKeycloak() != null) {
usernameAttribute = client.getKeycloak().getUseAsUsername();
} else {
usernameAttribute = "email";
}
}
try { try {
OidcUser user = delegate.loadUser(userRequest); OidcUser user = delegate.loadUser(userRequest);
String username = user.getUserInfo().getClaimAsString(usernameAttribute); String username = user.getUserInfo().getClaimAsString(usernameAttribute);
// Check if the username claim is null or empty
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException(
"Claim '" + usernameAttribute + "' cannot be null or empty");
}
Optional<User> duser = userService.findByUsernameIgnoreCase(username); Optional<User> duser = userService.findByUsernameIgnoreCase(username);
if (duser.isPresent()) { if (duser.isPresent()) {
if (loginAttemptService.isBlocked(username)) { if (loginAttemptService.isBlocked(username)) {
@ -56,13 +74,14 @@ public class CustomOAuth2UserService implements OAuth2UserService<OidcUserReques
throw new IllegalArgumentException("Password must not be null"); throw new IllegalArgumentException("Password must not be null");
} }
} }
// Return a new OidcUser with adjusted attributes // Return a new OidcUser with adjusted attributes
return new DefaultOidcUser( return new DefaultOidcUser(
user.getAuthorities(), user.getAuthorities(),
userRequest.getIdToken(), userRequest.getIdToken(),
user.getUserInfo(), user.getUserInfo(),
usernameAttribute); usernameAttribute);
} catch (java.lang.IllegalArgumentException e) { } catch (IllegalArgumentException e) {
logger.error("Error loading OIDC user: {}", e.getMessage()); logger.error("Error loading OIDC user: {}", e.getMessage());
throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e); throw new OAuth2AuthenticationException(new OAuth2Error(e.getMessage()), e);
} catch (Exception e) { } catch (Exception e) {

View file

@ -52,23 +52,23 @@ public class AccountWebController {
OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2(); OAUTH2 oauth = applicationProperties.getSecurity().getOAUTH2();
if (oauth != null) { if (oauth != null) {
if (oauth.isSettingsValid()) { if (oauth.isSettingsValid()) {
providerList.put("oidc", "OpenID Connect"); providerList.put("oidc", oauth.getProvider());
} }
Client client = oauth.getClient(); Client client = oauth.getClient();
if (client != null) { if (client != null) {
GoogleProvider google = client.getGoogle(); GoogleProvider google = client.getGoogle();
if (google.isSettingsValid()) { if (google.isSettingsValid()) {
providerList.put("google", "Google"); providerList.put(google.getName(), google.getClientName());
} }
GithubProvider github = client.getGithub(); GithubProvider github = client.getGithub();
if (github.isSettingsValid()) { if (github.isSettingsValid()) {
providerList.put("github", "Github"); providerList.put(github.getName(), github.getClientName());
} }
KeycloakProvider keycloak = client.getKeycloak(); KeycloakProvider keycloak = client.getKeycloak();
if (keycloak.isSettingsValid()) { if (keycloak.isSettingsValid()) {
providerList.put("keycloak", "Keycloak"); providerList.put(keycloak.getName(), keycloak.getClientName());
} }
} }
} }

View file

@ -356,7 +356,7 @@ public class ApplicationProperties {
private KeycloakProvider keycloak = new KeycloakProvider(); private KeycloakProvider keycloak = new KeycloakProvider();
public Provider get(String registrationId) throws Exception { public Provider get(String registrationId) throws Exception {
switch (registrationId) { switch (registrationId.toLowerCase()) {
case "google": case "google":
return getGoogle(); return getGoogle();
case "github": case "github":
@ -455,6 +455,7 @@ public class ApplicationProperties {
@Override @Override
public Collection<String> getScopes() { public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("https://www.googleapis.com/auth/userinfo.email"); scopes.add("https://www.googleapis.com/auth/userinfo.email");
scopes.add("https://www.googleapis.com/auth/userinfo.profile"); scopes.add("https://www.googleapis.com/auth/userinfo.profile");
} }
@ -495,6 +496,11 @@ public class ApplicationProperties {
return "google"; return "google";
} }
@Override
public String getClientName() {
return "Google";
}
public boolean isSettingsValid() { public boolean isSettingsValid() {
return super.isValid(this.getClientId(), "clientId") return super.isValid(this.getClientId(), "clientId")
&& super.isValid(this.getClientSecret(), "clientSecret") && super.isValid(this.getClientSecret(), "clientSecret")
@ -555,6 +561,7 @@ public class ApplicationProperties {
public Collection<String> getScopes() { public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes = new ArrayList<>();
scopes.add("read:user"); scopes.add("read:user");
} }
return scopes; return scopes;
@ -594,6 +601,11 @@ public class ApplicationProperties {
return "github"; return "github";
} }
@Override
public String getClientName() {
return "GitHub";
}
public boolean isSettingsValid() { public boolean isSettingsValid() {
return super.isValid(this.getClientId(), "clientId") return super.isValid(this.getClientId(), "clientId")
&& super.isValid(this.getClientSecret(), "clientSecret") && super.isValid(this.getClientSecret(), "clientSecret")
@ -642,7 +654,7 @@ public class ApplicationProperties {
@Override @Override
public Collection<String> getScopes() { public Collection<String> getScopes() {
if (scopes == null || scopes.isEmpty()) { if (scopes == null || scopes.isEmpty()) {
scopes.add("openid"); scopes = new ArrayList<>();
scopes.add("profile"); scopes.add("profile");
scopes.add("email"); scopes.add("email");
} }
@ -684,6 +696,11 @@ public class ApplicationProperties {
return "keycloak"; return "keycloak";
} }
@Override
public String getClientName() {
return "Keycloak";
}
public boolean isSettingsValid() { public boolean isSettingsValid() {
return isValid(this.getIssuer(), "issuer") return isValid(this.getIssuer(), "issuer")
&& isValid(this.getClientId(), "clientId") && isValid(this.getClientId(), "clientId")

View file

@ -4,11 +4,16 @@ import java.util.Collection;
public class Provider implements ProviderInterface { public class Provider implements ProviderInterface {
private String name; private String name;
private String clientName;
public String getName() { public String getName() {
return name; return name;
} }
public String getClientName() {
return clientName;
}
protected boolean isValid(String value, String name) { protected boolean isValid(String value, String name) {
if (value != null && !value.trim().isEmpty()) { if (value != null && !value.trim().isEmpty()) {
return true; return true;

View file

@ -26,7 +26,7 @@ bored=Nudíte se při čekání?
alphabet=Abeceda alphabet=Abeceda
downloadPdf=Stáhnout PDF downloadPdf=Stáhnout PDF
text=Text text=Text
font=Font font=Písmo
selectFillter=-- Vyberte -- selectFillter=-- Vyberte --
pageNum=Číslo stránky pageNum=Číslo stránky
sizes.small=Malé sizes.small=Malé

View file

@ -71,7 +71,7 @@ visitGithub=GitHub-Repository besuchen
donate=Spenden donate=Spenden
color=Farbe color=Farbe
sponsor=Sponsor sponsor=Sponsor
info=Die Info info=Informationen
@ -660,10 +660,10 @@ certSign.submit=PDF signieren
#removeCertSign #removeCertSign
removeCertSign.title=Remove Certificate Signature removeCertSign.title=Zertifikatsignatur entfernen
removeCertSign.header=Remove the digital certificate from the PDF removeCertSign.header=Digitales Zertifikat aus dem PDF entfernen
removeCertSign.selectPDF=Select a PDF file: removeCertSign.selectPDF=PDF-Datei auswählen:
removeCertSign.submit=Remove Signature removeCertSign.submit=Signatur entfernen
#removeBlanks #removeBlanks

View file

@ -1,7 +1,7 @@
########### ###########
# Generic # # Generic #
########### ###########
# the direction that the language is written (ltr=left to right, rtl = right to left) # the direction that the language is written (ltr = left to right, rtl = right to left)
language.direction=ltr language.direction=ltr
pdfPrompt=Odaberi PDF(ove) pdfPrompt=Odaberi PDF(ove)
@ -331,9 +331,10 @@ compare.tags=razlikovati,kontrast,izmjene,analiza
home.certSign.title=Potpišite s certifikatom home.certSign.title=Potpišite s certifikatom
home.certSign.desc=Potpisuje PDF s certifikatom/ključem (PEM/P12) home.certSign.desc=Potpisuje PDF s certifikatom/ključem (PEM/P12)
certSign.tags=autentifikacija,PEM,P12,zvanično,šifriranje certSign.tags=autentifikacija,PEM,P12,zvanično,šifriranje
# home.removeCertSign.title=Remove Certificate Sign
# home.removeCertSign.desc=Remove certificate signature from PDF home.removeCertSign.title=Remove Certificate Sign
# removeCertSign.tags=authenticate,PEM,P12,official,decrypt home.removeCertSign.desc=Remove certificate signature from PDF
removeCertSign.tags=authenticate,PEM,P12,official,decrypt
home.pageLayout.title=Izgled s više stranica home.pageLayout.title=Izgled s više stranica
home.pageLayout.desc=Spojite više stranica PDF dokumenta u jednu stranicu home.pageLayout.desc=Spojite više stranica PDF dokumenta u jednu stranicu
@ -656,10 +657,13 @@ certSign.reason=Razlog
certSign.location=Mjesto certSign.location=Mjesto
certSign.name=Ime certSign.name=Ime
certSign.submit=Potpiši PDF certSign.submit=Potpiši PDF
# removeCertSign.title=Remove Certificate Signature
# removeCertSign.header=Remove the digital certificate from the PDF
# removeCertSign.selectPDF=Select a PDF file: #removeCertSign
# removeCertSign.submit=Remove Signature removeCertSign.title=Remove Certificate Signature
removeCertSign.header=Remove the digital certificate from the PDF
removeCertSign.selectPDF=Select a PDF file:
removeCertSign.submit=Remove Signature
#removeBlanks #removeBlanks

View file

@ -438,7 +438,7 @@ PDFToBook.tags=bok,comic,calibre,konvertere,manga,amazon,kindle,epub,mobi,azw3,d
home.BookToPDF.title=Bok til PDF home.BookToPDF.title=Bok til PDF
home.BookToPDF.desc=Konverter bøker/tegneserier til PDF ved hjelp av calibre home.BookToPDF.desc=Konverter bøker/tegneserier til PDF ved hjelp av calibre
BookToPDF.tags=Book,Comic,Calibre,Convert,manga,amazon,kindle,epub,mobi,azw3,docx,rtf,txt,html,lit,fb2,pdb,lrf
########################### ###########################
@ -783,7 +783,7 @@ compress.selectText.2=Optimeringsnivå:
compress.selectText.3=4 (Dårlig for tekstbilder) compress.selectText.3=4 (Dårlig for tekstbilder)
compress.selectText.4=Automatisk modus - Justerer automatisk kvaliteten for å få PDF til nøyaktig størrelse compress.selectText.4=Automatisk modus - Justerer automatisk kvaliteten for å få PDF til nøyaktig størrelse
compress.selectText.5=Forventet PDF-størrelse (f.eks. 25MB, 10.8MB, 25KB) compress.selectText.5=Forventet PDF-størrelse (f.eks. 25MB, 10.8MB, 25KB)
compress.Submit=Komprimer compress.submit=Komprimer
#Add image #Add image
@ -855,7 +855,7 @@ split.desc.6=Dokument #4: Side 8
split.desc.7=Dokument #5: Side 9 split.desc.7=Dokument #5: Side 9
split.desc.8=Dokument #6: Side 10 split.desc.8=Dokument #6: Side 10
split.splitPages=Skriv inn sidene som skal deles på: split.splitPages=Skriv inn sidene som skal deles på:
split.Submit=Del split.submit=Del
#merge #merge