style: auto-format codebase with Prettier

Applied formatting to 1487+ files using pnpm format:write
  - TypeScript/JavaScript files
  - Svelte components
  - Astro pages
  - JSON configs
  - Markdown docs

  13 files still need manual review (Astro JSX comments)
This commit is contained in:
Wuesteon 2025-11-27 18:33:16 +01:00
parent 0241f5554c
commit d36b321d9d
3952 changed files with 661498 additions and 739751 deletions

View file

@ -1,21 +1,21 @@
{
"name": "@manacore/shared-i18n",
"version": "1.0.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./languages": "./src/languages.ts",
"./utils": "./src/utils.ts",
"./translations/common": "./src/translations/common/index.ts"
},
"scripts": {
"type-check": "tsc --noEmit"
},
"devDependencies": {
"svelte": "^5.43.14",
"typescript": "^5.7.3"
}
"name": "@manacore/shared-i18n",
"version": "1.0.0",
"private": true,
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./languages": "./src/languages.ts",
"./utils": "./src/utils.ts",
"./translations/common": "./src/translations/common/index.ts"
},
"scripts": {
"type-check": "tsc --noEmit"
},
"devDependencies": {
"svelte": "^5.43.14",
"typescript": "^5.7.3"
}
}

View file

@ -20,7 +20,7 @@
supportedLocales,
onLocaleChange,
isDark = false,
primaryColor = '#6366f1'
primaryColor = '#6366f1',
}: Props = $props();
let isOpen = $state(false);
@ -32,13 +32,13 @@
return {
flag: info.emoji,
name: info.nativeName,
code: code.toUpperCase().substring(0, 2)
code: code.toUpperCase().substring(0, 2),
};
}
return {
flag: '🌐',
name: code,
code: code.toUpperCase().substring(0, 2)
code: code.toUpperCase().substring(0, 2),
};
}

View file

@ -7,58 +7,58 @@
// Language definitions
export {
type LanguageCode,
type LanguageInfo,
LANGUAGES,
getLanguageCodes,
getLanguageInfo,
isLanguageSupported,
isRTL,
getLanguageDisplayName,
LOCALE_GROUPS,
getLanguagesByGroup,
type LanguageCode,
type LanguageInfo,
LANGUAGES,
getLanguageCodes,
getLanguageInfo,
isLanguageSupported,
isRTL,
getLanguageDisplayName,
LOCALE_GROUPS,
getLanguagesByGroup,
} from './languages';
// Utilities
export {
detectBrowserLocale,
getStoredLocale,
storeLocale,
getInitialLocale,
normalizeLocale,
getBaseLanguage,
matchesLanguage,
findBestMatch,
formatLocalizedNumber,
formatLocalizedDate,
formatRelativeTime,
getPluralCategory,
interpolate,
detectBrowserLocale,
getStoredLocale,
storeLocale,
getInitialLocale,
normalizeLocale,
getBaseLanguage,
matchesLanguage,
findBestMatch,
formatLocalizedNumber,
formatLocalizedDate,
formatRelativeTime,
getPluralCategory,
interpolate,
} from './utils';
// Common translations
export {
en as commonTranslationsEn,
de as commonTranslationsDe,
type CommonTranslations,
getCommonTranslations,
mergeWithCommon,
en as commonTranslationsEn,
de as commonTranslationsDe,
type CommonTranslations,
getCommonTranslations,
mergeWithCommon,
} from './translations/common';
// Auth translations
export {
en as authTranslationsEn,
de as authTranslationsDe,
it as authTranslationsIt,
fr as authTranslationsFr,
es as authTranslationsEs,
type AuthTranslations,
type AuthLocale,
authTranslations,
getAuthTranslations,
getLoginTranslations,
getRegisterTranslations,
getForgotPasswordTranslations,
en as authTranslationsEn,
de as authTranslationsDe,
it as authTranslationsIt,
fr as authTranslationsFr,
es as authTranslationsEs,
type AuthTranslations,
type AuthLocale,
authTranslations,
getAuthTranslations,
getLoginTranslations,
getRegisterTranslations,
getForgotPasswordTranslations,
} from './translations/auth';
// Components

View file

