Erweiterungen

This commit is contained in:
2026-02-19 20:51:33 +01:00
parent 041451afa1
commit fcf54ea0cc
17 changed files with 1532 additions and 70 deletions

View File

@@ -0,0 +1,56 @@
/**
* Cookie names for language preference
*/
const LANGUAGE_COOKIE_NAME = 'votianlt.language';
const COOKIE_MAX_AGE_DAYS = 365; // Cookie gültig für 1 Jahr
/**
* Sets the language cookie with the selected language code
* @param languageCode - The language code (e.g., 'de', 'en', 'fr', 'es')
*/
export function setLanguageCookie(languageCode: string): void {
const maxAge = COOKIE_MAX_AGE_DAYS * 24 * 60 * 60; // Convert days to seconds
document.cookie = `${LANGUAGE_COOKIE_NAME}=${languageCode};path=/;max-age=${maxAge};SameSite=Lax`;
}
/**
* Gets the language code from the cookie
* @returns The language code or null if not found
*/
export function getLanguageCookie(): string | null {
const cookies = document.cookie.split(';');
for (const cookie of cookies) {
const [name, value] = cookie.trim().split('=');
if (name === LANGUAGE_COOKIE_NAME) {
return decodeURIComponent(value);
}
}
return null;
}
/**
* Clears the language cookie
*/
export function clearLanguageCookie(): void {
document.cookie = `${LANGUAGE_COOKIE_NAME}=;path=/;max-age=0;SameSite=Lax`;
}
/**
* Maps Language enum values to locale strings
*/
export const languageToLocale: Record<string, string> = {
'DE': 'de',
'EN': 'en',
'FR': 'fr',
'ES': 'es'
};
/**
* Maps locale strings to Language enum values
*/
export const localeToLanguage: Record<string, string> = {
'de': 'DE',
'en': 'EN',
'fr': 'FR',
'es': 'ES'
};

View File

@@ -5,6 +5,7 @@ import com.vaadin.flow.server.ServiceInitEvent;
import com.vaadin.flow.server.VaadinServiceInitListener; import com.vaadin.flow.server.VaadinServiceInitListener;
import de.assecutor.votianlt.model.Language; import de.assecutor.votianlt.model.Language;
import de.assecutor.votianlt.security.CustomUserPrincipal; import de.assecutor.votianlt.security.CustomUserPrincipal;
import jakarta.servlet.http.Cookie;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@@ -17,48 +18,154 @@ import java.util.Locale;
* Sets the user's preferred locale on the UI BEFORE any layout or view is * Sets the user's preferred locale on the UI BEFORE any layout or view is
* constructed. Registered via {@code UIInitListener} → {@code BeforeEnterListener}, * constructed. Registered via {@code UIInitListener} → {@code BeforeEnterListener},
* which fires prior to the router creating the layout component tree. * which fires prior to the router creating the layout component tree.
*
* For authenticated users: Uses the language preference from the user profile.
* For anonymous users: Uses the language from the 'votianlt.language' cookie
* or falls back to the browser's preferred locale.
*/ */
@Component @Component
@Slf4j @Slf4j
public class LocaleVaadinInitListener implements VaadinServiceInitListener { public class LocaleVaadinInitListener implements VaadinServiceInitListener {
private static final String LANGUAGE_COOKIE_NAME = "votianlt.language";
@Override @Override
public void serviceInit(ServiceInitEvent event) { public void serviceInit(ServiceInitEvent event) {
event.getSource().addUIInitListener(uiInitEvent -> { event.getSource().addUIInitListener(uiInitEvent -> {
UI ui = uiInitEvent.getUI(); UI ui = uiInitEvent.getUI();
ui.addBeforeEnterListener(beforeEnterEvent -> applyLocaleFromCurrentUser(ui)); ui.addBeforeEnterListener(beforeEnterEvent -> applyLocale(ui));
}); });
} }
private void applyLocaleFromCurrentUser(UI ui) { private void applyLocale(UI ui) {
try { try {
Authentication auth = SecurityContextHolder.getContext().getAuthentication(); Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth == null || !auth.isAuthenticated() || auth instanceof AnonymousAuthenticationToken) {
return; if (auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken)) {
} // Authenticated user: use profile language
if (!(auth.getPrincipal() instanceof CustomUserPrincipal cup)) { applyLocaleFromAuthenticatedUser(ui, auth);
return; } else {
} // Anonymous user: use cookie or browser locale
Language language = cup.getUser().getLanguage(); applyLocaleFromCookieOrBrowser(ui);
if (language == null) {
return;
}
Locale targetLocale = getLocaleFromLanguage(language);
if (!targetLocale.equals(ui.getLocale())) {
ui.setLocale(targetLocale);
log.debug("Locale set to {} for user {}", targetLocale, cup.getUsername());
} }
} catch (Exception e) { } catch (Exception e) {
log.debug("Could not apply locale from user preferences: {}", e.getMessage()); log.debug("Could not apply locale: {}", e.getMessage());
} }
} }
private void applyLocaleFromAuthenticatedUser(UI ui, Authentication auth) {
if (!(auth.getPrincipal() instanceof CustomUserPrincipal cup)) {
return;
}
Language language = cup.getUser().getLanguage();
if (language == null) {
return;
}
Locale targetLocale = getLocaleFromLanguage(language);
if (!targetLocale.equals(ui.getLocale())) {
ui.setLocale(targetLocale);
log.debug("Locale set to {} for authenticated user {}", targetLocale, cup.getUsername());
}
}
private void applyLocaleFromCookieOrBrowser(UI ui) {
Locale targetLocale = null;
// Try to get locale from cookie first
String cookieLanguage = getLanguageFromCookie(ui);
if (cookieLanguage != null) {
targetLocale = getLocaleFromLanguageCode(cookieLanguage);
log.debug("Using locale {} from cookie for anonymous user", targetLocale);
}
// If no cookie, use browser's preferred locale if supported
if (targetLocale == null) {
targetLocale = getSupportedLocaleFromBrowser(ui);
if (targetLocale != null) {
log.debug("Using browser locale {} for anonymous user", targetLocale);
}
}
// Apply the locale if different from current
if (targetLocale != null && !targetLocale.equals(ui.getLocale())) {
ui.setLocale(targetLocale);
log.debug("Locale set to {} for anonymous user", targetLocale);
}
}
private String getLanguageFromCookie(UI ui) {
try {
var request = com.vaadin.flow.server.VaadinRequest.getCurrent();
if (request == null) {
return null;
}
Cookie[] cookies = request.getCookies();
if (cookies == null) {
return null;
}
for (Cookie cookie : cookies) {
if (LANGUAGE_COOKIE_NAME.equals(cookie.getName())) {
return cookie.getValue();
}
}
} catch (Exception e) {
log.debug("Could not read language cookie: {}", e.getMessage());
}
return null;
}
private Locale getSupportedLocaleFromBrowser(UI ui) {
// Get the browser's preferred locales
var locale = ui.getSession().getBrowser().getLocale();
if (locale == null) {
return null;
}
// Check if the browser locale is supported
String language = locale.getLanguage().toLowerCase();
return switch (language) {
case "de" -> Locale.GERMAN;
case "en" -> Locale.ENGLISH;
case "fr" -> Locale.FRENCH;
case "es" -> Locale.of("es", "ES");
default -> null; // Return null to use Vaadin's default
};
}
private Locale getLocaleFromLanguage(Language language) { private Locale getLocaleFromLanguage(Language language) {
return switch (language) { return switch (language) {
case DE -> Locale.GERMAN; case DE -> Locale.GERMAN;
case EN -> Locale.ENGLISH; case EN -> Locale.ENGLISH;
case FR -> Locale.FRENCH; case FR -> Locale.FRENCH;
case ES -> Locale.of("es", "ES"); case ES -> Locale.of("es", "ES");
case TR -> Locale.of("tr", "TR");
case PL -> Locale.of("pl", "PL");
case RU -> Locale.of("ru", "RU");
case EE -> Locale.of("et", "EE");
case LV -> Locale.of("lv", "LV");
case LT -> Locale.of("lt", "LT");
};
}
private Locale getLocaleFromLanguageCode(String languageCode) {
if (languageCode == null) {
return null;
}
return switch (languageCode.toUpperCase()) {
case "DE" -> Locale.GERMAN;
case "EN" -> Locale.ENGLISH;
case "FR" -> Locale.FRENCH;
case "ES" -> Locale.of("es", "ES");
case "TR" -> Locale.of("tr", "TR");
case "PL" -> Locale.of("pl", "PL");
case "RU" -> Locale.of("ru", "RU");
case "EE" -> Locale.of("et", "EE");
case "LV" -> Locale.of("lv", "LV");
case "LT" -> Locale.of("lt", "LT");
default -> null;
}; };
} }
} }

View File

