schon/storefront/app/utils/transliterator.ts
Alexandr SaVBaD Waltz 2ea18eb8a6 feat(storefront): refactor i18n and cart/wishlist handling for improved user experience
Refactored i18n configuration, replacing `DEFAULT_LOCALE` with `DEFAULT_LOCALE_FALLBACK` and enhancing environment-based locale validation. Improved cookie persistence for cart and wishlist, ensuring fallback handling for unauthenticated users.

Enhancements:
- Added `createProjectKey` utility for consistent project key generation.
- Reworked cart and wishlist composables (`useOrderOverwrite`, `useWishlistOverwrite`) to decouple product identifier and handle cookies robustly.
- Centralized `DEFAULT_LOCALE` logic for better maintainability.
- Refined `useOrderSync` and `useWishlistSync` for clean synchronization across auth states.
- Updated SCSS in hero and header styles for alignment corrections.

Breaking Changes: `DEFAULT_LOCALE` constant removed; replaced with runtime config and fallback logic. Consumers must adapt to `DEFAULT_LOCALE_FALLBACK` and `$appHelpers.DEFAULT_LOCALE`.
2026-02-28 22:38:45 +03:00

99 lines
No EOL
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export function transliterate(str: string | undefined): string {
if (!str) return '';
const map = {
// Russian/Ukrainian/Belarusian Cyrillic
'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Е': 'E', 'Ё': 'Yo', 'Ж': 'Zh',
'З': 'Z', 'И': 'I', 'Й': 'Y', 'К': 'K', 'Л': 'L', 'М': 'M', 'Н': 'N', 'О': 'O',
'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'У': 'U', 'Ф': 'F', 'Х': 'Kh', 'Ц': 'Ts',
'Ч': 'Ch', 'Ш': 'Sh', 'Щ': 'Shch', 'Ъ': '', 'Ы': 'Y', 'Ь': '', 'Э': 'E', 'Ю': 'Yu',
'Я': 'Ya',
'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'е': 'e', 'ё': 'yo', 'ж': 'zh',
'з': 'z', 'и': 'i', 'й': 'y', 'к': 'k', 'л': 'l', 'м': 'm', 'н': 'n', 'о': 'o',
'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'у': 'u', 'ф': 'f', 'х': 'kh', 'ц': 'ts',
'ч': 'ch', 'ш': 'sh', 'щ': 'shch', 'ъ': '', 'ы': 'y', 'ь': '', 'э': 'e', 'ю': 'yu',
'я': 'ya',
// Ukrainian extras
'Ґ': 'G', 'ґ': 'g', 'Є': 'Ye', 'є': 'ye', 'І': 'I', 'і': 'i', 'Ї': 'Yi', 'ї': 'yi',
// Serbian/Macedonian Cyrillic extras
'Ђ': 'Dj', 'ђ': 'dj', 'Ј': 'J', 'ј': 'j', 'Љ': 'Lj', 'љ': 'lj', 'Њ': 'Nj', 'њ': 'nj',
'Ћ': 'C', 'ћ': 'c', 'Џ': 'Dz', 'џ': 'dz', 'Ѓ': 'Gj', 'ѓ': 'gj', 'Ѕ': 'Dz', 'ѕ': 'dz',
'Ќ': 'Kj', 'ќ': 'kj',
// Belarusian extras
'Ў': 'U', 'ў': 'u',
// Bulgarian extras (mostly covered above, but ъ is different)
// In Bulgarian context ъ = 'a', but we keep '' as default for Russian
// Greek
'Α': 'A', 'Β': 'V', 'Γ': 'G', 'Δ': 'D', 'Ε': 'E', 'Ζ': 'Z', 'Η': 'I', 'Θ': 'Th',
'Ι': 'I', 'Κ': 'K', 'Λ': 'L', 'Μ': 'M', 'Ν': 'N', 'Ξ': 'X', 'Ο': 'O', 'Π': 'P',
'Ρ': 'R', 'Σ': 'S', 'Τ': 'T', 'Υ': 'Y', 'Φ': 'F', 'Χ': 'Ch', 'Ψ': 'Ps', 'Ω': 'O',
'α': 'a', 'β': 'v', 'γ': 'g', 'δ': 'd', 'ε': 'e', 'ζ': 'z', 'η': 'i', 'θ': 'th',
'ι': 'i', 'κ': 'k', 'λ': 'l', 'μ': 'm', 'ν': 'n', 'ξ': 'x', 'ο': 'o', 'π': 'p',
'ρ': 'r', 'σ': 's', 'ς': 's', 'τ': 't', 'υ': 'y', 'φ': 'f', 'χ': 'ch', 'ψ': 'ps', 'ω': 'o',
// Arabic
'ا': 'a', 'ب': 'b', 'ت': 't', 'ث': 'th', 'ج': 'j', 'ح': 'h', 'خ': 'kh', 'د': 'd',
'ذ': 'dh', 'ر': 'r', 'ز': 'z', 'س': 's', 'ش': 'sh', 'ص': 's', 'ض': 'd', 'ط': 't',
'ظ': 'z', 'ع': 'a', 'غ': 'gh', 'ف': 'f', 'ق': 'q', 'ك': 'k', 'ل': 'l', 'م': 'm',
'ن': 'n', 'ه': 'h', 'و': 'w', 'ي': 'y', 'ة': 'h', 'ء': '\'', 'آ': 'aa',
// German/Nordic/Central European diacritics
'Ä': 'Ae', 'ä': 'ae', 'Ö': 'Oe', 'ö': 'oe', 'Ü': 'Ue', 'ü': 'ue', 'ß': 'ss',
'Å': 'A', 'å': 'a', 'Æ': 'Ae', 'æ': 'ae', 'Ø': 'O', 'ø': 'o',
'Ð': 'D', 'ð': 'd', 'Þ': 'Th', 'þ': 'th',
// Czech/Slovak/Polish/Hungarian/Romanian/Turkish
'Č': 'C', 'č': 'c', 'Ď': 'D', 'ď': 'd', 'Ě': 'E', 'ě': 'e', 'Ň': 'N', 'ň': 'n',
'Ř': 'R', 'ř': 'r', 'Š': 'S', 'š': 's', 'Ť': 'T', 'ť': 't', 'Ů': 'U', 'ů': 'u',
'Ž': 'Z', 'ž': 'z', 'Ľ': 'L', 'ľ': 'l', 'Ĺ': 'L', 'ĺ': 'l', 'Ŕ': 'R', 'ŕ': 'r',
'Ą': 'A', 'ą': 'a', 'Ć': 'C', 'ć': 'c', 'Ę': 'E', 'ę': 'e', 'Ł': 'L', 'ł': 'l',
'Ń': 'N', 'ń': 'n', 'Ś': 'S', 'ś': 's', 'Ź': 'Z', 'ź': 'z', 'Ż': 'Z', 'ż': 'z',
'Á': 'A', 'á': 'a', 'É': 'E', 'é': 'e', 'Í': 'I', 'í': 'i', 'Ó': 'O', 'ó': 'o',
'Ú': 'U', 'ú': 'u', 'Ý': 'Y', 'ý': 'y',
'Ő': 'O', 'ő': 'o', 'Ű': 'U', 'ű': 'u',
'Ă': 'A', 'ă': 'a', 'Â': 'A', 'â': 'a', 'Î': 'I', 'î': 'i', 'Ș': 'S', 'ș': 's', 'Ț': 'T', 'ț': 't',
'Ç': 'C', 'ç': 'c', 'Ğ': 'G', 'ğ': 'g', 'İ': 'I', 'ı': 'i', 'Ş': 'S', 'ş': 's',
// Vietnamese (basic - stripped of tone marks conceptually)
'Đ': 'D', 'đ': 'd',
// Spanish/Portuguese/French
'Ñ': 'N', 'ñ': 'n',
'À': 'A', 'à': 'a', 'È': 'E', 'è': 'e', 'Ì': 'I', 'ì': 'i', 'Ò': 'O', 'ò': 'o',
'Ù': 'U', 'ù': 'u', 'Ë': 'E', 'ë': 'e', 'Ï': 'I', 'ï': 'i',
'Ê': 'E', 'ê': 'e', 'Ô': 'O', 'ô': 'o', 'Û': 'U', 'û': 'u',
'Ã': 'A', 'ã': 'a', 'Õ': 'O', 'õ': 'o',
};
return str.split('').map(ch => {
if (ch in map) return map[ch];
const normalized = ch
.normalize('NFD')
.replace(/[\u0300-\u036f]/g, '');
if (normalized !== ch && /^[\x20-\x7E]+$/.test(normalized)) {
return normalized;
}
return ch;
}).join('');
}
export function createProjectKey(str: string | undefined): string {
if (!str) return 'default-project';
return transliterate(str)
.toLowerCase()
.replace(/['"]/g, '')
.replace(/[^a-z0-9\s-]/g, '')
.trim()
.replace(/\s+/g, '-')
.replace(/-+/g, '-');
}