@ -6,154 +6,220 @@
* Supported language codes
*/
export type LanguageCode =
| 'en' | 'de' | 'fr' | 'es' | 'it' | 'pt' | 'nl' | 'pl' | 'ru' | 'ja'
| 'ko' | 'zh' | 'ar' | 'hi' | 'bn' | 'ur' | 'id' | 'fa' | 'vi' | 'th'
| 'tr' | 'uk' | 'cs' | 'da' | 'fi' | 'sv' | 'nb' | 'el' | 'hu' | 'ro'
| 'bg' | 'hr' | 'sk' | 'sl' | 'sr' | 'lt' | 'lv' | 'et' | 'mt' | 'ga'
| 'tl' | 'ms' | 'he' | 'af' | 'pt-BR' | 'es-MX';
| 'en'
| 'de'
| 'fr'
| 'es'
| 'it'
| 'pt'
| 'nl'
| 'pl'
| 'ru'
| 'ja'
| 'ko'
| 'zh'
| 'ar'
| 'hi'
| 'bn'
| 'ur'
| 'id'
| 'fa'
| 'vi'
| 'th'
| 'tr'
| 'uk'
| 'cs'
| 'da'
| 'fi'
| 'sv'
| 'nb'
| 'el'
| 'hu'
| 'ro'
| 'bg'
| 'hr'
| 'sk'
| 'sl'
| 'sr'
| 'lt'
| 'lv'
| 'et'
| 'mt'
| 'ga'
| 'tl'
| 'ms'
| 'he'
| 'af'
| 'pt-BR'
| 'es-MX';
/**
* Language metadata
*/
export interface LanguageInfo {
/** Native name of the language */
nativeName: string;
/** English name of the language */
englishName: string;
/** Flag emoji */
emoji: string;
/** RTL language */
rtl?: boolean;
/** Native name of the language */
nativeName: string;
/** English name of the language */
englishName: string;
/** Flag emoji */
emoji: string;
/** RTL language */
rtl?: boolean;
}
/**
* Complete language definitions
*/
export const LANGUAGES: Record<LanguageCode, LanguageInfo> = {
// Major languages
en: { nativeName: 'English', englishName: 'English', emoji: '🇬🇧' },
de: { nativeName: 'Deutsch', englishName: 'German', emoji: '🇩🇪' },
fr: { nativeName: 'Français', englishName: 'French', emoji: '🇫🇷' },
es: { nativeName: 'Español', englishName: 'Spanish', emoji: '🇪🇸' },
it: { nativeName: 'Italiano', englishName: 'Italian', emoji: '🇮🇹' },
pt: { nativeName: 'Português', englishName: 'Portuguese', emoji: '🇵🇹' },
nl: { nativeName: 'Nederlands', englishName: 'Dutch', emoji: '🇳🇱' },
pl: { nativeName: 'Polski', englishName: 'Polish', emoji: '🇵🇱' },
ru: { nativeName: 'Русский', englishName: 'Russian', emoji: '🇷🇺' },
// Major languages
en: { nativeName: 'English', englishName: 'English', emoji: '🇬🇧' },
de: { nativeName: 'Deutsch', englishName: 'German', emoji: '🇩🇪' },
fr: { nativeName: 'Français', englishName: 'French', emoji: '🇫🇷' },
es: { nativeName: 'Español', englishName: 'Spanish', emoji: '🇪🇸' },
it: { nativeName: 'Italiano', englishName: 'Italian', emoji: '🇮🇹' },
pt: { nativeName: 'Português', englishName: 'Portuguese', emoji: '🇵🇹' },
nl: { nativeName: 'Nederlands', englishName: 'Dutch', emoji: '🇳🇱' },
pl: { nativeName: 'Polski', englishName: 'Polish', emoji: '🇵🇱' },
ru: { nativeName: 'Русский', englishName: 'Russian', emoji: '🇷🇺' },
// Asian languages
ja: { nativeName: '日本語', englishName: 'Japanese', emoji: '🇯🇵' },
ko: { nativeName: '한국어', englishName: 'Korean', emoji: '🇰🇷' },
zh: { nativeName: '中文', englishName: 'Chinese', emoji: '🇨🇳' },
vi: { nativeName: 'Tiếng Việt', englishName: 'Vietnamese', emoji: '🇻🇳' },
th: { nativeName: 'ไทย', englishName: 'Thai', emoji: '🇹🇭' },
id: { nativeName: 'Bahasa Indonesia', englishName: 'Indonesian', emoji: '🇮🇩' },
ms: { nativeName: 'Bahasa Melayu', englishName: 'Malay', emoji: '🇲🇾' },
tl: { nativeName: 'Filipino', englishName: 'Filipino', emoji: '🇵🇭' },
// Asian languages
ja: { nativeName: '日本語', englishName: 'Japanese', emoji: '🇯🇵' },
ko: { nativeName: '한국어', englishName: 'Korean', emoji: '🇰🇷' },
zh: { nativeName: '中文', englishName: 'Chinese', emoji: '🇨🇳' },
vi: { nativeName: 'Tiếng Việt', englishName: 'Vietnamese', emoji: '🇻🇳' },
th: { nativeName: 'ไทย', englishName: 'Thai', emoji: '🇹🇭' },
id: { nativeName: 'Bahasa Indonesia', englishName: 'Indonesian', emoji: '🇮🇩' },
ms: { nativeName: 'Bahasa Melayu', englishName: 'Malay', emoji: '🇲🇾' },
tl: { nativeName: 'Filipino', englishName: 'Filipino', emoji: '🇵🇭' },
// South Asian languages
hi: { nativeName: 'हिन्दी', englishName: 'Hindi', emoji: '🇮🇳' },
bn: { nativeName: 'বাংলা', englishName: 'Bengali', emoji: '🇧🇩' },
ur: { nativeName: 'اردو', englishName: 'Urdu', emoji: '🇵🇰', rtl: true },
// South Asian languages
hi: { nativeName: 'हिन्दी', englishName: 'Hindi', emoji: '🇮🇳' },
bn: { nativeName: 'বাংলা', englishName: 'Bengali', emoji: '🇧🇩' },
ur: { nativeName: 'اردو', englishName: 'Urdu', emoji: '🇵🇰', rtl: true },
// Middle Eastern languages
ar: { nativeName: 'العربية', englishName: 'Arabic', emoji: '🇦🇪', rtl: true },
fa: { nativeName: 'فارسی', englishName: 'Persian', emoji: '🇮🇷', rtl: true },
he: { nativeName: 'עברית', englishName: 'Hebrew', emoji: '🇮🇱', rtl: true },
tr: { nativeName: 'Türkçe', englishName: 'Turkish', emoji: '🇹🇷' },
// Middle Eastern languages
ar: { nativeName: 'العربية', englishName: 'Arabic', emoji: '🇦🇪', rtl: true },
fa: { nativeName: 'فارسی', englishName: 'Persian', emoji: '🇮🇷', rtl: true },
he: { nativeName: 'עברית', englishName: 'Hebrew', emoji: '🇮🇱', rtl: true },
tr: { nativeName: 'Türkçe', englishName: 'Turkish', emoji: '🇹🇷' },
// Nordic languages
sv: { nativeName: 'Svenska', englishName: 'Swedish', emoji: '🇸🇪' },
da: { nativeName: 'Dansk', englishName: 'Danish', emoji: '🇩🇰' },
fi: { nativeName: 'Suomi', englishName: 'Finnish', emoji: '🇫🇮' },
nb: { nativeName: 'Norsk', englishName: 'Norwegian', emoji: '🇳🇴' },
// Nordic languages
sv: { nativeName: 'Svenska', englishName: 'Swedish', emoji: '🇸🇪' },
da: { nativeName: 'Dansk', englishName: 'Danish', emoji: '🇩🇰' },
fi: { nativeName: 'Suomi', englishName: 'Finnish', emoji: '🇫🇮' },
nb: { nativeName: 'Norsk', englishName: 'Norwegian', emoji: '🇳🇴' },
// Eastern European languages
uk: { nativeName: 'Українська', englishName: 'Ukrainian', emoji: '🇺🇦' },
cs: { nativeName: 'Čeština', englishName: 'Czech', emoji: '🇨🇿' },
hu: { nativeName: 'Magyar', englishName: 'Hungarian', emoji: '🇭🇺' },
ro: { nativeName: 'Română', englishName: 'Romanian', emoji: '🇷🇴' },
bg: { nativeName: 'Български', englishName: 'Bulgarian', emoji: '🇧🇬' },
hr: { nativeName: 'Hrvatski', englishName: 'Croatian', emoji: '🇭🇷' },
sk: { nativeName: 'Slovenčina', englishName: 'Slovak', emoji: '🇸🇰' },
sl: { nativeName: 'Slovenščina', englishName: 'Slovenian', emoji: '🇸🇮' },
sr: { nativeName: 'Српски', englishName: 'Serbian', emoji: '🇷🇸' },
// Eastern European languages
uk: { nativeName: 'Українська', englishName: 'Ukrainian', emoji: '🇺🇦' },
cs: { nativeName: 'Čeština', englishName: 'Czech', emoji: '🇨🇿' },
hu: { nativeName: 'Magyar', englishName: 'Hungarian', emoji: '🇭🇺' },
ro: { nativeName: 'Română', englishName: 'Romanian', emoji: '🇷🇴' },
bg: { nativeName: 'Български', englishName: 'Bulgarian', emoji: '🇧🇬' },
hr: { nativeName: 'Hrvatski', englishName: 'Croatian', emoji: '🇭🇷' },
sk: { nativeName: 'Slovenčina', englishName: 'Slovak', emoji: '🇸🇰' },
sl: { nativeName: 'Slovenščina', englishName: 'Slovenian', emoji: '🇸🇮' },
sr: { nativeName: 'Српски', englishName: 'Serbian', emoji: '🇷🇸' },
// Baltic languages
lt: { nativeName: 'Lietuvių', englishName: 'Lithuanian', emoji: '🇱🇹' },
lv: { nativeName: 'Latviešu', englishName: 'Latvian', emoji: '🇱🇻' },
et: { nativeName: 'Eesti', englishName: 'Estonian', emoji: '🇪🇪' },
// Baltic languages
lt: { nativeName: 'Lietuvių', englishName: 'Lithuanian', emoji: '🇱🇹' },
lv: { nativeName: 'Latviešu', englishName: 'Latvian', emoji: '🇱🇻' },
et: { nativeName: 'Eesti', englishName: 'Estonian', emoji: '🇪🇪' },
// Other European languages
el: { nativeName: 'Ελληνικά', englishName: 'Greek', emoji: '🇬🇷' },
mt: { nativeName: 'Malti', englishName: 'Maltese', emoji: '🇲🇹' },
ga: { nativeName: 'Gaeilge', englishName: 'Irish', emoji: '🇮🇪' },
// Other European languages
el: { nativeName: 'Ελληνικά', englishName: 'Greek', emoji: '🇬🇷' },
mt: { nativeName: 'Malti', englishName: 'Maltese', emoji: '🇲🇹' },
ga: { nativeName: 'Gaeilge', englishName: 'Irish', emoji: '🇮🇪' },
// African languages
af: { nativeName: 'Afrikaans', englishName: 'Afrikaans', emoji: '🇿🇦' },
// African languages
af: { nativeName: 'Afrikaans', englishName: 'Afrikaans', emoji: '🇿🇦' },
// Regional variants
'pt-BR': { nativeName: 'Português (Brasil)', englishName: 'Portuguese (Brazil)', emoji: '🇧🇷' },
'es-MX': { nativeName: 'Español (México)', englishName: 'Spanish (Mexico)', emoji: '🇲🇽' },
// Regional variants
'pt-BR': { nativeName: 'Português (Brasil)', englishName: 'Portuguese (Brazil)', emoji: '🇧🇷' },
'es-MX': { nativeName: 'Español (México)', englishName: 'Spanish (Mexico)', emoji: '🇲🇽' },
};
/**
* Get list of all language codes
*/
export function getLanguageCodes(): LanguageCode[] {
return Object.keys(LANGUAGES) as LanguageCode[];
return Object.keys(LANGUAGES) as LanguageCode[];
}
/**
* Get language info by code
*/
export function getLanguageInfo(code: string): LanguageInfo | undefined {
return LANGUAGES[code as LanguageCode];
return LANGUAGES[code as LanguageCode];
}
/**
* Check if a language code is supported
*/
export function isLanguageSupported(code: string): code is LanguageCode {
return code in LANGUAGES;
return code in LANGUAGES;
}
/**
* Check if a language is RTL
*/
export function isRTL(code: string): boolean {
const info = LANGUAGES[code as LanguageCode];
return info?.rtl === true;
const info = LANGUAGES[code as LanguageCode];
return info?.rtl === true;
}
/**
* Get display name for a language (native name with emoji)
*/
export function getLanguageDisplayName(code: string): string {
const info = LANGUAGES[code as LanguageCode];
if (!info) return code;
return `${info.emoji} ${info.nativeName}`;
const info = LANGUAGES[code as LanguageCode];
if (!info) return code;
return `${info.emoji} ${info.nativeName}`;
}
/**
* Common locale groups for filtering
*/
export const LOCALE_GROUPS = {
/** European Union official languages */
eu: ['en', 'de', 'fr', 'es', 'it', 'pt', 'nl', 'pl', 'cs', 'da', 'fi', 'sv', 'el', 'hu', 'ro', 'bg', 'hr', 'sk', 'sl', 'lt', 'lv', 'et', 'mt', 'ga'] as LanguageCode[],
/** Major world languages */
major: ['en', 'de', 'fr', 'es', 'it', 'pt', 'ru', 'ja', 'ko', 'zh', 'ar'] as LanguageCode[],
/** DACH region (German-speaking) */
dach: ['de'] as LanguageCode[],
/** Nordic countries */
nordic: ['sv', 'da', 'fi', 'nb'] as LanguageCode[],
/** RTL languages */
rtl: ['ar', 'fa', 'he', 'ur'] as LanguageCode[],
/** European Union official languages */
eu: [
'en',
'de',
'fr',
'es',
'it',
'pt',
'nl',
'pl',
'cs',
'da',
'fi',
'sv',
'el',
'hu',
'ro',
'bg',
'hr',
'sk',
'sl',
'lt',
'lv',
'et',
'mt',
'ga',
] as LanguageCode[],
/** Major world languages */
major: ['en', 'de', 'fr', 'es', 'it', 'pt', 'ru', 'ja', 'ko', 'zh', 'ar'] as LanguageCode[],
/** DACH region (German-speaking) */
dach: ['de'] as LanguageCode[],
/** Nordic countries */
nordic: ['sv', 'da', 'fi', 'nb'] as LanguageCode[],
/** RTL languages */
rtl: ['ar', 'fa', 'he', 'ur'] as LanguageCode[],
};
/**
* Get languages by group
*/
export function getLanguagesByGroup(group: keyof typeof LOCALE_GROUPS): LanguageCode[] {
return LOCALE_GROUPS[group];
return LOCALE_GROUPS[group];
}

View file