@@ -9,19 +9,53 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.ResourceBundle.Control;
@Component @Component
public class TranslationProvider implements I18NProvider { public class TranslationProvider implements I18NProvider {
public static final String BUNDLE_PREFIX = "messages"; public static final String BUNDLE_PREFIX = "messages";
// Custom Control to map language codes to file names
private static final Control BUNDLE_CONTROL = new Control() {
@Override
public List<Locale> getCandidateLocales(String baseName, Locale locale) {
// Map Estonian "et" to "ee" file, Latvian "lv" to "lv", Lithuanian "lt" to "lt"
String language = locale.getLanguage();
String country = locale.getCountry();
// Create a locale that matches our file naming convention
Locale mappedLocale = switch (language) {
case "et" -> new Locale("ee"); // Estonian -> messages_ee.properties
case "lv" -> new Locale("lv"); // Latvian -> messages_lv.properties
case "lt" -> new Locale("lt"); // Lithuanian -> messages_lt.properties
case "ru" -> new Locale("ru"); // Russian -> messages_ru.properties
case "pl" -> new Locale("pl"); // Polish -> messages_pl.properties
case "tr" -> new Locale("tr"); // Turkish -> messages_tr.properties
case "es" -> new Locale("es"); // Spanish -> messages_es.properties
case "fr" -> new Locale("fr"); // French -> messages_fr.properties
case "en" -> new Locale("en"); // English -> messages_en.properties
case "de" -> new Locale("de"); // German -> messages.properties (default)
default -> locale;
};
return super.getCandidateLocales(baseName, mappedLocale);
}
};
@Override @Override
public List<Locale> getProvidedLocales() { public List<Locale> getProvidedLocales() {
return Collections.unmodifiableList(Arrays.asList( return Collections.unmodifiableList(Arrays.asList(
Locale.GERMAN, Locale.GERMAN,
Locale.ENGLISH, Locale.ENGLISH,
Locale.FRENCH, Locale.FRENCH,
Locale.of("es", "ES") Locale.of("es", "ES"),
Locale.of("tr", "TR"),
Locale.of("pl", "PL"),
Locale.of("ru", "RU"),
Locale.of("et", "EE"),
Locale.of("lv", "LV"),
Locale.of("lt", "LT")
)); ));
} }
@@ -32,7 +66,7 @@ public class TranslationProvider implements I18NProvider {
} }
try { try {
ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_PREFIX, locale); ResourceBundle bundle = ResourceBundle.getBundle(BUNDLE_PREFIX, locale, BUNDLE_CONTROL);
String value = bundle.getString(key); String value = bundle.getString(key);
if (params.length > 0) { if (params.length > 0) {
@@ -51,6 +85,12 @@ public class TranslationProvider implements I18NProvider {
case EN -> Locale.ENGLISH; case EN -> Locale.ENGLISH;
case FR -> Locale.FRENCH; case FR -> Locale.FRENCH;
case ES -> Locale.of("es", "ES"); case ES -> Locale.of("es", "ES");
case TR -> Locale.of("tr", "TR");
case PL -> Locale.of("pl", "PL");
case RU -> Locale.of("ru", "RU");
case EE -> Locale.of("et", "EE");
case LV -> Locale.of("lv", "LV");
case LT -> Locale.of("lt", "LT");
}; };
return getTranslation(key, locale); return getTranslation(key, locale);
} }

View File

@@ -4,7 +4,13 @@ public enum Language {
DE("Deutsch"), DE("Deutsch"),
EN("English"), EN("English"),
FR("Français"), FR("Français"),
ES("Español"); ES("Español"),
TR("Türkçe"),
PL("Polski"),
RU("Русский"),
EE("Eesti"),
LV("Latviešu"),
LT("Lietuvių");
private final String displayName; private final String displayName;

View File

@@ -498,6 +498,12 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle
case EN -> "🇬🇧 "; case EN -> "🇬🇧 ";
case FR -> "🇫🇷 "; case FR -> "🇫🇷 ";
case ES -> "🇪🇸 "; case ES -> "🇪🇸 ";
case TR -> "🇹🇷 ";
case PL -> "🇵🇱 ";
case RU -> "🇷🇺 ";
case EE -> "🇪🇪 ";
case LV -> "🇱🇻 ";
case LT -> "🇱🇹 ";
}; };
return flag + language.getDisplayName(); return flag + language.getDisplayName();
}); });
@@ -507,6 +513,9 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle
languageCombo.addValueChangeListener(e -> { languageCombo.addValueChangeListener(e -> {
// Language will be saved when the user clicks save button // Language will be saved when the user clicks save button
currentUser.setLanguage(e.getValue()); currentUser.setLanguage(e.getValue());
// Also set the language cookie so it's available before login
setLanguageCookie(e.getValue());
}); });
languageLayout.add(languageLabel, languageCombo); languageLayout.add(languageLabel, languageCombo);
@@ -1845,6 +1854,34 @@ public class EditProfileView extends HorizontalLayout implements HasDynamicTitle
} }
} }
/**
* Sets the language cookie via JavaScript so the selected language
* is available even before the user logs in (e.g., on the login page).
*
* @param language the selected language
*/
private void setLanguageCookie(Language language) {
String languageCode = switch (language) {
case DE -> "DE";
case EN -> "EN";
case FR -> "FR";
case ES -> "ES";
case TR -> "TR";
case PL -> "PL";
case RU -> "RU";
case EE -> "EE";
case LV -> "LV";
case LT -> "LT";
};
// Execute JavaScript to set the cookie
UI.getCurrent().getPage().executeJs(
"const maxAge = 365 * 24 * 60 * 60;" +
"document.cookie = 'votianlt.language=' + $0 + ';path=/;max-age=' + maxAge + ';SameSite=Lax';",
languageCode
);
}
@Override @Override
public String getPageTitle() { public String getPageTitle() {
return getTranslation("page.title.profile.edit"); return getTranslation("page.title.profile.edit");

View File

@@ -223,32 +223,32 @@ public class RegisterView extends VerticalLayout implements HasDynamicTitle {
// Validierung // Validierung
if (email.isEmpty()) { if (email.isEmpty()) {
Notification.show("Bitte geben Sie eine E-Mail-Adresse ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.email.required"), 3000, Notification.Position.MIDDLE);
emailField.focus(); emailField.focus();
return; return;
} }
if (!email.contains("@") || !email.contains(".")) { if (!email.contains("@") || !email.contains(".")) {
Notification.show("Bitte geben Sie eine gültige E-Mail-Adresse ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.email.invalid"), 3000, Notification.Position.MIDDLE);
emailField.focus(); emailField.focus();
return; return;
} }
if (userService.existsByEmail(email)) { if (userService.existsByEmail(email)) {
Notification.show("Ein Benutzer mit dieser E-Mail-Adresse existiert bereits.", 4000, Notification.show(getTranslation("register.notification.email.duplicate"), 4000,
Notification.Position.MIDDLE); Notification.Position.MIDDLE);
return; return;
} }
if (password.isEmpty()) { if (password.isEmpty()) {
Notification.show("Bitte geben Sie ein Passwort ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.password.required"), 3000, Notification.Position.MIDDLE);
passwordField.focus(); passwordField.focus();
return; return;
} }
if (password.length() < 6) { if (password.length() < 6) {
Notification.show("Das Passwort muss mindestens 6 Zeichen lang sein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.password.min"), 3000, Notification.Position.MIDDLE);
passwordField.focus(); passwordField.focus();
return; return;
} }
if (!password.equals(confirmPassword)) { if (!password.equals(confirmPassword)) {
Notification.show("Die Passwörter stimmen nicht überein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.password.mismatch"), 3000, Notification.Position.MIDDLE);
confirmPasswordField.focus(); confirmPasswordField.focus();
return; return;
} }
@@ -256,49 +256,49 @@ public class RegisterView extends VerticalLayout implements HasDynamicTitle {
// Weitere Pflichtfelder prüfen (aus Edit-Profile) // Weitere Pflichtfelder prüfen (aus Edit-Profile)
var firstName = firstNameField.getValue() != null ? firstNameField.getValue().trim() : ""; var firstName = firstNameField.getValue() != null ? firstNameField.getValue().trim() : "";
if (firstName.isEmpty()) { if (firstName.isEmpty()) {
Notification.show("Bitte geben Sie Ihren Vornamen ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.firstname.required"), 3000, Notification.Position.MIDDLE);
firstNameField.focus(); firstNameField.focus();
return; return;
} }
var lastName = lastNameField.getValue() != null ? lastNameField.getValue().trim() : ""; var lastName = lastNameField.getValue() != null ? lastNameField.getValue().trim() : "";
if (lastName.isEmpty()) { if (lastName.isEmpty()) {
Notification.show("Bitte geben Sie Ihren Nachnamen ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.lastname.required"), 3000, Notification.Position.MIDDLE);
lastNameField.focus(); lastNameField.focus();
return; return;
} }
var phone = phoneField.getValue() != null ? phoneField.getValue().trim() : ""; var phone = phoneField.getValue() != null ? phoneField.getValue().trim() : "";
if (phone.isEmpty()) { if (phone.isEmpty()) {
Notification.show("Bitte geben Sie Ihre Telefonnummer ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.phone.required"), 3000, Notification.Position.MIDDLE);
phoneField.focus(); phoneField.focus();
return; return;
} }
var company = companyField.getValue() != null ? companyField.getValue().trim() : ""; var company = companyField.getValue() != null ? companyField.getValue().trim() : "";
if (company.isEmpty()) { if (company.isEmpty()) {
Notification.show("Bitte geben Sie den Firmennamen ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.company.required"), 3000, Notification.Position.MIDDLE);
companyField.focus(); companyField.focus();
return; return;
} }
var street = streetField.getValue() != null ? streetField.getValue().trim() : ""; var street = streetField.getValue() != null ? streetField.getValue().trim() : "";
if (street.isEmpty()) { if (street.isEmpty()) {
Notification.show("Bitte geben Sie die Straße ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.street.required"), 3000, Notification.Position.MIDDLE);
streetField.focus(); streetField.focus();
return; return;
} }
var houseNo = houseNumberField.getValue() != null ? houseNumberField.getValue().trim() : ""; var houseNo = houseNumberField.getValue() != null ? houseNumberField.getValue().trim() : "";
if (houseNo.isEmpty()) { if (houseNo.isEmpty()) {
Notification.show("Bitte geben Sie die Hausnummer ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.housenr.required"), 3000, Notification.Position.MIDDLE);
houseNumberField.focus(); houseNumberField.focus();
return; return;
} }
var zip = zipField.getValue() != null ? zipField.getValue().trim() : ""; var zip = zipField.getValue() != null ? zipField.getValue().trim() : "";
if (zip.isEmpty()) { if (zip.isEmpty()) {
Notification.show("Bitte geben Sie die Postleitzahl ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.zip.required"), 3000, Notification.Position.MIDDLE);
zipField.focus(); zipField.focus();
return; return;
} }
var city = cityField.getValue() != null ? cityField.getValue().trim() : ""; var city = cityField.getValue() != null ? cityField.getValue().trim() : "";
if (city.isEmpty()) { if (city.isEmpty()) {
Notification.show("Bitte geben Sie die Stadt ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.city.required"), 3000, Notification.Position.MIDDLE);
cityField.focus(); cityField.focus();
return; return;
} }
@@ -311,7 +311,7 @@ public class RegisterView extends VerticalLayout implements HasDynamicTitle {
// Rate-Limit: 60 Sekunden zwischen Sendungen // Rate-Limit: 60 Sekunden zwischen Sendungen
if (lastSentAt != null && Duration.between(lastSentAt, LocalDateTime.now()).getSeconds() < 60) { if (lastSentAt != null && Duration.between(lastSentAt, LocalDateTime.now()).getSeconds() < 60) {
long wait = 60 - Duration.between(lastSentAt, LocalDateTime.now()).getSeconds(); long wait = 60 - Duration.between(lastSentAt, LocalDateTime.now()).getSeconds();
Notification.show("Bitte warten Sie " + wait + " Sekunden, bevor Sie den Code erneut senden.", 4000, Notification.show(getTranslation("passwordreset.notification.wait", wait), 4000,
Notification.Position.MIDDLE); Notification.Position.MIDDLE);
return; return;
} }
@@ -320,9 +320,8 @@ public class RegisterView extends VerticalLayout implements HasDynamicTitle {
codeExpiresAt = LocalDateTime.now().plusMinutes(10); codeExpiresAt = LocalDateTime.now().plusMinutes(10);
lastSentAt = LocalDateTime.now(); lastSentAt = LocalDateTime.now();
String subject = "Ihr VotianLT Bestätigungscode"; String subject = getTranslation("email.2fa.subject");
String body = "Ihr Bestätigungscode lautet: " + code + "\n\n" + "Dieser Code ist 10 Minuten gültig.\n" String body = getTranslation("email.2fa.body", code);
+ "Wenn Sie diese Registrierung nicht angefragt haben, ignorieren Sie diese E-Mail.";
try { try {
emailService.sendSimpleEmail(email, subject, body); emailService.sendSimpleEmail(email, subject, body);
awaitingVerification = true; awaitingVerification = true;
@@ -348,31 +347,31 @@ public class RegisterView extends VerticalLayout implements HasDynamicTitle {
submitButton.setEnabled(false); submitButton.setEnabled(false);
Notification.show("Ein Bestätigungscode wurde an " + email + " gesendet.", 4000, Notification.show(getTranslation("register.notification.code.sent", email), 4000,
Notification.Position.MIDDLE); Notification.Position.MIDDLE);
} catch (Exception e) { } catch (Exception e) {
awaitingVerification = false; awaitingVerification = false;
Notification.show("Fehler beim Senden der E-Mail: " + e.getMessage(), 5000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.code.emailerror", e.getMessage()), 5000, Notification.Position.MIDDLE);
} }
} }
private void onVerifyCode() { private void onVerifyCode() {
if (!awaitingVerification) { if (!awaitingVerification) {
Notification.show("Bitte starten Sie zuerst die Registrierung.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.code.startfirst"), 3000, Notification.Position.MIDDLE);
return; return;
} }
String entered = codeField.getValue() != null ? codeField.getValue().trim() : ""; String entered = codeField.getValue() != null ? codeField.getValue().trim() : "";
if (!entered.matches("\\d{6}")) { if (!entered.matches("\\d{6}")) {
Notification.show("Bitte geben Sie den 6-stelligen Code ein.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.code.required"), 3000, Notification.Position.MIDDLE);
return; return;
} }
if (codeExpiresAt == null || LocalDateTime.now().isAfter(codeExpiresAt)) { if (codeExpiresAt == null || LocalDateTime.now().isAfter(codeExpiresAt)) {
Notification.show("Der Code ist abgelaufen. Bitte senden Sie einen neuen Code.", 4000, Notification.show(getTranslation("register.notification.code.expired"), 4000,
Notification.Position.MIDDLE); Notification.Position.MIDDLE);
return; return;
} }
if (!entered.equals(pendingCode)) { if (!entered.equals(pendingCode)) {
Notification.show("Der eingegebene Code ist ungültig.", 3000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.code.invalid"), 3000, Notification.Position.MIDDLE);
return; return;
} }
@@ -399,10 +398,10 @@ public class RegisterView extends VerticalLayout implements HasDynamicTitle {
user.setCity(city); user.setCity(city);
userService.save(user); userService.save(user);
VaadinSession.getCurrent().setAttribute("flashMessage", VaadinSession.getCurrent().setAttribute("flashMessage",
"Registrierung erfolgreich. Bitte melden Sie sich an."); getTranslation("register.notification.success"));
getUI().ifPresent(ui -> ui.navigate("login")); getUI().ifPresent(ui -> ui.navigate("login"));
} catch (RuntimeException e) { } catch (RuntimeException e) {
Notification.show("Registrierung fehlgeschlagen: " + e.getMessage(), 5000, Notification.Position.MIDDLE); Notification.show(getTranslation("register.notification.failed", e.getMessage()), 5000, Notification.Position.MIDDLE);
} }
} }

