342 lines
16 KiB
TypeScript
342 lines
16 KiB
TypeScript
import { computed, reactive } from 'vue'
|
|
|
|
export type Locale = 'en' | 'ru'
|
|
|
|
type Messages = Record<string, string>
|
|
|
|
const STORAGE_KEY = 'familyhub-locale'
|
|
|
|
const messages: Record<Locale, Messages> = {
|
|
en: {
|
|
'language.english': 'English',
|
|
'language.russian': 'Russian',
|
|
'language.title': 'Language',
|
|
'language.description': 'Choose your app language',
|
|
|
|
'nav.calendar': 'Calendar',
|
|
'nav.finance': 'Finance',
|
|
'nav.home': 'Home',
|
|
'nav.votes': 'Votes',
|
|
'nav.intimacy': 'Intimacy',
|
|
|
|
'header.greeting.night': 'Good night',
|
|
'header.greeting.morning': 'Good morning',
|
|
'header.greeting.afternoon': 'Good afternoon',
|
|
'header.greeting.evening': 'Good evening',
|
|
'header.familyName': 'Anderson Family',
|
|
|
|
'home.balance.total': 'Total Balance',
|
|
'home.balance.income': 'Income',
|
|
'home.balance.expenses': 'Expenses',
|
|
|
|
'home.today.title': 'Today',
|
|
'home.today.events': 'events',
|
|
'home.today.event.familyDinner': 'Family Dinner',
|
|
'home.today.event.movieNight': 'Movie Night',
|
|
'home.today.location.home': 'Home',
|
|
'home.today.location.livingRoom': 'Living Room',
|
|
|
|
'home.activity.title': 'Activity',
|
|
'home.activity.viewAll': 'View all',
|
|
'home.activity.shopping': 'Grocery Shopping',
|
|
'home.activity.shoppingSubtitle': 'Sarah • $124.50',
|
|
'home.activity.movieVote': 'Movie Vote',
|
|
'home.activity.movieVoteSubtitle': '3 votes for "Dune 2"',
|
|
'home.activity.subscription': 'Subscription',
|
|
'home.activity.subscriptionSubtitle': 'Netflix • $15.99',
|
|
'home.activity.newEvent': 'New Event',
|
|
'home.activity.newEventSubtitle': 'Family BBQ Saturday',
|
|
|
|
'home.swipe.title': 'Vote Now',
|
|
'home.swipe.subtitle': 'Swipe to decide',
|
|
'home.swipe.type.food': 'Restaurant',
|
|
'home.swipe.type.movie': 'Movie',
|
|
'home.swipe.card.italian.title': 'Italian Restaurant',
|
|
'home.swipe.card.italian.subtitle': 'Authentic pasta & pizza',
|
|
'home.swipe.card.italian.location': '2.3 km away',
|
|
'home.swipe.card.dune.title': 'Dune: Part Two',
|
|
'home.swipe.card.dune.subtitle': 'Sci-Fi Epic',
|
|
'home.swipe.card.dune.duration': '2h 46m',
|
|
'home.swipe.card.sushi.title': 'Sushi House',
|
|
'home.swipe.card.sushi.subtitle': 'Fresh Japanese cuisine',
|
|
'home.swipe.card.sushi.location': '1.8 km away',
|
|
|
|
'finance.header.eyebrow': 'Family budget',
|
|
'finance.header.title': 'Finance',
|
|
'finance.tab.transactions': 'Transactions',
|
|
'finance.tab.analytics': 'Analytics',
|
|
'finance.tab.categories': 'Categories',
|
|
'finance.balance.total': 'Total Balance',
|
|
'finance.balance.vsLastMonth': 'vs last month',
|
|
'finance.balance.thisMonth': 'This Month',
|
|
'finance.balance.income': 'income',
|
|
'finance.balance.expenses': 'Expenses',
|
|
'finance.balance.saved': 'saved',
|
|
'finance.transactions.today': 'Today',
|
|
'finance.transactions.yesterday': 'Yesterday',
|
|
'finance.transactions.apr1': 'Apr 1',
|
|
'finance.transactions.loading': 'Loading transactions...',
|
|
'finance.transactions.empty': 'No transactions yet',
|
|
'finance.transactions.error': 'Failed to load transactions',
|
|
'finance.transactions.untitled': 'Transaction',
|
|
'finance.category.groceries': 'Groceries',
|
|
'finance.category.foodDining': 'Food & Dining',
|
|
'finance.category.coffee': 'Coffee',
|
|
'finance.category.income': 'Income',
|
|
'finance.category.transport': 'Transport',
|
|
'finance.category.entertainment': 'Entertainment',
|
|
'finance.category.donation': 'Donation',
|
|
'finance.category.housing': 'Housing',
|
|
'finance.analytics.avgIncome': 'Avg. Income',
|
|
'finance.analytics.growth': '+5.2% growth',
|
|
'finance.analytics.avgExpenses': 'Avg. Expenses',
|
|
'finance.analytics.decrease': '-12% decrease',
|
|
'finance.analytics.byCategory': 'Spending by Category',
|
|
'finance.analytics.lastMonths': 'Last 6 Months',
|
|
'finance.analytics.month.oct': 'Oct',
|
|
'finance.analytics.month.nov': 'Nov',
|
|
'finance.analytics.month.dec': 'Dec',
|
|
'finance.analytics.month.jan': 'Jan',
|
|
'finance.analytics.month.feb': 'Feb',
|
|
'finance.analytics.month.mar': 'Mar',
|
|
'finance.analytics.month.income': 'Income',
|
|
'finance.analytics.month.expenses': 'Expenses',
|
|
'finance.analytics.food': 'Food',
|
|
'finance.analytics.transport': 'Transport',
|
|
'finance.analytics.shopping': 'Shopping',
|
|
'finance.analytics.bills': 'Bills',
|
|
'finance.analytics.others': 'Others',
|
|
'finance.categories.foodDining': 'Food & Dining',
|
|
'finance.categories.shopping': 'Shopping',
|
|
'finance.categories.transport': 'Transport',
|
|
'finance.categories.housing': 'Housing',
|
|
'finance.categories.entertainment': 'Entertainment',
|
|
'finance.categories.coffee': 'Coffee',
|
|
'finance.categories.billsUtilities': 'Bills & Utilities',
|
|
'finance.categories.work': 'Work',
|
|
'finance.categories.giftsDonations': 'Gifts & Donations',
|
|
'finance.categories.others': 'Others',
|
|
'finance.categories.of': 'of',
|
|
|
|
'settings.header.eyebrow': 'Manage your family hub',
|
|
'settings.header.title': 'Settings',
|
|
'settings.profile.role': 'Family Admin',
|
|
'settings.section.family': 'Family',
|
|
'settings.section.customization': 'Customization',
|
|
'settings.section.activeModules': 'Active Modules',
|
|
'settings.section.privacy': 'Privacy & Security',
|
|
'settings.section.advanced': 'Advanced',
|
|
'settings.family.members.label': 'Family Members',
|
|
'settings.family.members.description': 'Manage family access',
|
|
'settings.family.roles.label': 'Roles & Permissions',
|
|
'settings.family.roles.description': 'Control what members can do',
|
|
'settings.customization.widgets.label': 'Dashboard Widgets',
|
|
'settings.customization.widgets.description': 'Customize your home screen',
|
|
'settings.customization.theme.label': 'Theme & Appearance',
|
|
'settings.customization.theme.description': 'Dark mode, colors, fonts',
|
|
'settings.privacy.label': 'Privacy Settings',
|
|
'settings.privacy.description': 'Control data sharing',
|
|
'settings.visibility.label': 'Visibility Controls',
|
|
'settings.visibility.description': 'Who can see what',
|
|
'settings.security.label': 'Security',
|
|
'settings.security.description': 'Password, 2FA, biometrics',
|
|
'settings.notifications.label': 'Notifications',
|
|
'settings.notifications.description': 'Push, email, SMS settings',
|
|
'settings.preferences.label': 'App Preferences',
|
|
'settings.preferences.description': 'Language, timezone, units',
|
|
'settings.module.finance': 'Finance Tracking',
|
|
'settings.module.calendar': 'Family Calendar',
|
|
'settings.module.food': 'Food Voting',
|
|
'settings.module.movies': 'Movie Voting',
|
|
'settings.module.activities': 'Activity Feed',
|
|
'settings.module.active': 'Active',
|
|
'settings.module.disabled': 'Disabled',
|
|
'settings.signOut': 'Sign Out',
|
|
},
|
|
ru: {
|
|
'language.english': 'Английский',
|
|
'language.russian': 'Русский',
|
|
'language.title': 'Язык',
|
|
'language.description': 'Выберите язык приложения',
|
|
|
|
'nav.calendar': 'Календарь',
|
|
'nav.finance': 'Финансы',
|
|
'nav.home': 'Главная',
|
|
'nav.votes': 'Голосования',
|
|
'nav.intimacy': 'Близость',
|
|
|
|
'header.greeting.night': 'Доброй ночи',
|
|
'header.greeting.morning': 'Доброе утро',
|
|
'header.greeting.afternoon': 'Добрый день',
|
|
'header.greeting.evening': 'Добрый вечер',
|
|
'header.familyName': 'Семья Андерсон',
|
|
|
|
'home.balance.total': 'Общий баланс',
|
|
'home.balance.income': 'Доходы',
|
|
'home.balance.expenses': 'Расходы',
|
|
|
|
'home.today.title': 'Сегодня',
|
|
'home.today.events': 'события',
|
|
'home.today.event.familyDinner': 'Семейный ужин',
|
|
'home.today.event.movieNight': 'Киновечер',
|
|
'home.today.location.home': 'Дом',
|
|
'home.today.location.livingRoom': 'Гостиная',
|
|
|
|
'home.activity.title': 'Активность',
|
|
'home.activity.viewAll': 'Смотреть все',
|
|
'home.activity.shopping': 'Покупка продуктов',
|
|
'home.activity.shoppingSubtitle': 'Сара • $124.50',
|
|
'home.activity.movieVote': 'Голосование за фильм',
|
|
'home.activity.movieVoteSubtitle': '3 голоса за "Дюна 2"',
|
|
'home.activity.subscription': 'Подписка',
|
|
'home.activity.subscriptionSubtitle': 'Netflix • $15.99',
|
|
'home.activity.newEvent': 'Новое событие',
|
|
'home.activity.newEventSubtitle': 'Семейное барбекю в субботу',
|
|
|
|
'home.swipe.title': 'Голосуйте',
|
|
'home.swipe.subtitle': 'Свайпните, чтобы выбрать',
|
|
'home.swipe.type.food': 'Ресторан',
|
|
'home.swipe.type.movie': 'Фильм',
|
|
'home.swipe.card.italian.title': 'Итальянский ресторан',
|
|
'home.swipe.card.italian.subtitle': 'Аутентичная паста и пицца',
|
|
'home.swipe.card.italian.location': '2.3 км отсюда',
|
|
'home.swipe.card.dune.title': 'Дюна: Часть вторая',
|
|
'home.swipe.card.dune.subtitle': 'Научно-фантастический эпик',
|
|
'home.swipe.card.dune.duration': '2 ч 46 мин',
|
|
'home.swipe.card.sushi.title': 'Суши Хаус',
|
|
'home.swipe.card.sushi.subtitle': 'Свежая японская кухня',
|
|
'home.swipe.card.sushi.location': '1.8 км отсюда',
|
|
|
|
'finance.header.eyebrow': 'Семейный бюджет',
|
|
'finance.header.title': 'Финансы',
|
|
'finance.tab.transactions': 'Транзакции',
|
|
'finance.tab.analytics': 'Аналитика',
|
|
'finance.tab.categories': 'Категории',
|
|
'finance.balance.total': 'Общий баланс',
|
|
'finance.balance.vsLastMonth': 'по сравнению с прошлым месяцем',
|
|
'finance.balance.thisMonth': 'Этот месяц',
|
|
'finance.balance.income': 'доход',
|
|
'finance.balance.expenses': 'Расходы',
|
|
'finance.balance.saved': 'сэкономлено',
|
|
'finance.transactions.today': 'Сегодня',
|
|
'finance.transactions.yesterday': 'Вчера',
|
|
'finance.transactions.apr1': '1 апр',
|
|
'finance.transactions.loading': 'Загрузка транзакций...',
|
|
'finance.transactions.empty': 'Транзакций пока нет',
|
|
'finance.transactions.error': 'Не удалось загрузить транзакции',
|
|
'finance.transactions.untitled': 'Транзакция',
|
|
'finance.category.groceries': 'Продукты',
|
|
'finance.category.foodDining': 'Еда и рестораны',
|
|
'finance.category.coffee': 'Кофе',
|
|
'finance.category.income': 'Доход',
|
|
'finance.category.transport': 'Транспорт',
|
|
'finance.category.entertainment': 'Развлечения',
|
|
'finance.category.donation': 'Пожертвование',
|
|
'finance.category.housing': 'Жильё',
|
|
'finance.analytics.avgIncome': 'Средний доход',
|
|
'finance.analytics.growth': '+5.2% рост',
|
|
'finance.analytics.avgExpenses': 'Средние расходы',
|
|
'finance.analytics.decrease': '-12% снижение',
|
|
'finance.analytics.byCategory': 'Расходы по категориям',
|
|
'finance.analytics.lastMonths': 'Последние 6 месяцев',
|
|
'finance.analytics.month.oct': 'Окт',
|
|
'finance.analytics.month.nov': 'Ноя',
|
|
'finance.analytics.month.dec': 'Дек',
|
|
'finance.analytics.month.jan': 'Янв',
|
|
'finance.analytics.month.feb': 'Фев',
|
|
'finance.analytics.month.mar': 'Мар',
|
|
'finance.analytics.month.income': 'Доход',
|
|
'finance.analytics.month.expenses': 'Расходы',
|
|
'finance.analytics.food': 'Еда',
|
|
'finance.analytics.transport': 'Транспорт',
|
|
'finance.analytics.shopping': 'Покупки',
|
|
'finance.analytics.bills': 'Счета',
|
|
'finance.analytics.others': 'Прочее',
|
|
'finance.categories.foodDining': 'Еда и рестораны',
|
|
'finance.categories.shopping': 'Покупки',
|
|
'finance.categories.transport': 'Транспорт',
|
|
'finance.categories.housing': 'Жильё',
|
|
'finance.categories.entertainment': 'Развлечения',
|
|
'finance.categories.coffee': 'Кофе',
|
|
'finance.categories.billsUtilities': 'Счета и коммунальные',
|
|
'finance.categories.work': 'Работа',
|
|
'finance.categories.giftsDonations': 'Подарки и пожертвования',
|
|
'finance.categories.others': 'Прочее',
|
|
'finance.categories.of': 'из',
|
|
|
|
'settings.header.eyebrow': 'Управляйте семейным хабом',
|
|
'settings.header.title': 'Настройки',
|
|
'settings.profile.role': 'Администратор семьи',
|
|
'settings.section.family': 'Семья',
|
|
'settings.section.customization': 'Кастомизация',
|
|
'settings.section.activeModules': 'Активные модули',
|
|
'settings.section.privacy': 'Конфиденциальность и защита',
|
|
'settings.section.advanced': 'Дополнительно',
|
|
'settings.family.members.label': 'Члены семьи',
|
|
'settings.family.members.description': 'Управление доступом семьи',
|
|
'settings.family.roles.label': 'Роли и разрешения',
|
|
'settings.family.roles.description': 'Контроль возможностей участников',
|
|
'settings.customization.widgets.label': 'Виджеты дашборда',
|
|
'settings.customization.widgets.description': 'Настройте главный экран',
|
|
'settings.customization.theme.label': 'Тема и внешний вид',
|
|
'settings.customization.theme.description': 'Тёмная тема, цвета, шрифты',
|
|
'settings.privacy.label': 'Настройки приватности',
|
|
'settings.privacy.description': 'Управление обменом данными',
|
|
'settings.visibility.label': 'Параметры видимости',
|
|
'settings.visibility.description': 'Кто что может видеть',
|
|
'settings.security.label': 'Безопасность',
|
|
'settings.security.description': 'Пароль, 2FA, биометрия',
|
|
'settings.notifications.label': 'Уведомления',
|
|
'settings.notifications.description': 'Push, email, SMS настройки',
|
|
'settings.preferences.label': 'Параметры приложения',
|
|
'settings.preferences.description': 'Язык, часовой пояс, единицы',
|
|
'settings.module.finance': 'Учёт финансов',
|
|
'settings.module.calendar': 'Семейный календарь',
|
|
'settings.module.food': 'Голосование за еду',
|
|
'settings.module.movies': 'Голосование за фильмы',
|
|
'settings.module.activities': 'Лента активности',
|
|
'settings.module.active': 'Активен',
|
|
'settings.module.disabled': 'Отключён',
|
|
'settings.signOut': 'Выйти',
|
|
},
|
|
}
|
|
|
|
function detectLocale(): Locale {
|
|
if (typeof window === 'undefined') {
|
|
return 'en'
|
|
}
|
|
|
|
const stored = window.localStorage.getItem(STORAGE_KEY)
|
|
if (stored === 'en' || stored === 'ru') {
|
|
return stored
|
|
}
|
|
|
|
const browserLocale = window.navigator.language.toLowerCase()
|
|
return browserLocale.startsWith('ru') ? 'ru' : 'en'
|
|
}
|
|
|
|
const state = reactive({
|
|
locale: detectLocale() as Locale,
|
|
})
|
|
|
|
export function setLocale(locale: Locale) {
|
|
state.locale = locale
|
|
if (typeof window !== 'undefined') {
|
|
window.localStorage.setItem(STORAGE_KEY, locale)
|
|
}
|
|
}
|
|
|
|
export function useI18n() {
|
|
const locale = computed(() => state.locale)
|
|
|
|
function t(key: string): string {
|
|
return messages[state.locale][key] ?? messages.en[key] ?? key
|
|
}
|
|
|
|
return {
|
|
locale,
|
|
setLocale,
|
|
t,
|
|
}
|
|
}
|