@ -1,59 +1,59 @@
{
"login": {
"title": "Anmelden",
"subtitle": "Melde dich mit deinem Mana-Konto an",
"emailPlaceholder": "E-Mail",
"passwordPlaceholder": "Passwort",
"rememberMe": "Angemeldet bleiben",
"forgotPassword": "Passwort vergessen?",
"signInButton": "Anmelden",
"signingIn": "Anmeldung...",
"success": "Erfolgreich!",
"orDivider": "oder",
"noAccount": "Noch kein Konto?",
"createAccount": "Jetzt erstellen",
"skipToForm": "Zum Anmeldeformular springen",
"showPassword": "Passwort anzeigen",
"hidePassword": "Passwort verbergen",
"emailRequired": "E-Mail ist erforderlich",
"emailInvalid": "Bitte gib eine gültige E-Mail-Adresse ein",
"passwordRequired": "Passwort ist erforderlich",
"signInFailed": "Anmeldung fehlgeschlagen",
"googleSignInFailed": "Google-Anmeldung fehlgeschlagen",
"signInSuccess": "Erfolgreich angemeldet. Weiterleitung...",
"googleSignInSuccess": "Erfolgreich mit Google angemeldet. Weiterleitung..."
},
"register": {
"title": "Konto erstellen",
"emailPlaceholder": "E-Mail",
"passwordPlaceholder": "Passwort",
"confirmPasswordPlaceholder": "Passwort bestätigen",
"passwordRequirements": "Das Passwort muss mindestens 8 Zeichen mit Kleinbuchstaben, Großbuchstaben, Zahl und Sonderzeichen enthalten.",
"createAccountButton": "Konto erstellen",
"creatingAccount": "Konto wird erstellt...",
"backToLogin": "Zurück zur Anmeldung",
"showPassword": "Passwort anzeigen",
"hidePassword": "Passwort verbergen",
"emailRequired": "E-Mail ist erforderlich",
"passwordRequired": "Passwort ist erforderlich",
"confirmPasswordRequired": "Bitte bestätige dein Passwort",
"passwordsDoNotMatch": "Passwörter stimmen nicht überein",
"passwordTooShort": "Passwort muss mindestens 8 Zeichen lang sein",
"passwordStrengthError": "Passwort muss Kleinbuchstaben, Großbuchstaben, Zahl und Sonderzeichen enthalten",
"registrationFailed": "Registrierung fehlgeschlagen",
"accountCreated": "Konto erstellt! Bitte überprüfe deine E-Mails, um dein Konto zu bestätigen."
},
"forgotPassword": {
"titleForm": "Passwort zurücksetzen",
"titleSuccess": "E-Mail gesendet",
"description": "Gib deine E-Mail-Adresse ein und wir senden dir einen Link zum Zurücksetzen deines Passworts.",
"emailPlaceholder": "E-Mail",
"sendResetLinkButton": "Link senden",
"sending": "Wird gesendet...",
"backToLogin": "Zurück zur Anmeldung",
"resendEmail": "E-Mail erneut senden",
"successMessage": "Wir haben einen Link zum Zurücksetzen des Passworts an {email} gesendet. Bitte überprüfe deinen Posteingang.",
"emailRequired": "E-Mail ist erforderlich",
"sendFailed": "E-Mail konnte nicht gesendet werden"
}
"login": {
"title": "Anmelden",
"subtitle": "Melde dich mit deinem Mana-Konto an",
"emailPlaceholder": "E-Mail",
"passwordPlaceholder": "Passwort",
"rememberMe": "Angemeldet bleiben",
"forgotPassword": "Passwort vergessen?",
"signInButton": "Anmelden",
"signingIn": "Anmeldung...",
"success": "Erfolgreich!",
"orDivider": "oder",
"noAccount": "Noch kein Konto?",
"createAccount": "Jetzt erstellen",
"skipToForm": "Zum Anmeldeformular springen",
"showPassword": "Passwort anzeigen",
"hidePassword": "Passwort verbergen",
"emailRequired": "E-Mail ist erforderlich",
"emailInvalid": "Bitte gib eine gültige E-Mail-Adresse ein",
"passwordRequired": "Passwort ist erforderlich",
"signInFailed": "Anmeldung fehlgeschlagen",
"googleSignInFailed": "Google-Anmeldung fehlgeschlagen",
"signInSuccess": "Erfolgreich angemeldet. Weiterleitung...",
"googleSignInSuccess": "Erfolgreich mit Google angemeldet. Weiterleitung..."
},
"register": {
"title": "Konto erstellen",
"emailPlaceholder": "E-Mail",
"passwordPlaceholder": "Passwort",
"confirmPasswordPlaceholder": "Passwort bestätigen",
"passwordRequirements": "Das Passwort muss mindestens 8 Zeichen mit Kleinbuchstaben, Großbuchstaben, Zahl und Sonderzeichen enthalten.",
"createAccountButton": "Konto erstellen",
"creatingAccount": "Konto wird erstellt...",
"backToLogin": "Zurück zur Anmeldung",
"showPassword": "Passwort anzeigen",
"hidePassword": "Passwort verbergen",
"emailRequired": "E-Mail ist erforderlich",
"passwordRequired": "Passwort ist erforderlich",
"confirmPasswordRequired": "Bitte bestätige dein Passwort",
"passwordsDoNotMatch": "Passwörter stimmen nicht überein",
"passwordTooShort": "Passwort muss mindestens 8 Zeichen lang sein",
"passwordStrengthError": "Passwort muss Kleinbuchstaben, Großbuchstaben, Zahl und Sonderzeichen enthalten",
"registrationFailed": "Registrierung fehlgeschlagen",
"accountCreated": "Konto erstellt! Bitte überprüfe deine E-Mails, um dein Konto zu bestätigen."
},
"forgotPassword": {
"titleForm": "Passwort zurücksetzen",
"titleSuccess": "E-Mail gesendet",
"description": "Gib deine E-Mail-Adresse ein und wir senden dir einen Link zum Zurücksetzen deines Passworts.",
"emailPlaceholder": "E-Mail",
"sendResetLinkButton": "Link senden",
"sending": "Wird gesendet...",
"backToLogin": "Zurück zur Anmeldung",
"resendEmail": "E-Mail erneut senden",
"successMessage": "Wir haben einen Link zum Zurücksetzen des Passworts an {email} gesendet. Bitte überprüfe deinen Posteingang.",
"emailRequired": "E-Mail ist erforderlich",
"sendFailed": "E-Mail konnte nicht gesendet werden"
}
}

View file

@ -1,59 +1,59 @@
{
"login": {
"title": "Sign In",
"subtitle": "Sign in with your Mana account",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Password",
"rememberMe": "Remember me",
"forgotPassword": "Forgot password?",
"signInButton": "Sign In",
"signingIn": "Signing in...",
"success": "Success!",
"orDivider": "or",
"noAccount": "Don't have an account?",
"createAccount": "Create one",
"skipToForm": "Skip to login form",
"showPassword": "Show password",
"hidePassword": "Hide password",
"emailRequired": "Email is required",
"emailInvalid": "Please enter a valid email address",
"passwordRequired": "Password is required",
"signInFailed": "Sign in failed",
"googleSignInFailed": "Google sign in failed",
"signInSuccess": "Successfully signed in. Redirecting...",
"googleSignInSuccess": "Successfully signed in with Google. Redirecting..."
},
"register": {
"title": "Create Account",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Password",
"confirmPasswordPlaceholder": "Confirm Password",
"passwordRequirements": "Password must be at least 8 characters with lowercase, uppercase, number, and special character.",
"createAccountButton": "Create Account",
"creatingAccount": "Creating Account...",
"backToLogin": "Back to Login",
"showPassword": "Show password",
"hidePassword": "Hide password",
"emailRequired": "Email is required",
"passwordRequired": "Password is required",
"confirmPasswordRequired": "Please confirm your password",
"passwordsDoNotMatch": "Passwords do not match",
"passwordTooShort": "Password must be at least 8 characters",
"passwordStrengthError": "Password must include lowercase, uppercase, number, and special character",
"registrationFailed": "Registration failed",
"accountCreated": "Account created! Please check your email to verify your account."
},
"forgotPassword": {
"titleForm": "Reset Password",
"titleSuccess": "Email Sent",
"description": "Enter your email address and we'll send you a link to reset your password.",
"emailPlaceholder": "Email",
"sendResetLinkButton": "Send Reset Link",
"sending": "Sending...",
"backToLogin": "Back to Login",
"resendEmail": "Resend Email",
"successMessage": "We've sent a password reset link to {email}. Please check your inbox.",
"emailRequired": "Email is required",
"sendFailed": "Failed to send reset email"
}
"login": {
"title": "Sign In",
"subtitle": "Sign in with your Mana account",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Password",
"rememberMe": "Remember me",
"forgotPassword": "Forgot password?",
"signInButton": "Sign In",
"signingIn": "Signing in...",
"success": "Success!",
"orDivider": "or",
"noAccount": "Don't have an account?",
"createAccount": "Create one",
"skipToForm": "Skip to login form",
"showPassword": "Show password",
"hidePassword": "Hide password",
"emailRequired": "Email is required",
"emailInvalid": "Please enter a valid email address",
"passwordRequired": "Password is required",
"signInFailed": "Sign in failed",
"googleSignInFailed": "Google sign in failed",
"signInSuccess": "Successfully signed in. Redirecting...",
"googleSignInSuccess": "Successfully signed in with Google. Redirecting..."
},
"register": {
"title": "Create Account",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Password",
"confirmPasswordPlaceholder": "Confirm Password",
"passwordRequirements": "Password must be at least 8 characters with lowercase, uppercase, number, and special character.",
"createAccountButton": "Create Account",
"creatingAccount": "Creating Account...",
"backToLogin": "Back to Login",
"showPassword": "Show password",
"hidePassword": "Hide password",
"emailRequired": "Email is required",
"passwordRequired": "Password is required",
"confirmPasswordRequired": "Please confirm your password",
"passwordsDoNotMatch": "Passwords do not match",
"passwordTooShort": "Password must be at least 8 characters",
"passwordStrengthError": "Password must include lowercase, uppercase, number, and special character",
"registrationFailed": "Registration failed",
"accountCreated": "Account created! Please check your email to verify your account."
},
"forgotPassword": {
"titleForm": "Reset Password",
"titleSuccess": "Email Sent",
"description": "Enter your email address and we'll send you a link to reset your password.",
"emailPlaceholder": "Email",
"sendResetLinkButton": "Send Reset Link",
"sending": "Sending...",
"backToLogin": "Back to Login",
"resendEmail": "Resend Email",
"successMessage": "We've sent a password reset link to {email}. Please check your inbox.",
"emailRequired": "Email is required",
"sendFailed": "Failed to send reset email"
}
}

View file