View File

@@ -5,6 +5,7 @@ import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button; import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant; import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.combobox.ComboBox; import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.contextmenu.ContextMenu;
import com.vaadin.flow.component.html.*; import com.vaadin.flow.component.html.*;
import com.vaadin.flow.component.icon.Icon; import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon; import com.vaadin.flow.component.icon.VaadinIcon;
@@ -16,9 +17,12 @@ import com.vaadin.flow.router.Route;
import com.vaadin.flow.router.BeforeEnterEvent; import com.vaadin.flow.router.BeforeEnterEvent;
import com.vaadin.flow.router.BeforeEnterObserver; import com.vaadin.flow.router.BeforeEnterObserver;
import com.vaadin.flow.server.auth.AnonymousAllowed; import com.vaadin.flow.server.auth.AnonymousAllowed;
import de.assecutor.votianlt.model.Language;
import de.assecutor.votianlt.security.SecurityService; import de.assecutor.votianlt.security.SecurityService;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import java.util.Locale;
@Route("") @Route("")
@AnonymousAllowed @AnonymousAllowed
public class StartView extends VerticalLayout implements BeforeEnterObserver, HasDynamicTitle { public class StartView extends VerticalLayout implements BeforeEnterObserver, HasDynamicTitle {
@@ -94,10 +98,90 @@ public class StartView extends VerticalLayout implements BeforeEnterObserver, Ha
Button registerBtn = new Button(getTranslation("start.button.register"), event -> register()); Button registerBtn = new Button(getTranslation("start.button.register"), event -> register());
registerBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY); registerBtn.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
navButtons.add(loginBtn, registerBtn); // Sprachauswahl Button
Button languageBtn = createLanguageSelector();
navButtons.add(loginBtn, registerBtn, languageBtn);
return navButtons; return navButtons;
} }
private Button createLanguageSelector() {
// Aktuelle Sprache aus der UI-Locale ermitteln (wird vom LocaleVaadinInitListener gesetzt)
String currentLang = getCurrentLanguageFromLocale();
String flag = getFlagForLanguage(currentLang);
Button languageBtn = new Button(flag + " " + currentLang);
languageBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
ContextMenu languageMenu = new ContextMenu();
languageMenu.setOpenOnClick(true);
languageMenu.setTarget(languageBtn);
// Alle Sprachen hinzufügen
for (Language lang : Language.values()) {
String langFlag = getFlagForLanguage(lang.name());
String langText = langFlag + " " + lang.getDisplayName();
languageMenu.addItem(langText, event -> {
setLanguageCookie(lang.name());
// Seite neu laden um die neue Sprache anzuwenden
UI.getCurrent().getPage().reload();
});
}
return languageBtn;
}
private String getCurrentLanguageFromLocale() {
// Aktuelle UI-Locale verwenden (wird vom LocaleVaadinInitListener aus Cookie/Browser gesetzt)
Locale locale = UI.getCurrent().getLocale();
if (locale == null) {
return "DE";
}
String language = locale.getLanguage();
return switch (language) {
case "en" -> "EN";
case "fr" -> "FR";
case "es" -> "ES";
case "tr" -> "TR";
case "pl" -> "PL";
case "ru" -> "RU";
case "et" -> "EE"; // Estnisch
case "lv" -> "LV"; // Lettisch
case "lt" -> "LT"; // Litauisch
default -> "DE"; // German as default
};
}
private String getFlagForLanguage(String languageCode) {
if (languageCode == null) {
return "🇩🇪";
}
return switch (languageCode.toUpperCase()) {
case "DE" -> "🇩🇪";
case "EN" -> "🇬🇧";
case "FR" -> "🇫🇷";
case "ES" -> "🇪🇸";
case "TR" -> "🇹🇷";
case "PL" -> "🇵🇱";
case "RU" -> "🇷🇺";
case "EE" -> "🇪🇪";
case "LV" -> "🇱🇻";
case "LT" -> "🇱🇹";
default -> "🇩🇪";
};
}
private void setLanguageCookie(String languageCode) {
UI.getCurrent().getPage().executeJs(
"const maxAge = 365 * 24 * 60 * 60;" +
"document.cookie = 'votianlt.language=' + $0 + ';path=/;max-age=' + maxAge + ';SameSite=Lax';",
languageCode
);
}
private Component createAuthenticatedNavigation() { private Component createAuthenticatedNavigation() {
HorizontalLayout navLayout = new HorizontalLayout(); HorizontalLayout navLayout = new HorizontalLayout();
navLayout.setSpacing(true); navLayout.setSpacing(true);
@@ -185,9 +269,7 @@ public class StartView extends VerticalLayout implements BeforeEnterObserver, Ha
heroTitle.getStyle().set("color", "var(--lumo-primary-text-color)"); heroTitle.getStyle().set("color", "var(--lumo-primary-text-color)");
heroTitle.getStyle().set("margin-bottom", "var(--lumo-space-l)"); heroTitle.getStyle().set("margin-bottom", "var(--lumo-space-l)");
Paragraph heroDescription = new Paragraph("Für Solo-Selbstständige und Kleinunternehmer im Transportgewerbe - " Paragraph heroDescription = new Paragraph(getTranslation("start.hero.description"));
+ "volldigital und aus einem Guss. Konzentrieren Sie sich auf Ihr Geschäft, "
+ "wir kümmern uns um die Büroarbeit.");
heroDescription.getStyle().set("text-align", "center"); heroDescription.getStyle().set("text-align", "center");
heroDescription.getStyle().set("max-width", "600px"); heroDescription.getStyle().set("max-width", "600px");
heroDescription.getStyle().set("font-size", "var(--lumo-font-size-l)"); heroDescription.getStyle().set("font-size", "var(--lumo-font-size-l)");
@@ -208,13 +290,11 @@ public class StartView extends VerticalLayout implements BeforeEnterObserver, Ha
systemSection.getStyle().set("background-color", "var(--lumo-base-color)"); systemSection.getStyle().set("background-color", "var(--lumo-base-color)");
// Section Header // Section Header
H2 systemTitle = new H2("Das System"); H2 systemTitle = new H2(getTranslation("start.system.title"));
systemTitle.getStyle().set("color", "var(--lumo-primary-color)"); systemTitle.getStyle().set("color", "var(--lumo-primary-color)");
systemTitle.getStyle().set("text-align", "center"); systemTitle.getStyle().set("text-align", "center");
Paragraph systemIntro = new Paragraph( Paragraph systemIntro = new Paragraph(getTranslation("start.system.intro"));
"Für Solo-Selbstständige und Kleinunternehmer im Transportgewerbe ist von entscheidender Bedeutung, "
+ "dass sie sich in erster Linie auf ihr eigentliches Geschäft konzentrieren können: Kunden gewinnen und Waren von A nach B liefern.");
systemIntro.getStyle().set("text-align", "center"); systemIntro.getStyle().set("text-align", "center");
systemIntro.getStyle().set("max-width", "800px"); systemIntro.getStyle().set("max-width", "800px");
systemIntro.getStyle().set("margin-bottom", "var(--lumo-space-xl)"); systemIntro.getStyle().set("margin-bottom", "var(--lumo-space-xl)");
@@ -227,12 +307,12 @@ public class StartView extends VerticalLayout implements BeforeEnterObserver, Ha
featuresGrid.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.STRETCH); featuresGrid.setDefaultVerticalComponentAlignment(FlexComponent.Alignment.STRETCH);
// Feature Cards // Feature Cards
featuresGrid.add(createFeatureCard(VaadinIcon.COG, "Einrichtungsassistent", featuresGrid.add(createFeatureCard(VaadinIcon.COG, getTranslation("start.feature.setup.title"),
"Mithilfe des Einrichtungsassistenten haben Sie die Möglichkeit, Ihr Nutzerprofil zu vervollständigen."), getTranslation("start.feature.setup.desc")),
createFeatureCard(VaadinIcon.USERS, "Kunden- und Auftragsverwaltung", createFeatureCard(VaadinIcon.USERS, getTranslation("start.feature.customers.title"),
"Mit der Kunden- und Auftragsverwaltung haben Sie alle Kontaktdaten und Auftragsdetails stets im Blick."), getTranslation("start.feature.customers.desc")),
createFeatureCard(VaadinIcon.CLIPBOARD_TEXT, "Auftragserstellung", createFeatureCard(VaadinIcon.CLIPBOARD_TEXT, getTranslation("start.feature.jobs.title"),
"Stellen Sie mit wenigen Mausklicks Aufträge ins System ein und legen Sie fest, welcher Mitarbeiter welchen Transportauftrag abarbeiten soll.")); getTranslation("start.feature.jobs.desc")));
systemSection.add(systemTitle, systemIntro, featuresGrid); systemSection.add(systemTitle, systemIntro, featuresGrid);
return systemSection; return systemSection;
@@ -274,13 +354,11 @@ public class StartView extends VerticalLayout implements BeforeEnterObserver, Ha
appSection.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER); appSection.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
appSection.getStyle().set("background-color", "var(--lumo-contrast-5pct)"); appSection.getStyle().set("background-color", "var(--lumo-contrast-5pct)");
H2 appTitle = new H2("Die App"); H2 appTitle = new H2(getTranslation("start.app.title"));
appTitle.getStyle().set("color", "var(--lumo-primary-color)"); appTitle.getStyle().set("color", "var(--lumo-primary-color)");
appTitle.getStyle().set("text-align", "center"); appTitle.getStyle().set("text-align", "center");
Paragraph appDescription = new Paragraph( Paragraph appDescription = new Paragraph(getTranslation("start.app.description"));
"Jeder Auftrag kann optional über die votianLT-App abgearbeitet werden ganz ohne \"Zettelwirtschaft\". "
+ "So gelangen alle relevanten Auftragsinformationen direkt auf das Smartphone des Fahrers.");
appDescription.getStyle().set("text-align", "center"); appDescription.getStyle().set("text-align", "center");
appDescription.getStyle().set("max-width", "800px"); appDescription.getStyle().set("max-width", "800px");
@@ -302,7 +380,7 @@ public class StartView extends VerticalLayout implements BeforeEnterObserver, Ha
footer.getStyle().set("border-top", "1px solid var(--lumo-contrast-20pct)"); footer.getStyle().set("border-top", "1px solid var(--lumo-contrast-20pct)");
// Company Info // Company Info
H3 companyTitle = new H3("Impressum"); H3 companyTitle = new H3(getTranslation("start.imprint.title"));
companyTitle.getStyle().set("color", "var(--lumo-primary-color)"); companyTitle.getStyle().set("color", "var(--lumo-primary-color)");
companyTitle.getStyle().set("text-align", "center"); companyTitle.getStyle().set("text-align", "center");
@@ -311,18 +389,17 @@ public class StartView extends VerticalLayout implements BeforeEnterObserver, Ha
companyInfo.setPadding(false); companyInfo.setPadding(false);
companyInfo.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER); companyInfo.setDefaultHorizontalComponentAlignment(FlexComponent.Alignment.CENTER);
companyInfo.add(new Paragraph("Assecutor Data Service GmbH"), new Paragraph("Ottensener Str. 8, 22525 Hamburg"), companyInfo.add(new Paragraph(getTranslation("start.imprint.company")), new Paragraph(getTranslation("start.imprint.address")),
new Paragraph("Telefon: +49 40 18 123 771 0"), new Paragraph("E-Mail: ahoi@assecutor.de")); new Paragraph(getTranslation("start.imprint.phone")), new Paragraph(getTranslation("start.imprint.email")));
// Call to Action // Call to Action
Paragraph ctaText = new Paragraph("Registrieren Sie sich noch heute und nutzen den kostenfreien Probemonat, " Paragraph ctaText = new Paragraph(getTranslation("start.cta.text"));
+ "um das System auf Herz und Nieren zu testen.");
ctaText.getStyle().set("text-align", "center"); ctaText.getStyle().set("text-align", "center");
ctaText.getStyle().set("font-weight", "bold"); ctaText.getStyle().set("font-weight", "bold");
ctaText.getStyle().set("color", "var(--lumo-primary-color)"); ctaText.getStyle().set("color", "var(--lumo-primary-color)");
ctaText.getStyle().set("margin-top", "var(--lumo-space-l)"); ctaText.getStyle().set("margin-top", "var(--lumo-space-l)");
Paragraph slogan = new Paragraph("Betreiben Sie Ihr Geschäft smart … mit votianLT!"); Paragraph slogan = new Paragraph(getTranslation("start.slogan"));
slogan.getStyle().set("text-align", "center"); slogan.getStyle().set("text-align", "center");
slogan.getStyle().set("font-style", "italic"); slogan.getStyle().set("font-style", "italic");
slogan.getStyle().set("color", "var(--lumo-primary-color)"); slogan.getStyle().set("color", "var(--lumo-primary-color)");

View File

@@ -763,7 +763,9 @@ start.button.register=Registrieren
start.button.createorder=Auftragserstellung start.button.createorder=Auftragserstellung
start.button.notifications=Benachrichtigungen start.button.notifications=Benachrichtigungen
start.button.nonotifications=Keine neuen Benachrichtigungen start.button.nonotifications=Keine neuen Benachrichtigungen
start.hero.description=Für Solo-Selbstständige und Kleinunternehmer im Transportgewerbe - volldigital und aus einem Guss. Konzentrieren Sie sich auf Ihr Geschäft, wir kümmern uns um die Büroarbeit.
start.system.title=Das System start.system.title=Das System
start.system.intro=Für Solo-Selbstständige und Kleinunternehmer im Transportgewerbe ist von entscheidender Bedeutung, dass sie sich in erster Linie auf ihr eigentliches Geschäft konzentrieren können: Kunden gewinnen und Waren von A nach B liefern.
start.feature.setup.title=Einrichtungsassistent start.feature.setup.title=Einrichtungsassistent
start.feature.setup.desc=Mithilfe des Einrichtungsassistenten haben Sie die Möglichkeit, Ihr Nutzerprofil zu vervollständigen. start.feature.setup.desc=Mithilfe des Einrichtungsassistenten haben Sie die Möglichkeit, Ihr Nutzerprofil zu vervollständigen.
start.feature.customers.title=Kunden- und Auftragsverwaltung start.feature.customers.title=Kunden- und Auftragsverwaltung
@@ -777,6 +779,7 @@ start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Telefon: +49 40 18 123 771 0 start.imprint.phone=Telefon: +49 40 18 123 771 0
start.imprint.email=E-Mail: ahoi@assecutor.de start.imprint.email=E-Mail: ahoi@assecutor.de
start.cta.text=Registrieren Sie sich noch heute und nutzen den kostenfreien Probemonat, um das System auf Herz und Nieren zu testen.
start.slogan=Betreiben Sie Ihr Geschäft smart … mit votianLT! start.slogan=Betreiben Sie Ihr Geschäft smart … mit votianLT!
start.version=Version start.version=Version

View File

@@ -0,0 +1,188 @@
# Navigation and Main Layout
nav.jobs=Ülesanded
nav.job.create=Loo ülesanne
nav.customers=Kliendid
nav.appusers=Rakenduse kasutajad
nav.statistics=Statistika
nav.invoices=Arved
nav.messages=Sõnumid
nav.profile=Minu profiil
nav.myinvoices=Minu arved
nav.imprint=Impressum
nav.management=Juhtimine
nav.users=Kasutajad
nav.showprofile=Kuva profiil
nav.settings=Seaded
nav.logout=Logi välja
# Profile View
profile.title=Muuda profiili
profile.language=Keel
profile.company=Ettevõte
profile.companyadd=Ettevõtte lisa
profile.firstname=Eesnimi
profile.lastname=Perekonnanimi
profile.phone=Telefoninumber
profile.fax=Faks
profile.mobile=Mobiiltelefon
profile.email=E-posti aadress (Sisselogimine)*
profile.street=Tänav
profile.housenr=Maja number
profile.addressadd=Aadressi lisa
profile.postcode=Postiindeks
profile.city=Linn
profile.diffinvoice=Erinev arveaadress
profile.basicdata=Põhiandmed
profile.map=Kaart
profile.invoicecreation=Arve loomine
profile.settings=Seaded
profile.account=Konto
profile.security=Turvalisus
profile.services=Teenuste kataloog
profile.saved=Profiil salvestatud
profile.save.error=Viga salvestamisel: {0}
profile.validation.required.fill=Palun täitke kõik kohustuslikud väljad õigesti
# Profile Settings
settings.digitalprocessing=Digitaalne töötlemine rakenduse kaudu
settings.digitalprocessinginfo=Lubab digitaalse ülesannete töötlemise mobiilirakenduse kaudu
settings.locationtracking=Rakenduse kasutajate asukoha jälgimine
settings.locationtrackinginfo=Võimaldab jälgida rakenduse kasutajate asukohta ülesande täitmise ajal
settings.twofactor=Kahefaktoriline autentimine
settings.twofactorinfo=Aktiveerimisel saadetakse igal sisselogimisel e-posti teel kood
# Profile Billing
profile.billing.enabled=Arveldamine votianLT kaudu
# Profile Validation
profile.validation.company=Ettevõte on kohustuslik väli
profile.validation.firstname=Eesnimi on kohustuslik väli
profile.validation.lastname=Perekonnanimi on kohustuslik väli
profile.validation.phone=Telefoninumber on kohustuslik väli
profile.validation.street=Tänav on kohustuslik väli
profile.validation.housenr=Maja number on kohustuslik väli
profile.validation.postcode=Postiindeks on kohustuslik väli
profile.validation.city=Linn on kohustuslik väli
profile.validation.email.required=E-posti aadress on kohustuslik väli
profile.validation.email.invalid=Palun sisestage kehtiv e-posti aadress
profile.validation.company.required=Ettevõte on nõutav
profile.validation.street.required=Tänav on nõutav
profile.validation.housenr.required=Maja number on nõutav
profile.validation.postcode.required=Postiindeks on nõutav
profile.validation.city.required=Linn on nõutav
profile.validation.firstname.required=Eesnimi on nõutav
profile.validation.lastname.required=Perekonnanimi on nõutav
profile.validation.phone.required=Telefoninumber on nõutav
# Buttons
button.save=Salvesta profiili muudatused
button.savechanges=Salvesta
button.clear=Tühjenda
button.preview=Eelvaade
button.savetemplate=Salvesta mall
button.changepassword=Muuda parooli
button.deleteaccount=Kustuta konto
button.add=Uus
button.edit=Muuda
button.delete=Kustuta
button.cancel=Tühista
button.close=Sulge
button.download=Lae alla
button.back=Tagasi
# Common
common.name=Nimi
common.yes=Jah
common.no=Ei
common.total=Kokku
common.price=Hind
common.service=Teenus
common.customer=Klient
common.actions=Tegevused
common.loading=Laadimine...
common.error=Viga
common.success=Edu
common.required=Kohustuslik väli
# Validation
validation.required=Väli on kohustuslik
validation.email=Kehtetu e-posti aadress
validation.error=Valideerimise viga
# Notifications
notification.saved=Profiil salvestatud
notification.error=Viga salvestamisel
notification.languagechanged=Keel muudetud
# Login
login.title=Logi sisse
login.username=Kasutajanimi
login.password=Parool
login.login=Logi sisse
login.forgotpassword=Unustasid parooli?
login.rememberme=Jäta meelde
login.register=Registreeru
login.2fa.helper=6-kohaline kood
login.2fa.sent=Kood saadetud e-postiga
login.2fa.no.credentials=Sisselogimisandmeid pole
login.2fa.invalid.code=Kehtetu kood
login.2fa.wrong.code=Vale kood
# Error Messages
error.loading=Laadimise viga
error.saving=Salvestamise viga
error.validation=Valideerimise viga
# Page Titles
page.title.welcome=VotianLT - Tere tulemast
page.title.login=VotianLT - Sisselogimine
# Start Page
start.title=VotianLT - Teie digitaalne transpordipartner
start.button.login=Logi sisse
start.button.register=Registreeru
start.button.createorder=Loo ülesanne
start.button.notifications=Teated
start.button.nonotifications=Uusi teateid pole
start.hero.description=Transporditööstuses tegutsevatele üksikettevõtjatele ja väikeettevõtetele täiesti digitaalne ja kõik-ühes. Keskenduge oma ärile, meie hoolitseme paberitöö eest.
start.system.title=Süsteem
start.system.intro=Transporditööstuses tegutsevatele üksikettevõtjatele ja väikeettevõtetele on äärmiselt oluline keskenduda eelkõige oma põhitegevusele: klientide võitmisele ja kaupade kohaletoimetamisele punktist A punkti B.
start.feature.setup.title=Seadistusassistent
start.feature.setup.desc=Kasutage seadistusassistenti, et täita oma kasutajaprofiil.
start.feature.customers.title=Klientide ja ülesannete haldamine
start.feature.customers.desc=Klientide ja ülesannete haldamisega on teil alati kõik kontaktandmed ja ülesannete üksikasjad silme ees.
start.feature.jobs.title=Ülesannete loomine
start.feature.jobs.desc=Looge süsteemis ülesandeid vaid mõne klõpsuga ja määrake, milline töötaja peab millist transpordiülesannet täitma.
start.app.title=Rakendus
start.app.description=Iga ülesanne saab vabatahtlikult täidetud votianLT rakenduse kaudu täiesti ilma "paberimajandusteta". Kogu oluline ülesande info läheb otse juhi nutitelefoni.
start.imprint.title=Impressum
start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Telefon: +49 40 18 123 771 0
start.imprint.email=E-post: ahoi@assecutor.de
start.cta.text=Registreeruge juba täna ja kasutage süsteemi põhjalikuks testimiseks tasuta proovikuud!
start.slogan=Juhtige oma äri nutikalt … koos votianLT-ga!
start.version=Versioon
# Register
register.title=Registreerimine
register.subtitle=Loo oma VotianLT konto
register.email=E-posti aadress
register.password=Parool
register.password.placeholder=Vähemalt 6 tähemärki
register.password.confirm=Kinnita parool
register.password.confirm.placeholder=Sisesta parool uuesti
register.firstname=Eesnimi
register.lastname=Perekonnanimi
register.phone=Telefoninumber
register.company=Ettevõte
register.street=Tänav
register.housenr=Maja number
register.postcode=Postiindeks
register.city=Linn
register.button.submit=Registreeru
register.notification.success=Registreerimine õnnestus. Palun logi sisse.
register.notification.failed=Registreerimine ebaõnnestus: {0}
# CTA Button
cta.freetest=Proovi tasuta