@ -1,59 +1,59 @@
{
"login": {
"title": "Iniciar Sesión",
"subtitle": "Inicia sesión con tu cuenta Mana",
"emailPlaceholder": "Correo electrónico",
"passwordPlaceholder": "Contraseña",
"rememberMe": "Recordarme",
"forgotPassword": "¿Olvidaste tu contraseña?",
"signInButton": "Iniciar Sesión",
"signingIn": "Iniciando sesión...",
"success": "¡Éxito!",
"orDivider": "o",
"noAccount": "¿No tienes cuenta?",
"createAccount": "Crear una",
"skipToForm": "Ir al formulario de inicio de sesión",
"showPassword": "Mostrar contraseña",
"hidePassword": "Ocultar contraseña",
"emailRequired": "El correo electrónico es obligatorio",
"emailInvalid": "Por favor ingresa un correo electrónico válido",
"passwordRequired": "La contraseña es obligatoria",
"signInFailed": "Error al iniciar sesión",
"googleSignInFailed": "Error al iniciar sesión con Google",
"signInSuccess": "Sesión iniciada correctamente. Redirigiendo...",
"googleSignInSuccess": "Sesión iniciada con Google correctamente. Redirigiendo..."
},
"register": {
"title": "Crear Cuenta",
"emailPlaceholder": "Correo electrónico",
"passwordPlaceholder": "Contraseña",
"confirmPasswordPlaceholder": "Confirmar Contraseña",
"passwordRequirements": "La contraseña debe tener al menos 8 caracteres con minúsculas, mayúsculas, números y caracteres especiales.",
"createAccountButton": "Crear Cuenta",
"creatingAccount": "Creando cuenta...",
"backToLogin": "Volver al inicio de sesión",
"showPassword": "Mostrar contraseña",
"hidePassword": "Ocultar contraseña",
"emailRequired": "El correo electrónico es obligatorio",
"passwordRequired": "La contraseña es obligatoria",
"confirmPasswordRequired": "Por favor confirma tu contraseña",
"passwordsDoNotMatch": "Las contraseñas no coinciden",
"passwordTooShort": "La contraseña debe tener al menos 8 caracteres",
"passwordStrengthError": "La contraseña debe incluir minúsculas, mayúsculas, números y caracteres especiales",
"registrationFailed": "Error en el registro",
"accountCreated": "¡Cuenta creada! Por favor revisa tu correo para verificar tu cuenta."
},
"forgotPassword": {
"titleForm": "Restablecer Contraseña",
"titleSuccess": "Correo Enviado",
"description": "Ingresa tu correo electrónico y te enviaremos un enlace para restablecer tu contraseña.",
"emailPlaceholder": "Correo electrónico",
"sendResetLinkButton": "Enviar Enlace",
"sending": "Enviando...",
"backToLogin": "Volver al inicio de sesión",
"resendEmail": "Reenviar correo",
"successMessage": "Hemos enviado un enlace de restablecimiento a {email}. Por favor revisa tu bandeja de entrada.",
"emailRequired": "El correo electrónico es obligatorio",
"sendFailed": "No se pudo enviar el correo"
}
"login": {
"title": "Iniciar Sesión",
"subtitle": "Inicia sesión con tu cuenta Mana",
"emailPlaceholder": "Correo electrónico",
"passwordPlaceholder": "Contraseña",
"rememberMe": "Recordarme",
"forgotPassword": "¿Olvidaste tu contraseña?",
"signInButton": "Iniciar Sesión",
"signingIn": "Iniciando sesión...",
"success": "¡Éxito!",
"orDivider": "o",
"noAccount": "¿No tienes cuenta?",
"createAccount": "Crear una",
"skipToForm": "Ir al formulario de inicio de sesión",
"showPassword": "Mostrar contraseña",
"hidePassword": "Ocultar contraseña",
"emailRequired": "El correo electrónico es obligatorio",
"emailInvalid": "Por favor ingresa un correo electrónico válido",
"passwordRequired": "La contraseña es obligatoria",
"signInFailed": "Error al iniciar sesión",
"googleSignInFailed": "Error al iniciar sesión con Google",
"signInSuccess": "Sesión iniciada correctamente. Redirigiendo...",
"googleSignInSuccess": "Sesión iniciada con Google correctamente. Redirigiendo..."
},
"register": {
"title": "Crear Cuenta",
"emailPlaceholder": "Correo electrónico",
"passwordPlaceholder": "Contraseña",
"confirmPasswordPlaceholder": "Confirmar Contraseña",
"passwordRequirements": "La contraseña debe tener al menos 8 caracteres con minúsculas, mayúsculas, números y caracteres especiales.",
"createAccountButton": "Crear Cuenta",
"creatingAccount": "Creando cuenta...",
"backToLogin": "Volver al inicio de sesión",
"showPassword": "Mostrar contraseña",
"hidePassword": "Ocultar contraseña",
"emailRequired": "El correo electrónico es obligatorio",
"passwordRequired": "La contraseña es obligatoria",
"confirmPasswordRequired": "Por favor confirma tu contraseña",
"passwordsDoNotMatch": "Las contraseñas no coinciden",
"passwordTooShort": "La contraseña debe tener al menos 8 caracteres",
"passwordStrengthError": "La contraseña debe incluir minúsculas, mayúsculas, números y caracteres especiales",
"registrationFailed": "Error en el registro",
"accountCreated": "¡Cuenta creada! Por favor revisa tu correo para verificar tu cuenta."
},
"forgotPassword": {
"titleForm": "Restablecer Contraseña",
"titleSuccess": "Correo Enviado",
"description": "Ingresa tu correo electrónico y te enviaremos un enlace para restablecer tu contraseña.",
"emailPlaceholder": "Correo electrónico",
"sendResetLinkButton": "Enviar Enlace",
"sending": "Enviando...",
"backToLogin": "Volver al inicio de sesión",
"resendEmail": "Reenviar correo",
"successMessage": "Hemos enviado un enlace de restablecimiento a {email}. Por favor revisa tu bandeja de entrada.",
"emailRequired": "El correo electrónico es obligatorio",
"sendFailed": "No se pudo enviar el correo"
}
}

View file

@ -1,59 +1,59 @@
{
"login": {
"title": "Connexion",
"subtitle": "Connectez-vous avec votre compte Mana",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Mot de passe",
"rememberMe": "Se souvenir de moi",
"forgotPassword": "Mot de passe oublié ?",
"signInButton": "Se connecter",
"signingIn": "Connexion...",
"success": "Succès !",
"orDivider": "ou",
"noAccount": "Pas encore de compte ?",
"createAccount": "Créer un compte",
"skipToForm": "Aller au formulaire de connexion",
"showPassword": "Afficher le mot de passe",
"hidePassword": "Masquer le mot de passe",
"emailRequired": "L'email est requis",
"emailInvalid": "Veuillez entrer une adresse email valide",
"passwordRequired": "Le mot de passe est requis",
"signInFailed": "Échec de la connexion",
"googleSignInFailed": "Échec de la connexion Google",
"signInSuccess": "Connexion réussie. Redirection...",
"googleSignInSuccess": "Connexion Google réussie. Redirection..."
},
"register": {
"title": "Créer un compte",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Mot de passe",
"confirmPasswordPlaceholder": "Confirmer le mot de passe",
"passwordRequirements": "Le mot de passe doit contenir au moins 8 caractères avec des minuscules, majuscules, chiffres et caractères spéciaux.",
"createAccountButton": "Créer un compte",
"creatingAccount": "Création du compte...",
"backToLogin": "Retour à la connexion",
"showPassword": "Afficher le mot de passe",
"hidePassword": "Masquer le mot de passe",
"emailRequired": "L'email est requis",
"passwordRequired": "Le mot de passe est requis",
"confirmPasswordRequired": "Veuillez confirmer votre mot de passe",
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
"passwordTooShort": "Le mot de passe doit contenir au moins 8 caractères",
"passwordStrengthError": "Le mot de passe doit contenir des minuscules, majuscules, chiffres et caractères spéciaux",
"registrationFailed": "Échec de l'inscription",
"accountCreated": "Compte créé ! Veuillez vérifier votre email pour activer votre compte."
},
"forgotPassword": {
"titleForm": "Réinitialiser le mot de passe",
"titleSuccess": "Email envoyé",
"description": "Entrez votre adresse email et nous vous enverrons un lien pour réinitialiser votre mot de passe.",
"emailPlaceholder": "Email",
"sendResetLinkButton": "Envoyer le lien",
"sending": "Envoi en cours...",
"backToLogin": "Retour à la connexion",
"resendEmail": "Renvoyer l'email",
"successMessage": "Nous avons envoyé un lien de réinitialisation à {email}. Veuillez vérifier votre boîte de réception.",
"emailRequired": "L'email est requis",
"sendFailed": "Impossible d'envoyer l'email"
}
"login": {
"title": "Connexion",
"subtitle": "Connectez-vous avec votre compte Mana",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Mot de passe",
"rememberMe": "Se souvenir de moi",
"forgotPassword": "Mot de passe oublié ?",
"signInButton": "Se connecter",
"signingIn": "Connexion...",
"success": "Succès !",
"orDivider": "ou",
"noAccount": "Pas encore de compte ?",
"createAccount": "Créer un compte",
"skipToForm": "Aller au formulaire de connexion",
"showPassword": "Afficher le mot de passe",
"hidePassword": "Masquer le mot de passe",
"emailRequired": "L'email est requis",
"emailInvalid": "Veuillez entrer une adresse email valide",
"passwordRequired": "Le mot de passe est requis",
"signInFailed": "Échec de la connexion",
"googleSignInFailed": "Échec de la connexion Google",
"signInSuccess": "Connexion réussie. Redirection...",
"googleSignInSuccess": "Connexion Google réussie. Redirection..."
},
"register": {
"title": "Créer un compte",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Mot de passe",
"confirmPasswordPlaceholder": "Confirmer le mot de passe",
"passwordRequirements": "Le mot de passe doit contenir au moins 8 caractères avec des minuscules, majuscules, chiffres et caractères spéciaux.",
"createAccountButton": "Créer un compte",
"creatingAccount": "Création du compte...",
"backToLogin": "Retour à la connexion",
"showPassword": "Afficher le mot de passe",
"hidePassword": "Masquer le mot de passe",
"emailRequired": "L'email est requis",
"passwordRequired": "Le mot de passe est requis",
"confirmPasswordRequired": "Veuillez confirmer votre mot de passe",
"passwordsDoNotMatch": "Les mots de passe ne correspondent pas",
"passwordTooShort": "Le mot de passe doit contenir au moins 8 caractères",
"passwordStrengthError": "Le mot de passe doit contenir des minuscules, majuscules, chiffres et caractères spéciaux",
"registrationFailed": "Échec de l'inscription",
"accountCreated": "Compte créé ! Veuillez vérifier votre email pour activer votre compte."
},
"forgotPassword": {
"titleForm": "Réinitialiser le mot de passe",
"titleSuccess": "Email envoyé",
"description": "Entrez votre adresse email et nous vous enverrons un lien pour réinitialiser votre mot de passe.",
"emailPlaceholder": "Email",
"sendResetLinkButton": "Envoyer le lien",
"sending": "Envoi en cours...",
"backToLogin": "Retour à la connexion",
"resendEmail": "Renvoyer l'email",
"successMessage": "Nous avons envoyé un lien de réinitialisation à {email}. Veuillez vérifier votre boîte de réception.",
"emailRequired": "L'email est requis",
"sendFailed": "Impossible d'envoyer l'email"
}
}

View file