View File

@@ -763,7 +763,9 @@ start.button.register=Register
start.button.createorder=Create Order start.button.createorder=Create Order
start.button.notifications=Notifications start.button.notifications=Notifications
start.button.nonotifications=No new notifications start.button.nonotifications=No new notifications
start.hero.description=For solo self-employed and small business owners in the transport industry - fully digital and all-in-one. Focus on your business, we take care of the paperwork.
start.system.title=The System start.system.title=The System
start.system.intro=For solo self-employed and small business owners in the transport industry, it is crucial to focus primarily on their core business: winning customers and delivering goods from A to B.
start.feature.setup.title=Setup Assistant start.feature.setup.title=Setup Assistant
start.feature.setup.desc=Use the setup assistant to complete your user profile. start.feature.setup.desc=Use the setup assistant to complete your user profile.
start.feature.customers.title=Customer and Job Management start.feature.customers.title=Customer and Job Management
@@ -777,6 +779,7 @@ start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Phone: +49 40 18 123 771 0 start.imprint.phone=Phone: +49 40 18 123 771 0
start.imprint.email=Email: ahoi@assecutor.de start.imprint.email=Email: ahoi@assecutor.de
start.cta.text=Register today and use the free trial month to test the system thoroughly.
start.slogan=Run your business smart … with votianLT! start.slogan=Run your business smart … with votianLT!
start.version=Version start.version=Version

View File

@@ -763,7 +763,9 @@ start.button.register=Registrarse
start.button.createorder=Crear Pedido start.button.createorder=Crear Pedido
start.button.notifications=Notificaciones start.button.notifications=Notificaciones
start.button.nonotifications=No hay notificaciones nuevas start.button.nonotifications=No hay notificaciones nuevas
start.hero.description=Para autónomos y pequeñas empresas del sector del transporte - totalmente digital y todo en uno. Concéntrese en su negocio, nosotros nos ocupamos del papeleo.
start.system.title=El Sistema start.system.title=El Sistema
start.system.intro=Para autónomos y pequeñas empresas del sector del transporte, es crucial concentrarse principalmente en su negocio principal: ganar clientes y entregar mercancías de A a B.
start.feature.setup.title=Asistente de Configuración start.feature.setup.title=Asistente de Configuración
start.feature.setup.desc=Use el asistente de configuración para completar su perfil de usuario. start.feature.setup.desc=Use el asistente de configuración para completar su perfil de usuario.
start.feature.customers.title=Gestión de Clientes y Trabajos start.feature.customers.title=Gestión de Clientes y Trabajos
@@ -777,6 +779,7 @@ start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Teléfono: +49 40 18 123 771 0 start.imprint.phone=Teléfono: +49 40 18 123 771 0
start.imprint.email=Correo: ahoi@assecutor.de start.imprint.email=Correo: ahoi@assecutor.de
start.cta.text=¡Regístrese hoy y use el mes de prueba gratuito para probar el sistema a fondo!
start.slogan=¡Opere su negocio de forma inteligente … con votianLT! start.slogan=¡Opere su negocio de forma inteligente … con votianLT!
start.version=Versión start.version=Versión

View File

@@ -772,6 +772,9 @@ start.feature.jobs.title=Création d'Emplois
start.feature.jobs.desc=Créez des emplois dans le système en quelques clics et déterminez quel employé doit traiter quel emploi de transport. start.feature.jobs.desc=Créez des emplois dans le système en quelques clics et déterminez quel employé doit traiter quel emploi de transport.
start.app.title=L'App start.app.title=L'App
start.app.description=Chaque emploi peut être traité optionnellement via l'app votianLT - complètement sans "paperasse". Toutes les informations pertinentes de l'emploi vont directement sur le smartphone du conducteur. start.app.description=Chaque emploi peut être traité optionnellement via l'app votianLT - complètement sans "paperasse". Toutes les informations pertinentes de l'emploi vont directement sur le smartphone du conducteur.
start.hero.description=Pour indépendants et petites entreprises du secteur du transport - entièrement numérique et tout-en-un. Concentrez-vous sur votre entreprise, nous nous occupons de la paperasse.
start.system.intro=Pour indépendants et petites entreprises du secteur du transport, il est crucial de se concentrer principalement sur leur cœur de métier : gagner des clients et livrer des marchandises de A à B.
start.cta.text=Inscrivez-vous dès aujourd'hui et profitez du mois d'essai gratuit pour tester le système à fond !
start.imprint.title=Mentions Légales start.imprint.title=Mentions Légales
start.imprint.company=Assecutor Data Service GmbH start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hambourg start.imprint.address=Ottensener Str. 8, 22525 Hambourg

View File

@@ -0,0 +1,188 @@
# Navigation and Main Layout
nav.jobs=Užduotys
nav.job.create=Sukurti užduotį
nav.customers=Klientai
nav.appusers=Programėlės naudotojai
nav.statistics=Statistika
nav.invoices=Sąskaitos
nav.messages=Žinutės
nav.profile=Mano profilis
nav.myinvoices=Mano sąskaitos
nav.imprint=Impressum
nav.management=Valdymas
nav.users=Naudotojai
nav.showprofile=Rodyti profilį
nav.settings=Nustatymai
nav.logout=Atsijungti
# Profile View
profile.title=Redaguoti profilį
profile.language=Kalba
profile.company=Įmonė
profile.companyadd=Įmonės papildymas
profile.firstname=Vardas
profile.lastname=Pavardė
profile.phone=Telefono numeris
profile.fax=Faksas
profile.mobile=Mobilusis telefonas
profile.email=El. pašto adresas (Prisijungimas)*
profile.street=Gatvė
profile.housenr=Namo numeris
profile.addressadd=Adreso papildymas
profile.postcode=Pašto kodas
profile.city=Miestas
profile.diffinvoice=Kitas atsiskaitymo adresas
profile.basicdata=Pagrindiniai duomenys
profile.map=Žemėlapis
profile.invoicecreation=Sąskaitos kūrimas
profile.settings=Nustatymai
profile.account=Paskyra
profile.security=Saugumas
profile.services=Paslaugų katalogas
profile.saved=Profilis išsaugotas
profile.save.error=Klaida išsaugant: {0}
profile.validation.required.fill=Prašome teisingai užpildyti visus privalomus laukus
# Profile Settings
settings.digitalprocessing=Skaitmeninis apdorojimas per programėlę
settings.digitalprocessinginfo=Įgalina skaitmeninį užduočių apdorojimą per mobiliojo programėlę
settings.locationtracking=Programėlės naudotojų vietos sekimas
settings.locationtrackinginfo=Leidžia sekti programėlės naudotojų vietą užduoties vykdymo metu
settings.twofactor=Dvivėjinė autentifikacija
settings.twofactorinfo=Aktyvavus, kiekvieno prisijungimo metu el. paštu siunčiamas kodas
# Profile Billing
profile.billing.enabled=Atsiskaitymas per votianLT
# Profile Validation
profile.validation.company=Įmonė yra privalomas laukas
profile.validation.firstname=Vardas yra privalomas laukas
profile.validation.lastname=Pavardė yra privalomas laukas
profile.validation.phone=Telefono numeris yra privalomas laukas
profile.validation.street=Gatvė yra privalomas laukas
profile.validation.housenr=Namo numeris yra privalomas laukas
profile.validation.postcode=Pašto kodas yra privalomas laukas
profile.validation.city=Miestas yra privalomas laukas
profile.validation.email.required=El. pašto adresas yra privalomas laukas
profile.validation.email.invalid=Prašome įvesti galiojantį el. pašto adresą
profile.validation.company.required=Reikalinga įmonė
profile.validation.street.required=Reikalinga gatvė
profile.validation.housenr.required=Reikalingas namo numeris
profile.validation.postcode.required=Reikalingas pašto kodas
profile.validation.city.required=Reikalingas miestas
profile.validation.firstname.required=Reikalingas vardas
profile.validation.lastname.required=Reikalinga pavardė
profile.validation.phone.required=Reikalingas telefono numeris
# Buttons
button.save=Išsaugoti profilio pakeitimus
button.savechanges=Išsaugoti
button.clear=Išvalyti
button.preview=Peržiūra
button.savetemplate=Išsaugoti šabloną
button.changepassword=Keisti slaptažodį
button.deleteaccount=Ištrinti paskyrą
button.add=Naujas
button.edit=Redaguoti
button.delete=Ištrinti
button.cancel=Atšaukti
button.close=Uždaryti
button.download=Atsisiųsti
button.back=Atgal
# Common
common.name=Pavadinimas
common.yes=Taip
common.no=Ne
common.total=Iš viso
common.price=Kaina
common.service=Paslauga
common.customer=Klientas
common.actions=Veiksmai
common.loading=Įkeliama...
common.error=Klaida
common.success=Sėkmė
common.required=Privalomas laukas
# Validation
validation.required=Laukas yra privalomas
validation.email=Netinkamas el. pašto adresas
validation.error=Validavimo klaida
# Notifications
notification.saved=Profilis išsaugotas
notification.error=Klaida išsaugant
notification.languagechanged=Kalba pakeista
# Login
login.title=Prisijungti
login.username=Naudotojo vardas
login.password=Slaptažodis
login.login=Prisijungti
login.forgotpassword=Pamiršote slaptažodį?
login.rememberme=Prisiminti mane
login.register=Registruotis
login.2fa.helper=6 skaitmenų kodas
login.2fa.sent=Kodas išsiųstas el. paštu
login.2fa.no.credentials=Nėra prisijungimo duomenų
login.2fa.invalid.code=Netinkamas kodas
login.2fa.wrong.code=Neteisingas kodas
# Error Messages
error.loading=Įkėlimo klaida
error.saving=Išsaugojimo klaida
error.validation=Validavimo klaida
# Page Titles
page.title.welcome=VotianLT - Sveiki atvykę
page.title.login=VotianLT - Prisijungimas
# Start Page
start.title=VotianLT - Jūsų skaitmeninis transporto partneris
start.button.login=Prisijungti
start.button.register=Registruotis
start.button.createorder=Sukurti užduotį
start.button.notifications=Pranešimai
start.button.nonotifications=Nėra naujų pranešimų
start.hero.description=Individualiems specialistams ir mažoms transporto įmonėms visiškai skaitmeninis ir viskas viename. Susikoncentruokite į savo verslą, o mes pasirūpinsime dokumentais.
start.system.title=Sistema
start.system.intro=Individualiems specialistams ir mažoms transporto įmonėms labai svarbu susikoncentruoti į pagrindinę veiklą: klientų pritraukimą ir krovinių gabenimą iš taško A į tašką B.
start.feature.setup.title=Nustatymo asistentas
start.feature.setup.desc=Naudokitės nustatymo asistentu, kad užpildytumėte savo naudotojo profilį.
start.feature.customers.title=Klientų ir užduočių valdymas
start.feature.customers.desc=Su klientų ir užduočių valdymu visada turite visus kontaktinius duomenis ir užduočių detales prieš akis.
start.feature.jobs.title=Užduočių kūrimas
start.feature.jobs.desc=Sukurkite užduotis sistemoje vos keliais paspaudimais ir nustatykite, kuris darbuotojas turi atlikti kurią transporto užduotį.
start.app.title=Programėlė
start.app.description=Kiekviena užduotis gali būti atliekama pasirinktinai per votianLT programėlę visiškai be "popierizmo". Visa svarbi užduoties informacija tiesiai patenka į vairuotojo išmanųjį telefoną.
start.imprint.title=Impressum
start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Telefonas: +49 40 18 123 771 0
start.imprint.email=El. paštas: ahoi@assecutor.de
start.cta.text=Registruokitės jau šiandien ir pasinaudokite nemokamu bandomuoju mėnesiu, kad kruopščiai išbandytumėte sistemą!
start.slogan=Veskite savo verslą protingai … su votianLT!
start.version=Versija
# Register
register.title=Registracija
register.subtitle=Sukurkite savo VotianLT paskyrą
register.email=El. pašto adresas
register.password=Slaptažodis
register.password.placeholder=Mažiausiai 6 simboliai
register.password.confirm=Patvirtinkite slaptažodį
register.password.confirm.placeholder=Įveskite slaptažodį dar kartą
register.firstname=Vardas
register.lastname=Pavardė
register.phone=Telefono numeris
register.company=Įmonė
register.street=Gatvė
register.housenr=Namo numeris
register.postcode=Pašto kodas
register.city=Miestas
register.button.submit=Registruotis
register.notification.success=Registracija sėkminga. Prašome prisijungti.
register.notification.failed=Registracijos klaida: {0}
# CTA Button
cta.freetest=Išbandykite nemokamai

View File

@@ -0,0 +1,188 @@
# Navigation and Main Layout
nav.jobs=Uzdevumi
nav.job.create=Izveidot uzdevumu
nav.customers=Klienti
nav.appusers=Lietotnes lietotāji
nav.statistics=Statistika
nav.invoices=Rēķini
nav.messages=Ziņojumi
nav.profile=Mans profils
nav.myinvoices=Mani rēķini
nav.imprint=Impressum
nav.management=Pārvaldība
nav.users=Lietotāji
nav.showprofile=Rādīt profilu
nav.settings=Iestatījumi
nav.logout=Izrakstīties
# Profile View
profile.title=Rediģēt profilu
profile.language=Valoda
profile.company=Uzņēmums
profile.companyadd=Uzņēmuma papildinājums
profile.firstname=Vārds
profile.lastname=Uzvārds
profile.phone=Tālruņa numurs
profile.fax=Fakss
profile.mobile=Mobilais tālrunis
profile.email=E-pasta adrese (Pieteikšanās)*
profile.street=Iela
profile.housenr=Mājas numurs
profile.addressadd=Adreses papildinājums
profile.postcode=Pasta indekss
profile.city=Pilsēta
profile.diffinvoice=Cita norēķinu adrese
profile.basicdata=Pamatdati
profile.map=Karte
profile.invoicecreation=Rēķina izveide
profile.settings=Iestatījumi
profile.account=Konts
profile.security=Drošība
profile.services=Pakalpojumu katalogs
profile.saved=Profils saglabāts
profile.save.error=Kļūda saglabājot: {0}
profile.validation.required.fill=Lūdzu, pareizi aizpildiet visus obligātos laukus
# Profile Settings
settings.digitalprocessing=Digitālā apstrāde caur lietotni
settings.digitalprocessinginfo=Iespējo digitālo uzdevumu apstrādi caur mobilās lietotnes
settings.locationtracking=Lietotnes lietotāju atrašanās vietas izsekošana
settings.locationtrackinginfo=Ļauj izsekot lietotnes lietotāju atrašanās vietu uzdevuma izpildes laikā
settings.twofactor=Divfaktoru autentifikācija
settings.twofactorinfo=Aktivējot, katras pieteikšanās laikā pa e-pastu tiek nosūtīts kods
# Profile Billing
profile.billing.enabled=Norēķini caur votianLT
# Profile Validation
profile.validation.company=Uzņēmums ir obligāts lauks
profile.validation.firstname=Vārds ir obligāts lauks
profile.validation.lastname=Uzvārds ir obligāts lauks
profile.validation.phone=Tālruņa numurs ir obligāts lauks
profile.validation.street=Iela ir obligāts lauks
profile.validation.housenr=Mājas numurs ir obligāts lauks
profile.validation.postcode=Pasta indekss ir obligāts lauks
profile.validation.city=Pilsēta ir obligāts lauks
profile.validation.email.required=E-pasta adrese ir obligāts lauks
profile.validation.email.invalid=Lūdzu, ievadiet derīgu e-pasta adresi
profile.validation.company.required=Nepieciešams uzņēmums
profile.validation.street.required=Nepieciešama iela
profile.validation.housenr.required=Nepieciešams mājas numurs
profile.validation.postcode.required=Nepieciešams pasta indekss
profile.validation.city.required=Nepieciešama pilsēta
profile.validation.firstname.required=Nepieciešams vārds
profile.validation.lastname.required=Nepieciešams uzvārds
profile.validation.phone.required=Nepieciešams tālruņa numurs
# Buttons
button.save=Saglabāt profila izmaiņas
button.savechanges=Saglabāt
button.clear=Notīrīt
button.preview=Priekšskatījums
button.savetemplate=Saglabāt veidni
button.changepassword=Mainīt paroli
button.deleteaccount=Dzēst kontu
button.add=Jauns
button.edit=Rediģēt
button.delete=Dzēst
button.cancel=Atcelt
button.close=Aizvērt
button.download=Lejupielādēt
button.back=Atpakaļ
# Common
common.name=Nosaukums
common.yes=
common.no=
common.total=Kopā
common.price=Cena
common.service=Pakalpojums
common.customer=Klients
common.actions=Darbības
common.loading=Ielādējas...
common.error=Kļūda
common.success=Veiksmīgi
common.required=Obligāts lauks
# Validation
validation.required=Lauks ir obligāts
validation.email=Nederīga e-pasta adrese
validation.error=Validācijas kļūda
# Notifications
notification.saved=Profils saglabāts
notification.error=Kļūda saglabājot
notification.languagechanged=Valoda nomainīta
# Login
login.title=Pieteikties
login.username=Lietotājvārds
login.password=Parole
login.login=Pieteikties
login.forgotpassword=Aizmirsi paroli?
login.rememberme=Atcerēties mani
login.register=Reģistrēties
login.2fa.helper=6 ciparu kods
login.2fa.sent=Kods nosūtīts pa e-pastu
login.2fa.no.credentials=Nav pieteikšanās datu
login.2fa.invalid.code=Nederīgs kods
login.2fa.wrong.code=Nepareizs kods
# Error Messages
error.loading=Ielādes kļūda
error.saving=Saglabāšanas kļūda
error.validation=Validācijas kļūda
# Page Titles
page.title.welcome=VotianLT - Laipni lūdzam
page.title.login=VotianLT - Pieteikšanās
# Start Page
start.title=VotianLT - Jūsu digitālais transporta partneris
start.button.login=Pieteikties
start.button.register=Reģistrēties
start.button.createorder=Izveidot uzdevumu
start.button.notifications=Paziņojumi
start.button.nonotifications=Nav jaunu paziņojumu
start.hero.description=Pašnodarbinātajiem un mazajiem transporta uzņēmumiem pilnībā digitāls un viss vienā. Koncentrējieties uz savu biznesu, mēs parūpēsimies par birokrātiju.
start.system.title=Sistēma
start.system.intro=Pašnodarbinātajiem un mazajiem transporta uzņēmumiem ir ārkārtīgi svarīgi koncentrēties galvenokārt uz savu pamatdarbību: klientu piesaisti un preču piegādi no punkta A uz punktu B.
start.feature.setup.title=Iestatīšanas asistents
start.feature.setup.desc=Izmantojiet iestatīšanas asistentu, lai aizpildītu savu lietotāja profilu.
start.feature.customers.title=Klientu un uzdevumu pārvaldība
start.feature.customers.desc=Ar klientu un uzdevumu pārvaldību jums vienmēr ir visas kontaktinformācijas un uzdevumu detaļas acu priekšā.
start.feature.jobs.title=Uzdevumu izveide
start.feature.jobs.desc=Izveidojiet uzdevumus sistēmā tikai ar dažiem klikšķiem un noteikiet, kurš darbinieks veic kādu transporta uzdevumu.
start.app.title=Lietotne
start.app.description=Katru uzdevumu var pildīt pēc izvēles caur votianLT lietotni pilnīgi bez "birokrātijas". Visa svarīgā uzdevuma informācija nonāk tieši vadītāja viedtālrunī.
start.imprint.title=Impressum
start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Tālrunis: +49 40 18 123 771 0
start.imprint.email=E-pasts: ahoi@assecutor.de
start.cta.text=Reģistrējieties jau šodien un izmantojiet bezmaksas izmēģinājuma mēnesi, lai rūpīgi pārbaudītu sistēmu!
start.slogan=Vadīt savu biznesu gudri … ar votianLT!
start.version=Versija
# Register
register.title=Reģistrācija
register.subtitle=Izveidojiet savu VotianLT kontu
register.email=E-pasta adrese
register.password=Parole
register.password.placeholder=Vismaz 6 rakstzīmes
register.password.confirm=Apstipriniet paroli
register.password.confirm.placeholder=Ievadiet paroli vēlreiz
register.firstname=Vārds
register.lastname=Uzvārds
register.phone=Tālruņa numurs
register.company=Uzņēmums
register.street=Iela
register.housenr=Mājas numurs
register.postcode=Pasta indekss
register.city=Pilsēta
register.button.submit=Reģistrēties
register.notification.success=Reģistrācija veiksmīga. Lūdzu, pieteikties.
register.notification.failed=Reģistrācijas kļūda: {0}
# CTA Button
cta.freetest=Izmēģiniet bez maksas

View File