@ -14,63 +14,63 @@ export { en, de, it, fr, es };
* Auth translations type structure
*/
export interface AuthTranslations {
login: {
title: string;
subtitle: string;
emailPlaceholder: string;
passwordPlaceholder: string;
rememberMe: string;
forgotPassword: string;
signInButton: string;
signingIn: string;
success: string;
orDivider: string;
noAccount: string;
createAccount: string;
skipToForm: string;
showPassword: string;
hidePassword: string;
emailRequired: string;
emailInvalid: string;
passwordRequired: string;
signInFailed: string;
googleSignInFailed: string;
signInSuccess: string;
googleSignInSuccess: string;
};
register: {
title: string;
emailPlaceholder: string;
passwordPlaceholder: string;
confirmPasswordPlaceholder: string;
passwordRequirements: string;
createAccountButton: string;
creatingAccount: string;
backToLogin: string;
showPassword: string;
hidePassword: string;
emailRequired: string;
passwordRequired: string;
confirmPasswordRequired: string;
passwordsDoNotMatch: string;
passwordTooShort: string;
passwordStrengthError: string;
registrationFailed: string;
accountCreated: string;
};
forgotPassword: {
titleForm: string;
titleSuccess: string;
description: string;
emailPlaceholder: string;
sendResetLinkButton: string;
sending: string;
backToLogin: string;
resendEmail: string;
successMessage: string;
emailRequired: string;
sendFailed: string;
};
login: {
title: string;
subtitle: string;
emailPlaceholder: string;
passwordPlaceholder: string;
rememberMe: string;
forgotPassword: string;
signInButton: string;
signingIn: string;
success: string;
orDivider: string;
noAccount: string;
createAccount: string;
skipToForm: string;
showPassword: string;
hidePassword: string;
emailRequired: string;
emailInvalid: string;
passwordRequired: string;
signInFailed: string;
googleSignInFailed: string;
signInSuccess: string;
googleSignInSuccess: string;
};
register: {
title: string;
emailPlaceholder: string;
passwordPlaceholder: string;
confirmPasswordPlaceholder: string;
passwordRequirements: string;
createAccountButton: string;
creatingAccount: string;
backToLogin: string;
showPassword: string;
hidePassword: string;
emailRequired: string;
passwordRequired: string;
confirmPasswordRequired: string;
passwordsDoNotMatch: string;
passwordTooShort: string;
passwordStrengthError: string;
registrationFailed: string;
accountCreated: string;
};
forgotPassword: {
titleForm: string;
titleSuccess: string;
description: string;
emailPlaceholder: string;
sendResetLinkButton: string;
sending: string;
backToLogin: string;
resendEmail: string;
successMessage: string;
emailRequired: string;
sendFailed: string;
};
}
/**
@ -82,42 +82,42 @@ export type AuthLocale = 'en' | 'de' | 'it' | 'fr' | 'es';
* All auth translations by locale
*/
export const authTranslations: Record<AuthLocale, AuthTranslations> = {
en,
de,
it,
fr,
es
en,
de,
it,
fr,
es,
};
/**
* Get auth translations by locale
*/
export function getAuthTranslations(locale: string): AuthTranslations {
const supportedLocale = locale as AuthLocale;
if (supportedLocale in authTranslations) {
return authTranslations[supportedLocale];
}
// Default to English
return authTranslations.en;
const supportedLocale = locale as AuthLocale;
if (supportedLocale in authTranslations) {
return authTranslations[supportedLocale];
}
// Default to English
return authTranslations.en;
}
/**
* Get login translations for a specific locale
*/
export function getLoginTranslations(locale: string): AuthTranslations['login'] {
return getAuthTranslations(locale).login;
return getAuthTranslations(locale).login;
}
/**
* Get register translations for a specific locale
*/
export function getRegisterTranslations(locale: string): AuthTranslations['register'] {
return getAuthTranslations(locale).register;
return getAuthTranslations(locale).register;
}
/**
* Get forgot password translations for a specific locale
*/
export function getForgotPasswordTranslations(locale: string): AuthTranslations['forgotPassword'] {
return getAuthTranslations(locale).forgotPassword;
return getAuthTranslations(locale).forgotPassword;
}

View file

@ -1,59 +1,59 @@
{
"login": {
"title": "Accedi",
"subtitle": "Accedi con il tuo account Mana",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Password",
"rememberMe": "Ricordami",
"forgotPassword": "Password dimenticata?",
"signInButton": "Accedi",
"signingIn": "Accesso in corso...",
"success": "Successo!",
"orDivider": "oppure",
"noAccount": "Non hai un account?",
"createAccount": "Creane uno",
"skipToForm": "Vai al modulo di accesso",
"showPassword": "Mostra password",
"hidePassword": "Nascondi password",
"emailRequired": "L'email è obbligatoria",
"emailInvalid": "Inserisci un indirizzo email valido",
"passwordRequired": "La password è obbligatoria",
"signInFailed": "Accesso fallito",
"googleSignInFailed": "Accesso con Google fallito",
"signInSuccess": "Accesso effettuato. Reindirizzamento...",
"googleSignInSuccess": "Accesso con Google effettuato. Reindirizzamento..."
},
"register": {
"title": "Crea Account",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Password",
"confirmPasswordPlaceholder": "Conferma Password",
"passwordRequirements": "La password deve contenere almeno 8 caratteri con minuscole, maiuscole, numeri e caratteri speciali.",
"createAccountButton": "Crea Account",
"creatingAccount": "Creazione account...",
"backToLogin": "Torna al login",
"showPassword": "Mostra password",
"hidePassword": "Nascondi password",
"emailRequired": "L'email è obbligatoria",
"passwordRequired": "La password è obbligatoria",
"confirmPasswordRequired": "Conferma la tua password",
"passwordsDoNotMatch": "Le password non corrispondono",
"passwordTooShort": "La password deve contenere almeno 8 caratteri",
"passwordStrengthError": "La password deve contenere minuscole, maiuscole, numeri e caratteri speciali",
"registrationFailed": "Registrazione fallita",
"accountCreated": "Account creato! Controlla la tua email per verificare il tuo account."
},
"forgotPassword": {
"titleForm": "Reimposta Password",
"titleSuccess": "Email Inviata",
"description": "Inserisci il tuo indirizzo email e ti invieremo un link per reimpostare la password.",
"emailPlaceholder": "Email",
"sendResetLinkButton": "Invia Link",
"sending": "Invio in corso...",
"backToLogin": "Torna al login",
"resendEmail": "Invia di nuovo",
"successMessage": "Abbiamo inviato un link per reimpostare la password a {email}. Controlla la tua casella di posta.",
"emailRequired": "L'email è obbligatoria",
"sendFailed": "Impossibile inviare l'email"
}
"login": {
"title": "Accedi",
"subtitle": "Accedi con il tuo account Mana",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Password",
"rememberMe": "Ricordami",
"forgotPassword": "Password dimenticata?",
"signInButton": "Accedi",
"signingIn": "Accesso in corso...",
"success": "Successo!",
"orDivider": "oppure",
"noAccount": "Non hai un account?",
"createAccount": "Creane uno",
"skipToForm": "Vai al modulo di accesso",
"showPassword": "Mostra password",
"hidePassword": "Nascondi password",
"emailRequired": "L'email è obbligatoria",
"emailInvalid": "Inserisci un indirizzo email valido",
"passwordRequired": "La password è obbligatoria",
"signInFailed": "Accesso fallito",
"googleSignInFailed": "Accesso con Google fallito",
"signInSuccess": "Accesso effettuato. Reindirizzamento...",
"googleSignInSuccess": "Accesso con Google effettuato. Reindirizzamento..."
},
"register": {
"title": "Crea Account",
"emailPlaceholder": "Email",
"passwordPlaceholder": "Password",
"confirmPasswordPlaceholder": "Conferma Password",
"passwordRequirements": "La password deve contenere almeno 8 caratteri con minuscole, maiuscole, numeri e caratteri speciali.",
"createAccountButton": "Crea Account",
"creatingAccount": "Creazione account...",
"backToLogin": "Torna al login",
"showPassword": "Mostra password",
"hidePassword": "Nascondi password",
"emailRequired": "L'email è obbligatoria",
"passwordRequired": "La password è obbligatoria",
"confirmPasswordRequired": "Conferma la tua password",
"passwordsDoNotMatch": "Le password non corrispondono",
"passwordTooShort": "La password deve contenere almeno 8 caratteri",
"passwordStrengthError": "La password deve contenere minuscole, maiuscole, numeri e caratteri speciali",
"registrationFailed": "Registrazione fallita",
"accountCreated": "Account creato! Controlla la tua email per verificare il tuo account."
},
"forgotPassword": {
"titleForm": "Reimposta Password",
"titleSuccess": "Email Inviata",
"description": "Inserisci il tuo indirizzo email e ti invieremo un link per reimpostare la password.",
"emailPlaceholder": "Email",
"sendResetLinkButton": "Invia Link",
"sending": "Invio in corso...",
"backToLogin": "Torna al login",
"resendEmail": "Invia di nuovo",
"successMessage": "Abbiamo inviato un link per reimpostare la password a {email}. Controlla la tua casella di posta.",
"emailRequired": "L'email è obbligatoria",
"sendFailed": "Impossibile inviare l'email"
}
}

View file

@ -1,172 +1,172 @@
{
"common": {
"actions": {
"save": "Speichern",
"cancel": "Abbrechen",
"delete": "Löschen",
"edit": "Bearbeiten",
"create": "Erstellen",
"update": "Aktualisieren",
"close": "Schließen",
"confirm": "Bestätigen",
"submit": "Absenden",
"back": "Zurück",
"next": "Weiter",
"done": "Fertig",
"retry": "Erneut versuchen",
"refresh": "Aktualisieren",
"search": "Suchen",
"filter": "Filtern",
"sort": "Sortieren",
"share": "Teilen",
"copy": "Kopieren",
"download": "Herunterladen",
"upload": "Hochladen",
"select": "Auswählen",
"clear": "Leeren",
"reset": "Zurücksetzen",
"apply": "Anwenden",
"continue": "Fortfahren",
"skip": "Überspringen",
"yes": "Ja",
"no": "Nein",
"ok": "OK"
},
"labels": {
"loading": "Lädt...",
"saving": "Speichert...",
"deleting": "Löscht...",
"processing": "Verarbeitet...",
"uploading": "Lädt hoch...",
"downloading": "Lädt herunter...",
"searching": "Sucht...",
"noResults": "Keine Ergebnisse gefunden",
"noData": "Keine Daten verfügbar",
"empty": "Leer",
"all": "Alle",
"none": "Keine",
"other": "Andere",
"more": "Mehr",
"less": "Weniger",
"showMore": "Mehr anzeigen",
"showLess": "Weniger anzeigen",
"viewAll": "Alle anzeigen",
"required": "Erforderlich",
"optional": "Optional",
"new": "Neu",
"recent": "Aktuell",
"popular": "Beliebt",
"featured": "Empfohlen"
},
"time": {
"now": "Jetzt",
"today": "Heute",
"yesterday": "Gestern",
"tomorrow": "Morgen",
"thisWeek": "Diese Woche",
"lastWeek": "Letzte Woche",
"thisMonth": "Diesen Monat",
"lastMonth": "Letzten Monat",
"thisYear": "Dieses Jahr",
"ago": "vor",
"in": "in"
},
"status": {
"active": "Aktiv",
"inactive": "Inaktiv",
"pending": "Ausstehend",
"completed": "Abgeschlossen",
"failed": "Fehlgeschlagen",
"cancelled": "Abgebrochen",
"success": "Erfolg",
"error": "Fehler",
"warning": "Warnung",
"info": "Info"
}
},
"errors": {
"generic": "Etwas ist schief gelaufen. Bitte versuche es erneut.",
"network": "Netzwerkfehler. Bitte überprüfe deine Verbindung.",
"timeout": "Zeitüberschreitung. Bitte versuche es erneut.",
"notFound": "Das angeforderte Element wurde nicht gefunden.",
"unauthorized": "Du bist nicht berechtigt, diese Aktion durchzuführen.",
"forbidden": "Zugriff verweigert.",
"serverError": "Serverfehler. Bitte versuche es später erneut.",
"validation": "Bitte überprüfe deine Eingabe und versuche es erneut.",
"unknown": "Ein unbekannter Fehler ist aufgetreten.",
"offline": "Du bist offline. Bitte überprüfe deine Internetverbindung.",
"sessionExpired": "Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.",
"rateLimited": "Zu viele Anfragen. Bitte warte einen Moment und versuche es erneut."
},
"validation": {
"required": "Dieses Feld ist erforderlich",
"email": "Bitte gib eine gültige E-Mail-Adresse ein",
"minLength": "Muss mindestens {min} Zeichen lang sein",
"maxLength": "Darf höchstens {max} Zeichen lang sein",
"min": "Muss mindestens {min} sein",
"max": "Darf höchstens {max} sein",
"pattern": "Ungültiges Format",
"match": "Felder stimmen nicht überein",
"unique": "Dieser Wert wird bereits verwendet",
"invalid": "Ungültiger Wert",
"url": "Bitte gib eine gültige URL ein",
"phone": "Bitte gib eine gültige Telefonnummer ein",
"number": "Bitte gib eine gültige Zahl ein",
"integer": "Bitte gib eine ganze Zahl ein",
"positive": "Muss eine positive Zahl sein",
"date": "Bitte gib ein gültiges Datum ein",
"futureDate": "Datum muss in der Zukunft liegen",
"pastDate": "Datum muss in der Vergangenheit liegen",
"password": {
"minLength": "Passwort muss mindestens {min} Zeichen lang sein",
"uppercase": "Passwort muss einen Großbuchstaben enthalten",
"lowercase": "Passwort muss einen Kleinbuchstaben enthalten",
"number": "Passwort muss eine Zahl enthalten",
"special": "Passwort muss ein Sonderzeichen enthalten",
"weak": "Passwort ist zu schwach"
}
},
"auth": {
"signIn": "Anmelden",
"signOut": "Abmelden",
"signUp": "Registrieren",
"forgotPassword": "Passwort vergessen?",
"resetPassword": "Passwort zurücksetzen",
"changePassword": "Passwort ändern",
"email": "E-Mail",
"password": "Passwort",
"confirmPassword": "Passwort bestätigen",
"rememberMe": "Angemeldet bleiben",
"orContinueWith": "Oder fortfahren mit",
"alreadyHaveAccount": "Bereits ein Konto?",
"dontHaveAccount": "Noch kein Konto?",
"errors": {
"invalidCredentials": "Ungültige E-Mail oder Passwort",
"emailInUse": "Diese E-Mail wird bereits verwendet",
"weakPassword": "Passwort ist zu schwach",
"userNotFound": "Benutzer nicht gefunden",
"tooManyAttempts": "Zu viele Versuche. Bitte versuche es später erneut."
}
},
"settings": {
"title": "Einstellungen",
"account": "Konto",
"profile": "Profil",
"preferences": "Einstellungen",
"notifications": "Benachrichtigungen",
"privacy": "Datenschutz",
"security": "Sicherheit",
"language": "Sprache",
"theme": "Design",
"appearance": "Erscheinungsbild",
"darkMode": "Dunkelmodus",
"lightMode": "Hellmodus",
"systemDefault": "Systemstandard",
"about": "Über",
"help": "Hilfe",
"feedback": "Feedback",
"terms": "Nutzungsbedingungen",
"privacyPolicy": "Datenschutzrichtlinie",
"version": "Version"
}
"common": {
"actions": {
"save": "Speichern",
"cancel": "Abbrechen",
"delete": "Löschen",
"edit": "Bearbeiten",
"create": "Erstellen",
"update": "Aktualisieren",
"close": "Schließen",
"confirm": "Bestätigen",
"submit": "Absenden",
"back": "Zurück",
"next": "Weiter",
"done": "Fertig",
"retry": "Erneut versuchen",
"refresh": "Aktualisieren",
"search": "Suchen",
"filter": "Filtern",
"sort": "Sortieren",
"share": "Teilen",
"copy": "Kopieren",
"download": "Herunterladen",
"upload": "Hochladen",
"select": "Auswählen",
"clear": "Leeren",
"reset": "Zurücksetzen",
"apply": "Anwenden",
"continue": "Fortfahren",
"skip": "Überspringen",
"yes": "Ja",
"no": "Nein",
"ok": "OK"
},
"labels": {
"loading": "Lädt...",
"saving": "Speichert...",
"deleting": "Löscht...",
"processing": "Verarbeitet...",
"uploading": "Lädt hoch...",
"downloading": "Lädt herunter...",
"searching": "Sucht...",
"noResults": "Keine Ergebnisse gefunden",
"noData": "Keine Daten verfügbar",
"empty": "Leer",
"all": "Alle",
"none": "Keine",
"other": "Andere",
"more": "Mehr",
"less": "Weniger",
"showMore": "Mehr anzeigen",
"showLess": "Weniger anzeigen",
"viewAll": "Alle anzeigen",
"required": "Erforderlich",
"optional": "Optional",
"new": "Neu",
"recent": "Aktuell",
"popular": "Beliebt",
"featured": "Empfohlen"
},
"time": {
"now": "Jetzt",
"today": "Heute",
"yesterday": "Gestern",
"tomorrow": "Morgen",
"thisWeek": "Diese Woche",
"lastWeek": "Letzte Woche",
"thisMonth": "Diesen Monat",
"lastMonth": "Letzten Monat",
"thisYear": "Dieses Jahr",
"ago": "vor",
"in": "in"
},
"status": {
"active": "Aktiv",
"inactive": "Inaktiv",
"pending": "Ausstehend",
"completed": "Abgeschlossen",
"failed": "Fehlgeschlagen",
"cancelled": "Abgebrochen",
"success": "Erfolg",
"error": "Fehler",
"warning": "Warnung",
"info": "Info"
}
},
"errors": {
"generic": "Etwas ist schief gelaufen. Bitte versuche es erneut.",
"network": "Netzwerkfehler. Bitte überprüfe deine Verbindung.",
"timeout": "Zeitüberschreitung. Bitte versuche es erneut.",
"notFound": "Das angeforderte Element wurde nicht gefunden.",
"unauthorized": "Du bist nicht berechtigt, diese Aktion durchzuführen.",
"forbidden": "Zugriff verweigert.",
"serverError": "Serverfehler. Bitte versuche es später erneut.",
"validation": "Bitte überprüfe deine Eingabe und versuche es erneut.",
"unknown": "Ein unbekannter Fehler ist aufgetreten.",
"offline": "Du bist offline. Bitte überprüfe deine Internetverbindung.",
"sessionExpired": "Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.",
"rateLimited": "Zu viele Anfragen. Bitte warte einen Moment und versuche es erneut."
},
"validation": {
"required": "Dieses Feld ist erforderlich",
"email": "Bitte gib eine gültige E-Mail-Adresse ein",
"minLength": "Muss mindestens {min} Zeichen lang sein",
"maxLength": "Darf höchstens {max} Zeichen lang sein",
"min": "Muss mindestens {min} sein",
"max": "Darf höchstens {max} sein",
"pattern": "Ungültiges Format",
"match": "Felder stimmen nicht überein",
"unique": "Dieser Wert wird bereits verwendet",
"invalid": "Ungültiger Wert",
"url": "Bitte gib eine gültige URL ein",
"phone": "Bitte gib eine gültige Telefonnummer ein",
"number": "Bitte gib eine gültige Zahl ein",
"integer": "Bitte gib eine ganze Zahl ein",
"positive": "Muss eine positive Zahl sein",
"date": "Bitte gib ein gültiges Datum ein",
"futureDate": "Datum muss in der Zukunft liegen",
"pastDate": "Datum muss in der Vergangenheit liegen",
"password": {
"minLength": "Passwort muss mindestens {min} Zeichen lang sein",
"uppercase": "Passwort muss einen Großbuchstaben enthalten",
"lowercase": "Passwort muss einen Kleinbuchstaben enthalten",
"number": "Passwort muss eine Zahl enthalten",
"special": "Passwort muss ein Sonderzeichen enthalten",
"weak": "Passwort ist zu schwach"
}
},
"auth": {
"signIn": "Anmelden",
"signOut": "Abmelden",
"signUp": "Registrieren",
"forgotPassword": "Passwort vergessen?",
"resetPassword": "Passwort zurücksetzen",
"changePassword": "Passwort ändern",
"email": "E-Mail",
"password": "Passwort",
"confirmPassword": "Passwort bestätigen",
"rememberMe": "Angemeldet bleiben",
"orContinueWith": "Oder fortfahren mit",
"alreadyHaveAccount": "Bereits ein Konto?",
"dontHaveAccount": "Noch kein Konto?",
"errors": {
"invalidCredentials": "Ungültige E-Mail oder Passwort",
"emailInUse": "Diese E-Mail wird bereits verwendet",
"weakPassword": "Passwort ist zu schwach",
"userNotFound": "Benutzer nicht gefunden",
"tooManyAttempts": "Zu viele Versuche. Bitte versuche es später erneut."
}
},
"settings": {
"title": "Einstellungen",
"account": "Konto",
"profile": "Profil",
"preferences": "Einstellungen",
"notifications": "Benachrichtigungen",
"privacy": "Datenschutz",
"security": "Sicherheit",
"language": "Sprache",
"theme": "Design",
"appearance": "Erscheinungsbild",
"darkMode": "Dunkelmodus",
"lightMode": "Hellmodus",
"systemDefault": "Systemstandard",
"about": "Über",
"help": "Hilfe",
"feedback": "Feedback",
"terms": "Nutzungsbedingungen",
"privacyPolicy": "Datenschutzrichtlinie",
"version": "Version"
}
}