@@ -0,0 +1,188 @@
# Navigation and Main Layout
nav.jobs=Zadania
nav.job.create=Utwórz zadanie
nav.customers=Klienci
nav.appusers=Użytkownicy aplikacji
nav.statistics=Statystyki
nav.invoices=Faktury
nav.messages=Wiadomości
nav.profile=Mój profil
nav.myinvoices=Moje faktury
nav.imprint=Impressum
nav.management=Zarządzanie
nav.users=Użytkownicy
nav.showprofile=Pokaż profil
nav.settings=Ustawienia
nav.logout=Wyloguj się
# Profile View
profile.title=Edytuj profil
profile.language=Język
profile.company=Firma
profile.companyadd=Dodatek do firmy
profile.firstname=Imię
profile.lastname=Nazwisko
profile.phone=Numer telefonu
profile.fax=Faks
profile.mobile=Telefon komórkowy
profile.email=Adres e-mail (Logowanie)*
profile.street=Ulica
profile.housenr=Nr domu
profile.addressadd=Dodatek do adresu
profile.postcode=Kod pocztowy
profile.city=Miasto
profile.diffinvoice=Inny adres rozliczeniowy
profile.basicdata=Dane podstawowe
profile.map=Mapa
profile.invoicecreation=Tworzenie faktury
profile.settings=Ustawienia
profile.account=Konto
profile.security=Bezpieczeństwo
profile.services=Katalog usług
profile.saved=Profil zapisany
profile.save.error=Błąd podczas zapisywania: {0}
profile.validation.required.fill=Wypełnij wszystkie wymagane pola poprawnie
# Profile Settings
settings.digitalprocessing=Cyfrowe przetwarzanie przez aplikację
settings.digitalprocessinginfo=Umożliwia cyfrowe przetwarzanie zadań za pośrednictwem aplikacji mobilnej
settings.locationtracking=Lokalizowanie użytkowników aplikacji
settings.locationtrackinginfo=Umożliwia lokalizowanie użytkowników aplikacji podczas wykonywania zadań
settings.twofactor=Uwierzytelnianie dwuskładnikowe
settings.twofactorinfo=Po włączeniu przy każdym logowaniu wysyłany jest kod e-mailem
# Profile Billing
profile.billing.enabled=Fakturowanie przez votianLT
# Profile Validation
profile.validation.company=Firma jest polem wymaganym
profile.validation.firstname=Imię jest polem wymaganym
profile.validation.lastname=Nazwisko jest polem wymaganym
profile.validation.phone=Numer telefonu jest polem wymaganym
profile.validation.street=Ulica jest polem wymaganym
profile.validation.housenr=Numer domu jest polem wymaganym
profile.validation.postcode=Kod pocztowy jest polem wymaganym
profile.validation.city=Miasto jest polem wymaganym
profile.validation.email.required=Adres e-mail jest polem wymaganym
profile.validation.email.invalid=Podaj prawidłowy adres e-mail
profile.validation.company.required=Firma jest wymagana
profile.validation.street.required=Ulica jest wymagana
profile.validation.housenr.required=Numer domu jest wymagany
profile.validation.postcode.required=Kod pocztowy jest wymagany
profile.validation.city.required=Miasto jest wymagane
profile.validation.firstname.required=Imię jest wymagane
profile.validation.lastname.required=Nazwisko jest wymagane
profile.validation.phone.required=Numer telefonu jest wymagany
# Buttons
button.save=Zapisz zmiany w profilu
button.savechanges=Zapisz
button.clear=Wyczyść
button.preview=Podgląd
button.savetemplate=Zapisz szablon
button.changepassword=Zmień hasło
button.deleteaccount=Usuń konto
button.add=Nowy
button.edit=Edytuj
button.delete=Usuń
button.cancel=Anuluj
button.close=Zamknij
button.download=Pobierz
button.back=Wstecz
# Common
common.name=Nazwa
common.yes=Tak
common.no=Nie
common.total=Suma
common.price=Cena
common.service=Usługa
common.customer=Klient
common.actions=Działania
common.loading=Ładowanie...
common.error=Błąd
common.success=Sukces
common.required=Pole wymagane
# Validation
validation.required=Pole jest wymagane
validation.email=Nieprawidłowy adres e-mail
validation.error=Błąd walidacji
# Notifications
notification.saved=Profil zapisany
notification.error=Błąd podczas zapisywania
notification.languagechanged=Język zmieniony
# Login
login.title=Zaloguj się
login.username=Nazwa użytkownika
login.password=Hasło
login.login=Zaloguj się
login.forgotpassword=Nie pamiętasz hasła?
login.rememberme=Zapamiętaj mnie
login.register=Zarejestruj się
login.2fa.helper=6-cyfrowy kod
login.2fa.sent=Kod został wysłany e-mailem
login.2fa.no.credentials=Brak danych logowania
login.2fa.invalid.code=Nieprawidłowy kod
login.2fa.wrong.code=Zły kod
# Error Messages
error.loading=Błąd ładowania
error.saving=Błąd zapisywania
error.validation=Błąd walidacji
# Page Titles
page.title.welcome=VotianLT - Witamy
page.title.login=VotianLT - Logowanie
# Start Page
start.title=VotianLT - Twój cyfrowy partner transportowy
start.button.login=Zaloguj się
start.button.register=Zarejestruj się
start.button.createorder=Utwórz zadanie
start.button.notifications=Powiadomienia
start.button.nonotifications=Brak nowych powiadomień
start.hero.description=Dla samozatrudnionych i małych przedsiębiorstw w branży transportowej - w pełni cyfrowe i kompleksowe. Skoncentruj się na swoim biznesie, my zajmiemy się dokumentacją.
start.system.title=System
start.system.intro=Dla samozatrudnionych i małych przedsiębiorstw w branży transportowej kluczowe jest skupienie się przede wszystkim na ich podstawowej działalności: pozyskiwaniu klientów i dostarczaniu towarów z punktu A do B.
start.feature.setup.title=Asystent konfiguracji
start.feature.setup.desc=Za pomocą asystenta konfiguracji masz możliwość uzupełnienia swojego profilu użytkownika.
start.feature.customers.title=Zarządzanie klientami i zadaniami
start.feature.customers.desc=Dzięki zarządzaniu klientami i zadaniami masz wszystkie dane kontaktowe i szczegóły zadań zawsze pod kontrolą.
start.feature.jobs.title=Tworzenie zadań
start.feature.jobs.desc=Twórz zadania w systemie za pomocą kilku kliknięć i określ, który pracownik powinien wykonać które zadanie transportowe.
start.app.title=Aplikacja
start.app.description=Każde zadanie może być opcjonalnie realizowane za pośrednictwem aplikacji votianLT - całkowicie bez "papierkowej roboty". Wszystkie istotne informacje o zadaniu trafiają bezpośrednio na smartfon kierowcy.
start.imprint.title=Stopka
start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Telefon: +49 40 18 123 771 0
start.imprint.email=E-Mail: ahoi@assecutor.de
start.cta.text=Zarejestruj się już dziś i skorzystaj z bezpłatnego miesiąca próbnego, aby dokładnie przetestować system!
start.slogan=Prowadź swój biznes inteligentnie … z votianLT!
start.version=Wersja
# Register
register.title=Rejestracja
register.subtitle=Utwórz swoje konto VotianLT
register.email=Adres e-mail
register.password=Hasło
register.password.placeholder=Co najmniej 6 znaków
register.password.confirm=Potwierdź hasło
register.password.confirm.placeholder=Wprowadź hasło ponownie
register.firstname=Imię
register.lastname=Nazwisko
register.phone=Numer telefonu
register.company=Firma
register.street=Ulica
register.housenr=Nr domu
register.postcode=Kod pocztowy
register.city=Miasto
register.button.submit=Zarejestruj się
register.notification.success=Rejestracja zakończona sukcesem. Zaloguj się.
register.notification.failed=Rejestracja nie powiodła się: {0}
# CTA Button
cta.freetest=Wypróbuj teraz za darmo

View File

@@ -0,0 +1,188 @@
# Navigation and Main Layout
nav.jobs=Задачи
nav.job.create=Создать задачу
nav.customers=Клиенты
nav.appusers=Пользователи приложения
nav.statistics=Статистика
nav.invoices=Счета
nav.messages=Сообщения
nav.profile=Мой профиль
nav.myinvoices=Мои счета
nav.imprint=Выходные данные
nav.management=Управление
nav.users=Пользователи
nav.showprofile=Показать профиль
nav.settings=Настройки
nav.logout=Выйти
# Profile View
profile.title=Редактировать профиль
profile.language=Язык
profile.company=Компания
profile.companyadd=Дополнение к компании
profile.firstname=Имя
profile.lastname=Фамилия
profile.phone=Номер телефона
profile.fax=Факс
profile.mobile=Мобильный телефон
profile.email=Адрес электронной почты (Вход)*
profile.street=Улица
profile.housenr=Номер дома
profile.addressadd=Дополнение к адресу
profile.postcode=Почтовый индекс
profile.city=Город
profile.diffinvoice=Другой адрес для выставления счетов
profile.basicdata=Основные данные
profile.map=Карта
profile.invoicecreation=Создание счета
profile.settings=Настройки
profile.account=Аккаунт
profile.security=Безопасность
profile.services=Каталог услуг
profile.saved=Профиль сохранен
profile.save.error=Ошибка сохранения: {0}
profile.validation.required.fill=Пожалуйста, правильно заполните все обязательные поля
# Profile Settings
settings.digitalprocessing=Цифровая обработка через приложение
settings.digitalprocessinginfo=Включает цифровую обработку задач через мобильное приложение
settings.locationtracking=Отслеживание местоположения пользователей приложения
settings.locationtrackinginfo=Позволяет отслеживать местоположение пользователей приложения во время выполнения задач
settings.twofactor=Двухфакторная аутентификация
settings.twofactorinfo=При активации при каждом входе отправляется код по электронной почте
# Profile Billing
profile.billing.enabled=Выставление счетов через votianLT
# Profile Validation
profile.validation.company=Компания - обязательное поле
profile.validation.firstname=Имя - обязательное поле
profile.validation.lastname=Фамилия - обязательное поле
profile.validation.phone=Номер телефона - обязательное поле
profile.validation.street=Улица - обязательное поле
profile.validation.housenr=Номер дома - обязательное поле
profile.validation.postcode=Почтовый индекс - обязательное поле
profile.validation.city=Город - обязательное поле
profile.validation.email.required=Адрес электронной почты - обязательное поле
profile.validation.email.invalid=Пожалуйста, введите действительный адрес электронной почты
profile.validation.company.required=Требуется компания
profile.validation.street.required=Требуется улица
profile.validation.housenr.required=Требуется номер дома
profile.validation.postcode.required=Требуется почтовый индекс
profile.validation.city.required=Требуется город
profile.validation.firstname.required=Требуется имя
profile.validation.lastname.required=Требуется фамилия
profile.validation.phone.required=Требуется номер телефона
# Buttons
button.save=Сохранить изменения профиля
button.savechanges=Сохранить
button.clear=Очистить
button.preview=Предпросмотр
button.savetemplate=Сохранить шаблон
button.changepassword=Изменить пароль
button.deleteaccount=Удалить аккаунт
button.add=Новый
button.edit=Редактировать
button.delete=Удалить
button.cancel=Отмена
button.close=Закрыть
button.download=Скачать
button.back=Назад
# Common
common.name=Название
common.yes=Да
common.no=Нет
common.total=Итого
common.price=Цена
common.service=Услуга
common.customer=Клиент
common.actions=Действия
common.loading=Загрузка...
common.error=Ошибка
common.success=Успех
common.required=Обязательное поле
# Validation
validation.required=Поле обязательно для заполнения
validation.email=Недействительный адрес электронной почты
validation.error=Ошибка валидации
# Notifications
notification.saved=Профиль сохранен
notification.error=Ошибка сохранения
notification.languagechanged=Язык изменен
# Login
login.title=Войти
login.username=Имя пользователя
login.password=Пароль
login.login=Войти
login.forgotpassword=Забыли пароль?
login.rememberme=Запомнить меня
login.register=Зарегистрироваться
login.2fa.helper=6-значный код
login.2fa.sent=Код отправлен по электронной почте
login.2fa.no.credentials=Нет учетных данных
login.2fa.invalid.code=Недействительный код
login.2fa.wrong.code=Неправильный код
# Error Messages
error.loading=Ошибка загрузки
error.saving=Ошибка сохранения
error.validation=Ошибка валидации
# Page Titles
page.title.welcome=VotianLT - Добро пожаловать
page.title.login=VotianLT - Вход
# Start Page
start.title=VotianLT - Ваш цифровой транспортный партнер
start.button.login=Войти
start.button.register=Зарегистрироваться
start.button.createorder=Создать задачу
start.button.notifications=Уведомления
start.button.nonotifications=Нет новых уведомлений
start.hero.description=Для самозанятых и малых предприятий в транспортной отрасли — полностью цифровое и комплексное решение. Сосредоточьтесь на своем бизнесе, а о документах мы позаботимся.
start.system.title=Система
start.system.intro=Для самозанятых и малых предприятий в транспортной отрасли крайне важно сосредоточиться прежде всего на своей основной деятельности: привлечении клиентов и доставке товаров из пункта А в пункт Б.
start.feature.setup.title=Помощник настройки
start.feature.setup.desc=Используйте помощник настройки для заполнения профиля пользователя.
start.feature.customers.title=Управление клиентами и задачами
start.feature.customers.desc=С управлением клиентами и задачами вы всегда имеете под рукой все контактные данные и детали задач.
start.feature.jobs.title=Создание задач
start.feature.jobs.desc=Создавайте задачи в системе всего за несколько кликов и определяйте, какой сотрудник должен выполнить какую транспортную задачу.
start.app.title=Приложение
start.app.description=Каждая задача может быть выполнена через приложение votianLT — полностью без "бумажной работы". Вся важная информация о задаче поступает прямо на смартфон водителя.
start.imprint.title=Выходные данные
start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Телефон: +49 40 18 123 771 0
start.imprint.email=Эл. почта: ahoi@assecutor.de
start.cta.text=Зарегистрируйтесь уже сегодня и воспользуйтесь бесплатным пробным месяцем, чтобы тщательно протестировать систему!
start.slogan=Умно управляйте своим бизнесом … с votianLT!
start.version=Версия
# Register
register.title=Регистрация
register.subtitle=Создайте свою учетную запись VotianLT
register.email=Адрес электронной почты
register.password=Пароль
register.password.placeholder=Минимум 6 символов
register.password.confirm=Подтвердите пароль
register.password.confirm.placeholder=Введите пароль еще раз
register.firstname=Имя
register.lastname=Фамилия
register.phone=Номер телефона
register.company=Компания
register.street=Улица
register.housenr=Номер дома
register.postcode=Почтовый индекс
register.city=Город
register.button.submit=Зарегистрироваться
register.notification.success=Регистрация прошла успешно. Пожалуйста, войдите.
register.notification.failed=Ошибка регистрации: {0}
# CTA Button
cta.freetest=Попробуйте бесплатно