View file

@ -1,172 +1,172 @@
{
"common": {
"actions": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"create": "Create",
"update": "Update",
"close": "Close",
"confirm": "Confirm",
"submit": "Submit",
"back": "Back",
"next": "Next",
"done": "Done",
"retry": "Retry",
"refresh": "Refresh",
"search": "Search",
"filter": "Filter",
"sort": "Sort",
"share": "Share",
"copy": "Copy",
"download": "Download",
"upload": "Upload",
"select": "Select",
"clear": "Clear",
"reset": "Reset",
"apply": "Apply",
"continue": "Continue",
"skip": "Skip",
"yes": "Yes",
"no": "No",
"ok": "OK"
},
"labels": {
"loading": "Loading...",
"saving": "Saving...",
"deleting": "Deleting...",
"processing": "Processing...",
"uploading": "Uploading...",
"downloading": "Downloading...",
"searching": "Searching...",
"noResults": "No results found",
"noData": "No data available",
"empty": "Empty",
"all": "All",
"none": "None",
"other": "Other",
"more": "More",
"less": "Less",
"showMore": "Show more",
"showLess": "Show less",
"viewAll": "View all",
"required": "Required",
"optional": "Optional",
"new": "New",
"recent": "Recent",
"popular": "Popular",
"featured": "Featured"
},
"time": {
"now": "Now",
"today": "Today",
"yesterday": "Yesterday",
"tomorrow": "Tomorrow",
"thisWeek": "This week",
"lastWeek": "Last week",
"thisMonth": "This month",
"lastMonth": "Last month",
"thisYear": "This year",
"ago": "ago",
"in": "in"
},
"status": {
"active": "Active",
"inactive": "Inactive",
"pending": "Pending",
"completed": "Completed",
"failed": "Failed",
"cancelled": "Cancelled",
"success": "Success",
"error": "Error",
"warning": "Warning",
"info": "Info"
}
},
"errors": {
"generic": "Something went wrong. Please try again.",
"network": "Network error. Please check your connection.",
"timeout": "Request timed out. Please try again.",
"notFound": "The requested item was not found.",
"unauthorized": "You are not authorized to perform this action.",
"forbidden": "Access denied.",
"serverError": "Server error. Please try again later.",
"validation": "Please check your input and try again.",
"unknown": "An unknown error occurred.",
"offline": "You are offline. Please check your internet connection.",
"sessionExpired": "Your session has expired. Please sign in again.",
"rateLimited": "Too many requests. Please wait a moment and try again."
},
"validation": {
"required": "This field is required",
"email": "Please enter a valid email address",
"minLength": "Must be at least {min} characters",
"maxLength": "Must be at most {max} characters",
"min": "Must be at least {min}",
"max": "Must be at most {max}",
"pattern": "Invalid format",
"match": "Fields do not match",
"unique": "This value is already in use",
"invalid": "Invalid value",
"url": "Please enter a valid URL",
"phone": "Please enter a valid phone number",
"number": "Please enter a valid number",
"integer": "Please enter a whole number",
"positive": "Must be a positive number",
"date": "Please enter a valid date",
"futureDate": "Date must be in the future",
"pastDate": "Date must be in the past",
"password": {
"minLength": "Password must be at least {min} characters",
"uppercase": "Password must contain an uppercase letter",
"lowercase": "Password must contain a lowercase letter",
"number": "Password must contain a number",
"special": "Password must contain a special character",
"weak": "Password is too weak"
}
},
"auth": {
"signIn": "Sign in",
"signOut": "Sign out",
"signUp": "Sign up",
"forgotPassword": "Forgot password?",
"resetPassword": "Reset password",
"changePassword": "Change password",
"email": "Email",
"password": "Password",
"confirmPassword": "Confirm password",
"rememberMe": "Remember me",
"orContinueWith": "Or continue with",
"alreadyHaveAccount": "Already have an account?",
"dontHaveAccount": "Don't have an account?",
"errors": {
"invalidCredentials": "Invalid email or password",
"emailInUse": "This email is already in use",
"weakPassword": "Password is too weak",
"userNotFound": "User not found",
"tooManyAttempts": "Too many attempts. Please try again later."
}
},
"settings": {
"title": "Settings",
"account": "Account",
"profile": "Profile",
"preferences": "Preferences",
"notifications": "Notifications",
"privacy": "Privacy",
"security": "Security",
"language": "Language",
"theme": "Theme",
"appearance": "Appearance",
"darkMode": "Dark mode",
"lightMode": "Light mode",
"systemDefault": "System default",
"about": "About",
"help": "Help",
"feedback": "Feedback",
"terms": "Terms of Service",
"privacyPolicy": "Privacy Policy",
"version": "Version"
}
"common": {
"actions": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"edit": "Edit",
"create": "Create",
"update": "Update",
"close": "Close",
"confirm": "Confirm",
"submit": "Submit",
"back": "Back",
"next": "Next",
"done": "Done",
"retry": "Retry",
"refresh": "Refresh",
"search": "Search",
"filter": "Filter",
"sort": "Sort",
"share": "Share",
"copy": "Copy",
"download": "Download",
"upload": "Upload",
"select": "Select",
"clear": "Clear",
"reset": "Reset",
"apply": "Apply",
"continue": "Continue",
"skip": "Skip",
"yes": "Yes",
"no": "No",
"ok": "OK"
},
"labels": {
"loading": "Loading...",
"saving": "Saving...",
"deleting": "Deleting...",
"processing": "Processing...",
"uploading": "Uploading...",
"downloading": "Downloading...",
"searching": "Searching...",
"noResults": "No results found",
"noData": "No data available",
"empty": "Empty",
"all": "All",
"none": "None",
"other": "Other",
"more": "More",
"less": "Less",
"showMore": "Show more",
"showLess": "Show less",
"viewAll": "View all",
"required": "Required",
"optional": "Optional",
"new": "New",
"recent": "Recent",
"popular": "Popular",
"featured": "Featured"
},
"time": {
"now": "Now",
"today": "Today",
"yesterday": "Yesterday",
"tomorrow": "Tomorrow",
"thisWeek": "This week",
"lastWeek": "Last week",
"thisMonth": "This month",
"lastMonth": "Last month",
"thisYear": "This year",
"ago": "ago",
"in": "in"
},
"status": {
"active": "Active",
"inactive": "Inactive",
"pending": "Pending",
"completed": "Completed",
"failed": "Failed",
"cancelled": "Cancelled",
"success": "Success",
"error": "Error",
"warning": "Warning",
"info": "Info"
}
},
"errors": {
"generic": "Something went wrong. Please try again.",
"network": "Network error. Please check your connection.",
"timeout": "Request timed out. Please try again.",
"notFound": "The requested item was not found.",
"unauthorized": "You are not authorized to perform this action.",
"forbidden": "Access denied.",
"serverError": "Server error. Please try again later.",
"validation": "Please check your input and try again.",
"unknown": "An unknown error occurred.",
"offline": "You are offline. Please check your internet connection.",
"sessionExpired": "Your session has expired. Please sign in again.",
"rateLimited": "Too many requests. Please wait a moment and try again."
},
"validation": {
"required": "This field is required",
"email": "Please enter a valid email address",
"minLength": "Must be at least {min} characters",
"maxLength": "Must be at most {max} characters",
"min": "Must be at least {min}",
"max": "Must be at most {max}",
"pattern": "Invalid format",
"match": "Fields do not match",
"unique": "This value is already in use",
"invalid": "Invalid value",
"url": "Please enter a valid URL",
"phone": "Please enter a valid phone number",
"number": "Please enter a valid number",
"integer": "Please enter a whole number",
"positive": "Must be a positive number",
"date": "Please enter a valid date",
"futureDate": "Date must be in the future",
"pastDate": "Date must be in the past",
"password": {
"minLength": "Password must be at least {min} characters",
"uppercase": "Password must contain an uppercase letter",
"lowercase": "Password must contain a lowercase letter",
"number": "Password must contain a number",
"special": "Password must contain a special character",
"weak": "Password is too weak"
}
},
"auth": {
"signIn": "Sign in",
"signOut": "Sign out",
"signUp": "Sign up",
"forgotPassword": "Forgot password?",
"resetPassword": "Reset password",
"changePassword": "Change password",
"email": "Email",
"password": "Password",
"confirmPassword": "Confirm password",
"rememberMe": "Remember me",
"orContinueWith": "Or continue with",
"alreadyHaveAccount": "Already have an account?",
"dontHaveAccount": "Don't have an account?",
"errors": {
"invalidCredentials": "Invalid email or password",
"emailInUse": "This email is already in use",
"weakPassword": "Password is too weak",
"userNotFound": "User not found",
"tooManyAttempts": "Too many attempts. Please try again later."
}
},
"settings": {
"title": "Settings",
"account": "Account",
"profile": "Profile",
"preferences": "Preferences",
"notifications": "Notifications",
"privacy": "Privacy",
"security": "Security",
"language": "Language",
"theme": "Theme",
"appearance": "Appearance",
"darkMode": "Dark mode",
"lightMode": "Light mode",
"systemDefault": "System default",
"about": "About",
"help": "Help",
"feedback": "Feedback",
"terms": "Terms of Service",
"privacyPolicy": "Privacy Policy",
"version": "Version"
}
}

View file

@ -16,22 +16,22 @@ export type CommonTranslations = typeof en;
* Get common translations by locale
*/
export function getCommonTranslations(locale: string): CommonTranslations {
switch (locale) {
case 'de':
return de;
case 'en':
default:
return en;
}
switch (locale) {
case 'de':
return de;
case 'en':
default:
return en;
}
}
/**
* Merge common translations with app-specific translations
*/
export function mergeWithCommon<T extends Record<string, unknown>>(
locale: string,
appTranslations: T
locale: string,
appTranslations: T
): T & CommonTranslations {
const common = getCommonTranslations(locale);
return { ...common, ...appTranslations } as T & CommonTranslations;
const common = getCommonTranslations(locale);
return { ...common, ...appTranslations } as T & CommonTranslations;
}

View file

@ -9,71 +9,71 @@ import { type LanguageCode, isLanguageSupported } from './languages';
* Works in browser environment only
*/
export function detectBrowserLocale(
supportedLocales: readonly string[],
defaultLocale: string = 'en'
supportedLocales: readonly string[],
defaultLocale: string = 'en'
): string {
if (typeof navigator === 'undefined') {
return defaultLocale;
}
if (typeof navigator === 'undefined') {
return defaultLocale;
}
// Try navigator.language first
const browserLang = navigator.language;
// Try navigator.language first
const browserLang = navigator.language;
// Check exact match (e.g., 'pt-BR')
if (supportedLocales.includes(browserLang)) {
return browserLang;
}
// Check exact match (e.g., 'pt-BR')
if (supportedLocales.includes(browserLang)) {
return browserLang;
}
// Check base language (e.g., 'pt' from 'pt-BR')
const baseLang = browserLang.split('-')[0];
if (supportedLocales.includes(baseLang)) {
return baseLang;
}
// Check base language (e.g., 'pt' from 'pt-BR')
const baseLang = browserLang.split('-')[0];
if (supportedLocales.includes(baseLang)) {
return baseLang;
}
// Try navigator.languages array
if (navigator.languages) {
for (const lang of navigator.languages) {
if (supportedLocales.includes(lang)) {
return lang;
}
const base = lang.split('-')[0];
if (supportedLocales.includes(base)) {
return base;
}
}
}
// Try navigator.languages array
if (navigator.languages) {
for (const lang of navigator.languages) {
if (supportedLocales.includes(lang)) {
return lang;
}
const base = lang.split('-')[0];
if (supportedLocales.includes(base)) {
return base;
}
}
}
return defaultLocale;
return defaultLocale;
}
/**
* Get locale from localStorage with validation
*/
export function getStoredLocale(
storageKey: string,
supportedLocales: readonly string[]
storageKey: string,
supportedLocales: readonly string[]
): string | null {
if (typeof localStorage === 'undefined') {
return null;
}
if (typeof localStorage === 'undefined') {
return null;
}
const stored = localStorage.getItem(storageKey);
if (stored && supportedLocales.includes(stored)) {
return stored;
}
const stored = localStorage.getItem(storageKey);
if (stored && supportedLocales.includes(stored)) {
return stored;
}
return null;
return null;
}
/**
* Store locale in localStorage
*/
export function storeLocale(storageKey: string, locale: string): void {
if (typeof localStorage === 'undefined') {
return;
}
if (typeof localStorage === 'undefined') {
return;
}
localStorage.setItem(storageKey, locale);
localStorage.setItem(storageKey, locale);
}
/**
@ -83,18 +83,18 @@ export function storeLocale(storageKey: string, locale: string): void {
* 3. Default locale
*/
export function getInitialLocale(
storageKey: string,
supportedLocales: readonly string[],
defaultLocale: string = 'en'
storageKey: string,
supportedLocales: readonly string[],
defaultLocale: string = 'en'
): string {
// Check localStorage first
const stored = getStoredLocale(storageKey, supportedLocales);
if (stored) {
return stored;
}
// Check localStorage first
const stored = getStoredLocale(storageKey, supportedLocales);
if (stored) {
return stored;
}
// Fall back to browser language
return detectBrowserLocale(supportedLocales, defaultLocale);
// Fall back to browser language
return detectBrowserLocale(supportedLocales, defaultLocale);
}
/**
@ -102,13 +102,13 @@ export function getInitialLocale(
* Examples: 'en-us' -> 'en-US', 'pt_BR' -> 'pt-BR'
*/
export function normalizeLocale(locale: string): string {
const parts = locale.replace('_', '-').split('-');
const parts = locale.replace('_', '-').split('-');
if (parts.length === 1) {
return parts[0].toLowerCase();
}
if (parts.length === 1) {
return parts[0].toLowerCase();
}
return `${parts[0].toLowerCase()}-${parts[1].toUpperCase()}`;
return `${parts[0].toLowerCase()}-${parts[1].toUpperCase()}`;
}
/**
@ -116,7 +116,7 @@ export function normalizeLocale(locale: string): string {
* Examples: 'pt-BR' -> 'pt', 'en-US' -> 'en'
*/
export function getBaseLanguage(locale: string): string {
return locale.split('-')[0].toLowerCase();
return locale.split('-')[0].toLowerCase();
}
/**
@ -124,126 +124,120 @@ export function getBaseLanguage(locale: string): string {
* Examples: matchesLanguage('pt-BR', 'pt') -> true
*/
export function matchesLanguage(locale: string, language: string): boolean {
const normalizedLocale = normalizeLocale(locale);
const normalizedLanguage = language.toLowerCase();
const normalizedLocale = normalizeLocale(locale);
const normalizedLanguage = language.toLowerCase();
return (
normalizedLocale === normalizedLanguage ||
getBaseLanguage(normalizedLocale) === normalizedLanguage
);
return (
normalizedLocale === normalizedLanguage ||
getBaseLanguage(normalizedLocale) === normalizedLanguage
);
}
/**
* Find best matching locale from supported list
*/
export function findBestMatch(
preferredLocale: string,
supportedLocales: readonly string[],
defaultLocale: string = 'en'
preferredLocale: string,
supportedLocales: readonly string[],
defaultLocale: string = 'en'
): string {
const normalized = normalizeLocale(preferredLocale);
const normalized = normalizeLocale(preferredLocale);
// Exact match
if (supportedLocales.includes(normalized)) {
return normalized;
}
// Exact match
if (supportedLocales.includes(normalized)) {
return normalized;
}
// Base language match
const base = getBaseLanguage(normalized);
if (supportedLocales.includes(base)) {
return base;
}
// Base language match
const base = getBaseLanguage(normalized);
if (supportedLocales.includes(base)) {
return base;
}
// Find any variant of the same language
const variant = supportedLocales.find(loc => getBaseLanguage(loc) === base);
if (variant) {
return variant;
}
// Find any variant of the same language
const variant = supportedLocales.find((loc) => getBaseLanguage(loc) === base);
if (variant) {
return variant;
}
return defaultLocale;
return defaultLocale;
}
/**
* Format number according to locale
*/
export function formatLocalizedNumber(
value: number,
locale: string = 'en',
options?: Intl.NumberFormatOptions
value: number,
locale: string = 'en',
options?: Intl.NumberFormatOptions
): string {
return new Intl.NumberFormat(locale, options).format(value);
return new Intl.NumberFormat(locale, options).format(value);
}
/**
* Format date according to locale
*/
export function formatLocalizedDate(
date: Date | string | number,
locale: string = 'en',
options?: Intl.DateTimeFormatOptions
date: Date | string | number,
locale: string = 'en',
options?: Intl.DateTimeFormatOptions
): string {
const dateObj = date instanceof Date ? date : new Date(date);
return new Intl.DateTimeFormat(locale, options).format(dateObj);
const dateObj = date instanceof Date ? date : new Date(date);
return new Intl.DateTimeFormat(locale, options).format(dateObj);
}
/**
* Format relative time according to locale
*/
export function formatRelativeTime(
date: Date | string | number,
locale: string = 'en',
style: 'long' | 'short' | 'narrow' = 'long'
date: Date | string | number,
locale: string = 'en',
style: 'long' | 'short' | 'narrow' = 'long'
): string {
const dateObj = date instanceof Date ? date : new Date(date);
const now = new Date();
const diffMs = dateObj.getTime() - now.getTime();
const diffSecs = Math.round(diffMs / 1000);
const diffMins = Math.round(diffSecs / 60);
const diffHours = Math.round(diffMins / 60);
const diffDays = Math.round(diffHours / 24);
const diffWeeks = Math.round(diffDays / 7);
const diffMonths = Math.round(diffDays / 30);
const diffYears = Math.round(diffDays / 365);
const dateObj = date instanceof Date ? date : new Date(date);
const now = new Date();
const diffMs = dateObj.getTime() - now.getTime();
const diffSecs = Math.round(diffMs / 1000);
const diffMins = Math.round(diffSecs / 60);
const diffHours = Math.round(diffMins / 60);
const diffDays = Math.round(diffHours / 24);
const diffWeeks = Math.round(diffDays / 7);
const diffMonths = Math.round(diffDays / 30);
const diffYears = Math.round(diffDays / 365);
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto', style });
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: 'auto', style });
if (Math.abs(diffSecs) < 60) {
return rtf.format(diffSecs, 'second');
} else if (Math.abs(diffMins) < 60) {
return rtf.format(diffMins, 'minute');
} else if (Math.abs(diffHours) < 24) {
return rtf.format(diffHours, 'hour');
} else if (Math.abs(diffDays) < 7) {
return rtf.format(diffDays, 'day');
} else if (Math.abs(diffWeeks) < 4) {
return rtf.format(diffWeeks, 'week');
} else if (Math.abs(diffMonths) < 12) {
return rtf.format(diffMonths, 'month');
} else {
return rtf.format(diffYears, 'year');
}
if (Math.abs(diffSecs) < 60) {
return rtf.format(diffSecs, 'second');
} else if (Math.abs(diffMins) < 60) {
return rtf.format(diffMins, 'minute');
} else if (Math.abs(diffHours) < 24) {
return rtf.format(diffHours, 'hour');
} else if (Math.abs(diffDays) < 7) {
return rtf.format(diffDays, 'day');
} else if (Math.abs(diffWeeks) < 4) {
return rtf.format(diffWeeks, 'week');
} else if (Math.abs(diffMonths) < 12) {
return rtf.format(diffMonths, 'month');
} else {
return rtf.format(diffYears, 'year');
}
}
/**
* Get plural form category
*/
export function getPluralCategory(
count: number,
locale: string = 'en'
): Intl.LDMLPluralRule {
const pr = new Intl.PluralRules(locale);
return pr.select(count);
export function getPluralCategory(count: number, locale: string = 'en'): Intl.LDMLPluralRule {
const pr = new Intl.PluralRules(locale);
return pr.select(count);
}
/**
* Interpolate values into a translation string
* Example: interpolate("Hello {name}!", { name: "World" }) -> "Hello World!"
*/
export function interpolate(
text: string,
values: Record<string, string | number>
): string {
return text.replace(/\{(\w+)\}/g, (match, key) => {
return key in values ? String(values[key]) : match;
});
export function interpolate(text: string, values: Record<string, string | number>): string {
return text.replace(/\{(\w+)\}/g, (match, key) => {
return key in values ? String(values[key]) : match;
});
}

View file

@ -1,19 +1,19 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"types": ["svelte"]
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"noEmit": true,
"types": ["svelte"]
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}