View File

@@ -0,0 +1,188 @@
# Navigation and Main Layout
nav.jobs=Görevler
nav.job.create=Görev Oluştur
nav.customers=Müşteriler
nav.appusers=App Kullanıcıları
nav.statistics=İstatistikler
nav.invoices=Faturalar
nav.messages=Mesajlar
nav.profile=Profilim
nav.myinvoices=Faturalarım
nav.imprint=Künye
nav.management=Yönetim
nav.users=Kullanıcılar
nav.showprofile=Profili Göster
nav.settings=Ayarlar
nav.logout=Çıkış Yap
# Profile View
profile.title=Profili Düzenle
profile.language=Dil
profile.company=Şirket
profile.companyadd=Şirket Eki
profile.firstname=Ad
profile.lastname=Soyad
profile.phone=Telefon Numarası
profile.fax=Faks
profile.mobile=Cep Telefonu
profile.email=E-Posta Adresi (Giriş)*
profile.street=Sokak
profile.housenr=Ev No
profile.addressadd=Adres Eki
profile.postcode=Posta Kodu
profile.city=Şehir
profile.diffinvoice=Farklı Fatura Adresi
profile.basicdata=Temel Veriler
profile.map=Harita
profile.invoicecreation=Fatura Oluşturma
profile.settings=Ayarlar
profile.account=Hesap
profile.security=Güvenlik
profile.services=Hizmet Kataloğu
profile.saved=Profil kaydedildi
profile.save.error=Kaydetme hatası: {0}
profile.validation.required.fill=Lütfen tüm zorunlu alanları doğru şekilde doldurun
# Profile Settings
settings.digitalprocessing=App ile Dijital İşlem
settings.digitalprocessinginfo=Mobil uygulama üzerinden dijital görev işlemeyi etkinleştirir
settings.locationtracking=App kullanıcılarını konumlandırma
settings.locationtrackinginfo=Görev yürütme sırasında App kullanıcılarının konumlandırılmasını sağlar
settings.twofactor=İki Faktörlü Kimlik Doğrulama
settings.twofactorinfo=Etkinleştirildiğinde, her girişte e-posta ile bir kod gönderilir
# Profile Billing
profile.billing.enabled=votianLT üzerinden faturalandırma
# Profile Validation
profile.validation.company=Şirket zorunlu bir alandır
profile.validation.firstname=Ad zorunlu bir alandır
profile.validation.lastname=Soyad zorunlu bir alandır
profile.validation.phone=Telefon numarası zorunlu bir alandır
profile.validation.street=Sokak zorunlu bir alandır
profile.validation.housenr=Ev numarası zorunlu bir alandır
profile.validation.postcode=Posta kodu zorunlu bir alandır
profile.validation.city=Şehir zorunlu bir alandır
profile.validation.email.required=E-posta adresi zorunlu bir alandır
profile.validation.email.invalid=Lütfen geçerli bir e-posta adresi girin
profile.validation.company.required=Şirket gereklidir
profile.validation.street.required=Sokak gereklidir
profile.validation.housenr.required=Ev numarası gereklidir
profile.validation.postcode.required=Posta kodu gereklidir
profile.validation.city.required=Şehir gereklidir
profile.validation.firstname.required=Ad gereklidir
profile.validation.lastname.required=Soyad gereklidir
profile.validation.phone.required=Telefon numarası gereklidir
# Buttons
button.save=Profil değişikliklerini kaydet
button.savechanges=Kaydet
button.clear=Temizle
button.preview=Önizleme
button.savetemplate=Şablonu kaydet
button.changepassword=Şifreyi değiştir
button.deleteaccount=Hesabı sil
button.add=Yeni
button.edit=Düzenle
button.delete=Sil
button.cancel=İptal
button.close=Kapat
button.download=İndir
button.back=Geri
# Common
common.name=Ad
common.yes=Evet
common.no=Hayır
common.total=Toplam
common.price=Fiyat
common.service=Hizmet
common.customer=Müşteri
common.actions=İşlemler
common.loading=Yükleniyor...
common.error=Hata
common.success=Başarı
common.required=Zorunlu alan
# Validation
validation.required=Alan zorunludur
validation.email=Geçersiz e-posta adresi
validation.error=Doğrulama hatası
# Notifications
notification.saved=Profil kaydedildi
notification.error=Kaydetme hatası
notification.languagechanged=Dil değiştirildi
# Login
login.title=Giriş Yap
login.username=Kullanıcı adı
login.password=Şifre
login.login=Giriş Yap
login.forgotpassword=Şifrenizi mi unuttunuz?
login.rememberme=Beni hatırla
login.register=Kaydol
login.2fa.helper=6 haneli kod
login.2fa.sent=Kod e-posta ile gönderildi
login.2fa.no.credentials=Kimlik bilgileri yok
login.2fa.invalid.code=Geçersiz kod
login.2fa.wrong.code=Yanlış kod
# Error Messages
error.loading=Yükleme hatası
error.saving=Kaydetme hatası
error.validation=Doğrulama hatası
# Page Titles
page.title.welcome=VotianLT - Hoş Geldiniz
page.title.login=VotianLT - Giriş Yap
# Start Page
start.title=VotianLT - Dijital Taşıma Ortağınız
start.button.login=Giriş Yap
start.button.register=Kaydol
start.button.createorder=Görev Oluştur
start.button.notifications=Bildirimler
start.button.nonotifications=Yeni bildirim yok
start.hero.description=Nakliyecilik sektöründe tek çalışanlar ve küçük işletmeler için - tamamen dijital ve hepsi bir arada. Siz işinize odaklanın, kâğıt işleriyle biz ilgilenelim.
start.system.title=Sistem
start.system.intro=Nakliyecilik sektöründe tek çalışanlar ve küçük işletmeler için, öncelikle temel işlerine odaklanmaları çok önemlidir: müşteri kazanmak ve malları A'dan B'ye teslim etmek.
start.feature.setup.title=Kurulum Asistanı
start.feature.setup.desc=Kurulum asistanını kullanarak kullanıcı profilinizi tamamlayabilirsiniz.
start.feature.customers.title=Müşteri ve Görev Yönetimi
start.feature.customers.desc=Müşteri ve görev yönetimi ile tüm iletişim bilgilerini ve görev detaylarını her zaman gözünüzün önünde bulundurun.
start.feature.jobs.title=Görev Oluşturma
start.feature.jobs.desc=Sadece birkaç tıklama ile sistemde görevler oluşturun ve hangi çalışanın hangi taşıma görevini işlemesi gerektiğini belirleyin.
start.app.title=Uygulama
start.app.description=Her görev, votianLT uygulaması üzerinden isteğe bağlı olarak işlenebilir - tamamen "evrak işi" olmadan. Tüm ilgili görev bilgileri doğrudan sürücünün akıllı telefonuna gider.
start.imprint.title=Künye
start.imprint.company=Assecutor Data Service GmbH
start.imprint.address=Ottensener Str. 8, 22525 Hamburg
start.imprint.phone=Telefon: +49 40 18 123 771 0
start.imprint.email=E-Posta: ahoi@assecutor.de
start.cta.text=Bugün kaydolun ve sistemi derinlemesine test etmek için ücretsiz deneme ayından yararlanın!
start.slogan=İşletmenizi akıllıca yönetin … votianLT ile!
start.version=Sürüm
# Register
register.title=Kayıt
register.subtitle=VotianLT hesabınızı oluşturun
register.email=E-Posta Adresi
register.password=Şifre
register.password.placeholder=En az 6 karakter
register.password.confirm=Şifreyi Onayla
register.password.confirm.placeholder=Şifreyi tekrar girin
register.firstname=Ad
register.lastname=Soyad
register.phone=Telefon Numarası
register.company=Şirket
register.street=Sokak
register.housenr=Ev No
register.postcode=Posta Kodu
register.city=Şehir
register.button.submit=Kaydol
register.notification.success=Kayıt başarılı. Lütfen giriş yapın.
register.notification.failed=Kayıt başarısız: {0}
# CTA Button
cta.freetest=Şimdi ücretsiz dene