812 lines
32 KiB
TypeScript
812 lines
32 KiB
TypeScript
import { create } from 'zustand';
|
||
|
||
export type Lang = 'ru' | 'en';
|
||
|
||
const LANG_KEY = 'knot_language';
|
||
|
||
const translations = {
|
||
ru: {
|
||
// Side menu
|
||
myProfile: 'Мой профиль',
|
||
settings: 'Настройки',
|
||
aboutApp: 'О приложении',
|
||
logout: 'Выйти из аккаунта',
|
||
// Profile
|
||
name: 'Имя',
|
||
username: 'Имя пользователя',
|
||
chats: 'Чаты',
|
||
calls: 'Звонки',
|
||
contacts: 'Контакты',
|
||
archive: 'Архив',
|
||
aboutMe: 'О себе',
|
||
birthday: 'Дата рождения',
|
||
enterName: 'Введите имя',
|
||
tellAboutYourself: 'Расскажите о себе',
|
||
removePhoto: 'Удалить фото',
|
||
cropPhoto: 'Обрезать фото',
|
||
saveChanges: 'Сохранить изменения',
|
||
displayName: 'Отображаемое имя',
|
||
// Settings
|
||
language: 'Язык / Language',
|
||
interfaceLang: 'Язык интерфейса',
|
||
theme: 'Оформление',
|
||
russian: 'Русский',
|
||
english: 'English',
|
||
about: 'О приложении',
|
||
version: 'Версия',
|
||
modernMessenger: 'Современный мессенджер с фокусом',
|
||
onPrivacy: 'на приватность и удобство',
|
||
modernMessengerShort: 'Современный мессенджер',
|
||
settingsDesc: 'Управляйте своим профилем и настройками приложения',
|
||
appSettings: 'Настройки приложения',
|
||
enterDisplayName: 'Как вас называть?',
|
||
tellAboutBio: 'Расскажите немного о себе...',
|
||
storageAndData: 'Хранилище и данные',
|
||
importTelegram: 'Импорт истории Telegram',
|
||
importTelegramDesc: 'Перенести сообщения и медиа из Telegram',
|
||
importSuccess: 'Импорт завершен',
|
||
importStarted: 'Импорт запущен в фоновом режиме',
|
||
importSelectArchive: 'Загрузите архив',
|
||
importSelectArchiveDesc: 'Экспортируйте чат из Telegram (HTML формат, вкл. медиа) и загрузите полученный ZIP архив.',
|
||
importLimit: 'Лимит: до 1 ГБ',
|
||
importSelectFile: 'Выбрать ZIP-архив',
|
||
importParticipants: 'Соответствие участников',
|
||
importParticipantsDesc: 'Назначьте участников из архива пользователям в Knot.',
|
||
importInArchive: 'В архиве',
|
||
importSelectContact: '-- Выберите контакт --',
|
||
importGroupName: 'Название чата',
|
||
importGroupNameHint: 'Например, Моя группа',
|
||
importStart: 'Запустить импорт',
|
||
importRestart: 'Начать заново',
|
||
importCompletedDesc: 'Мы успешно создали чат и начали перенос сообщений в фоновом режиме.',
|
||
// Chat
|
||
chat: 'Чат',
|
||
group: 'Группа',
|
||
searchChats: 'Поиск чатов...',
|
||
noChats: 'Нет чатов — создайте первый!',
|
||
nothingFound: 'Ничего не найдено',
|
||
selectChat: 'Выберите чат для начала общения',
|
||
selectChatTitle: 'Выберите чат',
|
||
selectChatSubtext: 'Начните общение прямо сейчас. Все ваши сообщения защищены сквозным шифрованием.',
|
||
newMessage: 'Новое сообщение',
|
||
noMessages: 'Нет сообщений — напишите первое!',
|
||
typing: 'печатает...',
|
||
online: 'в сети',
|
||
wasRecently: 'был(а) недавно',
|
||
members: 'участников',
|
||
files: 'файлов',
|
||
clearAll: 'Очистить всё',
|
||
maxFilesLimit: 'Максимум 20 файлов',
|
||
searchingHistory: 'Поиск сообщения в истории...',
|
||
messageNotFound: 'Сообщение не найдено',
|
||
messagePlaceholder: 'Сообщение...',
|
||
message: 'Сообщение...',
|
||
addCaption: 'Добавьте подпись...',
|
||
searchMessages: 'Поиск сообщений...',
|
||
searchMessagesBtn: 'Поиск сообщений',
|
||
userProfile: 'Профиль пользователя',
|
||
userProfileUpper: 'ПРОФИЛЬ ПОЛЬЗОВАТЕЛЯ',
|
||
enableSound: 'Включить звук',
|
||
disableSound: 'Выключить звук',
|
||
deleteChat: 'Удалить чат',
|
||
// Messages
|
||
messageDeleted: 'Сообщение удалено',
|
||
reply: 'Ответить',
|
||
copy: 'Копировать',
|
||
edit: 'Редактировать',
|
||
delete: 'Удалить',
|
||
deleteForMe: 'Удалить у меня',
|
||
deleteForAll: 'Удалить у всех',
|
||
deleteAlsoFor: 'Удалить также для',
|
||
editing: 'Редактирование',
|
||
replyTo: 'Ответ',
|
||
media: 'Медиа',
|
||
download: 'Скачать',
|
||
edited: 'ред.',
|
||
selected: 'выбрано',
|
||
fileLabel: 'Файл',
|
||
kb: 'КБ',
|
||
voice: '🎤 Голосовое',
|
||
photo: '🖼 Фото',
|
||
video: '🎬 Видео',
|
||
file: 'Файл',
|
||
// Call
|
||
call: 'Звонок',
|
||
videoCall: 'Видеозвонок',
|
||
incomingCall: 'Входящий звонок',
|
||
incomingVideoCall: 'Входящий видеозвонок',
|
||
calling: 'Вызов...',
|
||
isCalling: 'звонит...',
|
||
groupCall: 'Групповой звонок',
|
||
comingSoon: 'Скоро будет',
|
||
accept: 'Принять',
|
||
decline: 'Отклонить',
|
||
endCall: 'Завершить',
|
||
callEnded: 'Звонок завершён',
|
||
callDeclined: 'Звонок отклонён',
|
||
audioCall: 'Голосовой звонок',
|
||
missedCall: 'Пропущенный звонок',
|
||
declinedCall: 'Отклонённый звонок',
|
||
cancelledCall: 'Отменённый звонок',
|
||
completedCall: 'Вызов завершён',
|
||
// Photo/video
|
||
photoVideo: 'Фото / видео',
|
||
fileBtn: 'Файл',
|
||
sendError: 'Ошибка отправки',
|
||
// New chat
|
||
newChat: 'Новый чат',
|
||
add: 'Добавить',
|
||
menu: 'Меню',
|
||
// Date picker
|
||
months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
|
||
weekDays: ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'],
|
||
clear: 'Очистить',
|
||
today: 'Сегодня',
|
||
// New chat
|
||
newChatTitle: 'Новый чат',
|
||
selectMembers: 'Выберите участников',
|
||
newGroup: 'Новая группа',
|
||
groupNamePlaceholder: 'Название группы...',
|
||
membersCount: 'Участники',
|
||
createGroup: 'Создать группу',
|
||
upTo200: 'До 200 участников',
|
||
findUser: 'Найти пользователя по имени или @username...',
|
||
addMembers: 'Добавить участников...',
|
||
usersNotFound: 'Пользователи не найдены',
|
||
enterNameOrUsername: 'Введите имя или @username',
|
||
next: 'Далее',
|
||
pinMessage: 'Закрепить',
|
||
unpinMessage: 'Открепить',
|
||
pinnedMessage: 'Закреплённое сообщение',
|
||
poll: 'Опрос',
|
||
pollTab: 'Опросы',
|
||
createPoll: 'Создать опрос',
|
||
pollQuestion: 'Вопрос',
|
||
pollQuestionPlaceholder: 'Задайте вопрос...',
|
||
pollOptions: 'Варианты ответа',
|
||
pollOption: 'Вариант',
|
||
addOption: 'Добавить вариант',
|
||
pollSettings: 'Настройки',
|
||
anonymousVoting: 'Анонимное голосование',
|
||
multipleAnswers: 'Выбор нескольких вариантов',
|
||
singleAnswer: 'Одиночный выбор',
|
||
anonymous: 'Анонимно',
|
||
votes: 'голосов',
|
||
pollButton: 'Опрос',
|
||
forwardMessage: 'Переслать сообщение',
|
||
forward: 'Переслать',
|
||
forwardedFrom: 'Переслано от',
|
||
replyWithQuote: 'Ответить с цитатой',
|
||
select: 'Выбрать',
|
||
sending: 'Отправка...',
|
||
scheduleMessage: 'Запланировать',
|
||
scheduleSend: 'Отправить по расписанию',
|
||
scheduled: 'Запланировано',
|
||
myStory: 'Моя история',
|
||
newStory: 'Новая история',
|
||
textStory: 'Текст',
|
||
imageStory: 'Фото',
|
||
mediaStory: 'Медиа',
|
||
typeYourStory: 'Напишите историю...',
|
||
publishStory: 'Опубликовать',
|
||
stories: 'Истории',
|
||
clearChat: 'Очистить чат',
|
||
clearChatConfirm: 'Очистить историю чата для себя? Собеседник сохранит свою историю.',
|
||
clearHistory: 'Очистить историю',
|
||
clearHistoryConfirm: 'Очистить историю?',
|
||
deleteChatConfirm: 'Удалить чат? Это действие нельзя отменить.',
|
||
pinChat: 'Закрепить чат',
|
||
unpinChat: 'Открепить чат',
|
||
chatCleared: 'Очищено',
|
||
typeYourStoryPlaceholder: 'Напишите историю...',
|
||
uploadMedia: 'Загрузить медиа',
|
||
chooseBackground: 'Цвет фона',
|
||
viewedBy: 'Просмотрели',
|
||
storyDetails: 'Информация',
|
||
viewCountSuffix: 'посмотрели эту историю',
|
||
storyPrivacyNote: 'Истории зашифрованы и исчезнут через 24 часа. Сообщения о прочтении видны только автору.',
|
||
storiesEditor: 'Редактор историй',
|
||
tools: 'Инструменты',
|
||
privacyNote: 'Выберите, кто может просматривать вашу новую историю.',
|
||
allUsers: 'Все пользователи',
|
||
onlyContacts: 'Только контакты',
|
||
selectedContacts: 'Выбранные контакты',
|
||
yourStory: 'Ваша история',
|
||
stickers: 'Стикеры',
|
||
brush: 'Кисть',
|
||
filters: 'Фильтры',
|
||
report: 'Пожаловаться',
|
||
groupSettings: 'Настройки группы',
|
||
editGroupName: 'Изменить название',
|
||
addMember: 'Добавить участника',
|
||
removeMember: 'Удалить из группы',
|
||
leaveGroup: 'Покинуть группу',
|
||
adminBadge: 'Админ',
|
||
groupDescription: 'Описание',
|
||
noDescription: 'Нет описания',
|
||
memberBadge: 'Участник',
|
||
screenShare: 'Демонстрация экрана',
|
||
stopScreenShare: 'Остановить демонстрацию',
|
||
switchCamera: 'Выбрать камеру',
|
||
showInChat: 'Показать в чате',
|
||
minimize: 'Свернуть',
|
||
volume: 'Громкость',
|
||
mute: 'Выключить микрофон',
|
||
unmute: 'Включить микрофон',
|
||
noiseSuppressionOn: 'Шумоподавление включено',
|
||
noiseSuppressionOff: 'Шумоподавление выключено',
|
||
selectMicrophone: 'Выбрать микрофон',
|
||
microphone: 'Микрофон',
|
||
rightClickVolume: 'ПКМ для регулировки громкости',
|
||
participants: 'участников',
|
||
joinCall: 'Присоединиться к звонку',
|
||
activeCall: 'Активный звонок',
|
||
groupNameRequired: 'Введите название группы',
|
||
confirmRemoveMember: 'Удалить этого участника из группы?',
|
||
yes: 'Да',
|
||
no: 'Нет',
|
||
you: 'вы',
|
||
// Stories Editor
|
||
cropVideo: 'Обрезка видео',
|
||
cropTool: 'Обрезка',
|
||
trimVideo: 'Обрезать видео',
|
||
trim: 'Обрезать',
|
||
reset: 'Сбросить',
|
||
startCreation: 'Начать создание',
|
||
brushTool: 'Кисти',
|
||
textTool: 'Текст',
|
||
stickersTool: 'Стикеры',
|
||
filtersTool: 'Коррекция',
|
||
textContent: 'Контент',
|
||
typography: 'Типографика',
|
||
textSize: 'Размер',
|
||
textColor: 'Цвет текста',
|
||
brushThickness: 'Толщина',
|
||
clearCanvas: 'Очистить холст',
|
||
correctionMaster: 'Мастер коррекции',
|
||
brightness: 'Яркость',
|
||
contrast: 'Контраст',
|
||
saturation: 'Насыщенность',
|
||
sepia: 'Сепия',
|
||
bgColor: 'Цвет фона',
|
||
clickToChooseColor: 'Нажмите для выбора цвета',
|
||
done: 'Готово',
|
||
stop: 'Остановить',
|
||
zoomHint: 'Колесико мыши для зума',
|
||
secSelected: 'сек выбрано',
|
||
muted: 'Без звука',
|
||
unmuted: 'Со звуком',
|
||
muteVideo: 'Отключить звук',
|
||
unmuteVideo: 'Включить звук',
|
||
interactive: 'Интерактив',
|
||
apply: 'Применить',
|
||
zoom: 'Масштаб',
|
||
rotation: 'Поворот',
|
||
// User profile
|
||
mediaTab: 'Медиа',
|
||
gifs: 'GIF',
|
||
filesTab: 'Файлы',
|
||
linksTab: 'Ссылки',
|
||
profileTitle: 'Профиль',
|
||
removeAvatar: 'Удалить аватар',
|
||
namePlaceholder: 'Имя',
|
||
notSpecified: 'Не указано',
|
||
onKnotSince: 'На Knot с',
|
||
joined: 'С нами с',
|
||
cancel: 'Отмена',
|
||
confirm: 'Подтвердить',
|
||
save: 'Сохранить',
|
||
sharedPhotos: 'Общие фото и видео будут здесь',
|
||
sharedFiles: 'Общие файлы будут здесь',
|
||
sharedLinks: 'Общие ссылки будут здесь',
|
||
profileNotFound: 'Профиль не найден',
|
||
storiesTab: 'Истории',
|
||
publicationsTab: 'Публикации',
|
||
noStories: 'Публикаций пока нет',
|
||
noBio: 'Информация отсутствует',
|
||
goToMessage: 'Перейти к сообщению',
|
||
story: 'История',
|
||
commonGroups: 'Общие группы',
|
||
more: 'Ещё',
|
||
empty: 'Пусто',
|
||
acceptRequest: 'Принять запрос',
|
||
// Typing
|
||
typingText: 'печатает',
|
||
// Emoji
|
||
emojiFrequent: 'Часто',
|
||
emojiGestures: 'Жесты',
|
||
emojiEmotions: 'Эмоции',
|
||
emojiObjects: 'Предметы',
|
||
emojiFood: 'Еда',
|
||
emojiNature: 'Природа',
|
||
// Auth
|
||
login: 'Вход',
|
||
register: 'Регистрация',
|
||
latinOnly: '(латиница, нельзя изменить)',
|
||
displayNameLabel: 'Отображаемое имя',
|
||
displayNamePlaceholder: 'Ваше имя (любой язык)',
|
||
password: 'Пароль',
|
||
passwordPlaceholder: 'Введите пароль',
|
||
bioPlaceholder: 'Расскажите о себе (необязательно)',
|
||
loginBtn: 'Войти',
|
||
createAccount: 'Создать аккаунт',
|
||
testAccounts: 'Тестовые аккаунты: evgeniy, anastasia, artem, polina',
|
||
passwordForAll: 'Пароль для всех:',
|
||
dontHaveAccount: 'Нет аккаунта?',
|
||
alreadyHaveAccount: 'Уже есть аккаунт?',
|
||
passwordRequirements: 'Минимум 8 символов, буквы и цифры',
|
||
registerNow: 'Зарегистрироваться',
|
||
loginNow: 'Войти',
|
||
// File/upload
|
||
fileTooLarge: 'Файл слишком большой (макс. 200МБ)',
|
||
dropFileHere: 'Отпустите файл здесь',
|
||
uploading: 'Загрузка...',
|
||
uploadError: 'Ошибка загрузки файла',
|
||
changePhoto: 'Сменить фото',
|
||
remove: 'Удалить',
|
||
// Formatting
|
||
formatBold: 'Жирный',
|
||
formatBoldHint: '**текст**',
|
||
formatItalic: 'Курсив',
|
||
formatItalicHint: '_текст_',
|
||
formatStrike: 'Зачёркнут',
|
||
formatStrikeHint: '~текст~',
|
||
formatMono: 'Моноширинный',
|
||
formatMonoHint: '`текст`',
|
||
// Draft
|
||
draft: 'Черновик:',
|
||
// Date
|
||
datePlaceholder: 'дд.мм.гггг',
|
||
// GIF / Emoji
|
||
tenorKeyRequired: 'Для GIF нужен Tenor API ключ',
|
||
openConsoleRun: 'Откройте консоль и выполните:',
|
||
searchGifs: 'Поиск GIF...',
|
||
trending: 'Популярные',
|
||
// Misc
|
||
error: 'Ошибка',
|
||
// Friends
|
||
friends: 'Контакты',
|
||
friendRequests: 'Заявки в контакты',
|
||
friendsList: 'Список контактов',
|
||
noFriends: 'Пока нет контактов',
|
||
addFriend: 'Добавить в контакты',
|
||
removeFriend: 'Удалить из контактов',
|
||
requestSent: 'Заявка отправлена',
|
||
searchFriends: 'Поиск по @username (мин. 3 символа)',
|
||
searchResults: 'Результаты поиска',
|
||
noSearchResults: 'Пользователи не найдены',
|
||
minCharsHint: 'Введите минимум 3 символа после @',
|
||
selectContactToChat: 'Выберите контакт из списка, чтобы начать общение, или воспользуйтесь поиском для поиска новых людей.',
|
||
backToChats: 'Назад к чатам',
|
||
// Story viewers
|
||
storyViewers: 'Кто просмотрел',
|
||
noViewers: 'Пока никто не посмотрел',
|
||
replyToStory: 'Ответить на историю...',
|
||
send: 'Отправить',
|
||
// Favorites
|
||
favorites: 'Избранное',
|
||
favoritesDescription: 'Сохраняйте важные сообщения здесь',
|
||
// Privacy
|
||
privacy: 'Приватность',
|
||
hideStoryViews: 'Скрывать просмотры историй',
|
||
hideStoryViewsDesc: 'Другие не увидят, что вы смотрели их историю',
|
||
// Scheduled
|
||
scheduledFor: 'Запланировано на',
|
||
messageScheduled: 'Сообщение запланировано',
|
||
scheduledDelivered: 'Сообщение отправлено для',
|
||
scheduledDeliveredAt: 'в',
|
||
scheduleIn1h: 'Через 1 час',
|
||
scheduleIn3h: 'Через 3 часа',
|
||
scheduleTomorrow: 'Завтра в 9:00',
|
||
scheduleCustom: 'Выбрать дату и время',
|
||
scheduleTime: 'Время',
|
||
scheduleDate: 'Дата',
|
||
// Last seen
|
||
lastSeenAt: 'был(а)',
|
||
justNow: 'только что',
|
||
loadStoriesError: 'Ошибка загрузки историй',
|
||
loadChatsError: 'Ошибка загрузки чатов',
|
||
loadMessagesError: 'Ошибка загрузки сообщений',
|
||
unreadMessages: 'Непрочитанные сообщения',
|
||
attachmentDiscardConfirm: 'У вас есть прикрепленные вложения. Если вы перейдете в другой чат, они будут потеряны. Продолжить?',
|
||
},
|
||
en: {
|
||
myProfile: 'My Profile',
|
||
settings: 'Settings',
|
||
aboutApp: 'About',
|
||
logout: 'Log Out',
|
||
name: 'Name',
|
||
username: 'Username',
|
||
aboutMe: 'About me',
|
||
birthday: 'Birthday',
|
||
enterName: 'Enter name',
|
||
tellAboutYourself: 'Tell about yourself',
|
||
removePhoto: 'Remove photo',
|
||
cropPhoto: 'Crop Photo',
|
||
saveChanges: 'Save Changes',
|
||
displayName: 'Display Name',
|
||
language: 'Language',
|
||
chats: 'Chats',
|
||
calls: 'Calls',
|
||
contacts: 'Contacts',
|
||
archive: 'Archive',
|
||
interfaceLang: 'Interface language',
|
||
theme: 'Theme',
|
||
russian: 'Русский',
|
||
english: 'English',
|
||
about: 'About',
|
||
version: 'Version',
|
||
modernMessenger: 'A modern messenger focused',
|
||
onPrivacy: 'on privacy and convenience',
|
||
modernMessengerShort: 'Knot Messenger',
|
||
settingsDesc: 'Manage your profile and app settings',
|
||
appSettings: 'App Settings',
|
||
enterDisplayName: 'How should we call you?',
|
||
tellAboutBio: 'Tell us a bit about yourself...',
|
||
storageAndData: 'Storage and Data',
|
||
importTelegram: 'Import Telegram History',
|
||
importTelegramDesc: 'Move messages and media from Telegram',
|
||
importSuccess: 'Import completed',
|
||
importStarted: 'Import started in background',
|
||
importSelectArchive: 'Upload archive',
|
||
importSelectArchiveDesc: 'Export chat from Telegram (HTML format, incl. media) and upload the resulting ZIP archive.',
|
||
importLimit: 'Limit: up to 1 GB',
|
||
importSelectFile: 'Select ZIP archive',
|
||
importParticipants: 'Participant mapping',
|
||
importParticipantsDesc: 'Assign participants from the archive to Knot users.',
|
||
importInArchive: 'In archive',
|
||
importSelectContact: '-- Select contact --',
|
||
importGroupName: 'Chat name',
|
||
importGroupNameHint: 'e.g., My Group',
|
||
importStart: 'Start import',
|
||
importRestart: 'Start over',
|
||
importCompletedDesc: 'We successfully created the chat and started importing messages in the background.',
|
||
searchChats: 'Search chats...',
|
||
chat: 'Chat',
|
||
group: 'Group',
|
||
noChats: 'No chats — create one!',
|
||
nothingFound: 'Nothing found',
|
||
selectChat: 'Select a chat to start messaging',
|
||
selectChatTitle: 'Select a chat',
|
||
selectChatSubtext: 'Start communicating right now. All your messages are protected with end-to-end encryption.',
|
||
newMessage: 'New message',
|
||
noMessages: 'No messages — write the first one!',
|
||
typing: 'typing...',
|
||
online: 'online',
|
||
wasRecently: 'was recently',
|
||
members: 'members',
|
||
files: 'files',
|
||
clearAll: 'Clear all',
|
||
maxFilesLimit: 'Maximum 20 files',
|
||
searchingHistory: 'Searching history...',
|
||
messageNotFound: 'Message not found',
|
||
messagePlaceholder: 'Message...',
|
||
message: 'Message...',
|
||
addCaption: 'Add a caption...',
|
||
searchMessages: 'Search messages...',
|
||
searchMessagesBtn: 'Search messages',
|
||
userProfile: 'User profile',
|
||
userProfileUpper: 'USER PROFILE',
|
||
enableSound: 'Enable sound',
|
||
disableSound: 'Mute',
|
||
deleteChat: 'Delete chat',
|
||
messageDeleted: 'Message deleted',
|
||
reply: 'Reply',
|
||
copy: 'Copy',
|
||
edit: 'Edit',
|
||
delete: 'Delete',
|
||
deleteForMe: 'Delete for me',
|
||
deleteForAll: 'Delete for everyone',
|
||
deleteAlsoFor: 'Delete also for',
|
||
editing: 'Editing',
|
||
replyTo: 'Reply',
|
||
media: 'Media',
|
||
download: 'Download',
|
||
edited: 'edit.',
|
||
selected: 'selected',
|
||
fileLabel: 'File',
|
||
kb: 'KB',
|
||
voice: '🎤 Voice',
|
||
photo: '🖼 Photo',
|
||
video: '🎬 Video',
|
||
file: 'File',
|
||
call: 'Call',
|
||
videoCall: 'Video call',
|
||
incomingCall: 'Incoming call',
|
||
incomingVideoCall: 'Incoming video call',
|
||
calling: 'Calling...',
|
||
isCalling: 'is calling...',
|
||
groupCall: 'Group call',
|
||
comingSoon: 'Coming soon',
|
||
accept: 'Accept',
|
||
decline: 'Decline',
|
||
endCall: 'End call',
|
||
callEnded: 'Call ended',
|
||
callDeclined: 'Call declined',
|
||
audioCall: 'Audio call',
|
||
missedCall: 'Missed call',
|
||
declinedCall: 'Declined call',
|
||
cancelledCall: 'Cancelled call',
|
||
completedCall: 'Call completed',
|
||
photoVideo: 'Photo / video',
|
||
fileBtn: 'File',
|
||
sendError: 'Send error',
|
||
newChat: 'New chat',
|
||
add: 'Add',
|
||
menu: 'Menu',
|
||
months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
|
||
weekDays: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],
|
||
clear: 'Clear',
|
||
today: 'Today',
|
||
newChatTitle: 'New Chat',
|
||
selectMembers: 'Select members',
|
||
newGroup: 'New Group',
|
||
groupNamePlaceholder: 'Group name...',
|
||
membersCount: 'Members',
|
||
createGroup: 'Create Group',
|
||
upTo200: 'Up to 200 members',
|
||
findUser: 'Find user by name or @username...',
|
||
addMembers: 'Add members...',
|
||
usersNotFound: 'Users not found',
|
||
enterNameOrUsername: 'Enter name or @username',
|
||
next: 'Next',
|
||
pinMessage: 'Pin',
|
||
unpinMessage: 'Unpin',
|
||
pinnedMessage: 'Pinned message',
|
||
forwardMessage: 'Forward message',
|
||
forward: 'Forward',
|
||
forwardedFrom: 'Forwarded from',
|
||
replyWithQuote: 'Reply with quote',
|
||
select: 'Select',
|
||
sending: 'Sending...',
|
||
scheduleMessage: 'Schedule',
|
||
scheduleSend: 'Send scheduled',
|
||
scheduled: 'Scheduled',
|
||
myStory: 'My story',
|
||
newStory: 'New story',
|
||
textStory: 'Text',
|
||
imageStory: 'Photo',
|
||
mediaStory: 'Media',
|
||
typeYourStory: 'Write your story...',
|
||
publishStory: 'Publish',
|
||
stories: 'Stories',
|
||
clearChat: 'Clear chat',
|
||
clearChatConfirm: 'Clear chat history for yourself? The other person will keep their history.',
|
||
clearHistory: 'Clear history',
|
||
clearHistoryConfirm: 'Clear history?',
|
||
deleteChatConfirm: 'Delete this chat? This action cannot be undone.',
|
||
pinChat: 'Pin chat',
|
||
unpinChat: 'Unpin chat',
|
||
chatCleared: 'Chat cleared',
|
||
poll: 'Poll',
|
||
pollTab: 'Polls',
|
||
createPoll: 'Create Poll',
|
||
pollQuestion: 'Question',
|
||
pollQuestionPlaceholder: 'Ask a question...',
|
||
pollOptions: 'Options',
|
||
pollOption: 'Option',
|
||
addOption: 'Add Option',
|
||
pollSettings: 'Settings',
|
||
anonymousVoting: 'Anonymous Voting',
|
||
multipleAnswers: 'Multiple Answers',
|
||
singleAnswer: 'Single Answer',
|
||
anonymous: 'Anonymous',
|
||
votes: 'votes',
|
||
pollButton: 'Poll',
|
||
groupSettings: 'Group settings',
|
||
editGroupName: 'Edit name',
|
||
addMember: 'Add member',
|
||
removeMember: 'Remove from group',
|
||
leaveGroup: 'Leave group',
|
||
adminBadge: 'Admin',
|
||
groupDescription: 'Description',
|
||
noDescription: 'No description',
|
||
memberBadge: 'Member',
|
||
screenShare: 'Screen share',
|
||
stopScreenShare: 'Stop sharing',
|
||
switchCamera: 'Switch camera',
|
||
showInChat: 'Show in chat',
|
||
minimize: 'Minimize',
|
||
volume: 'Volume',
|
||
mute: 'Mute',
|
||
unmute: 'Unmute',
|
||
noiseSuppressionOn: 'Noise suppression on',
|
||
noiseSuppressionOff: 'Noise suppression off',
|
||
selectMicrophone: 'Select microphone',
|
||
microphone: 'Microphone',
|
||
rightClickVolume: 'Right-click to adjust volume',
|
||
participants: 'participants',
|
||
joinCall: 'Join call',
|
||
activeCall: 'Active call',
|
||
groupNameRequired: 'Enter a group name',
|
||
confirmRemoveMember: 'Remove this member from the group?',
|
||
yes: 'Yes',
|
||
no: 'No',
|
||
you: 'you',
|
||
// Stories Editor
|
||
cropVideo: 'Video Crop',
|
||
cropTool: 'Crop',
|
||
trimVideo: 'Trim Video',
|
||
trim: 'Trim',
|
||
reset: 'Reset',
|
||
startCreation: 'Start Creation',
|
||
brushTool: 'Brush',
|
||
textTool: 'Text',
|
||
stickersTool: 'Stickers',
|
||
filtersTool: 'Filters',
|
||
textContent: 'Content',
|
||
typography: 'Typography',
|
||
textSize: 'Size',
|
||
textColor: 'Color',
|
||
brushThickness: 'Thickness',
|
||
clearCanvas: 'Clear Canvas',
|
||
correctionMaster: 'Correction Master',
|
||
brightness: 'Brightness',
|
||
contrast: 'Contrast',
|
||
saturation: 'Saturation',
|
||
sepia: 'Sepia',
|
||
bgColor: 'Background',
|
||
clickToChooseColor: 'Click to choose color',
|
||
done: 'Done',
|
||
stop: 'Stop',
|
||
zoomHint: 'Mouse wheel to zoom',
|
||
secSelected: 'sec selected',
|
||
muted: 'Muted',
|
||
unmuted: 'Unmuted',
|
||
muteVideo: 'Mute Video',
|
||
unmuteVideo: 'Unmute Video',
|
||
interactive: 'Interactive',
|
||
apply: 'Apply',
|
||
zoom: 'Zoom',
|
||
rotation: 'Rotation',
|
||
// User profile
|
||
mediaTab: 'Media',
|
||
gifs: 'GIF',
|
||
filesTab: 'Files',
|
||
linksTab: 'Links',
|
||
profileTitle: 'Profile',
|
||
removeAvatar: 'Remove avatar',
|
||
namePlaceholder: 'Name',
|
||
notSpecified: 'Not specified',
|
||
onKnotSince: 'On Knot since',
|
||
joined: 'Joined',
|
||
cancel: 'Cancel',
|
||
confirm: 'Confirm',
|
||
save: 'Save',
|
||
sharedPhotos: 'Shared photos and videos will appear here',
|
||
sharedFiles: 'Shared files will appear here',
|
||
sharedLinks: 'Shared links will appear here',
|
||
profileNotFound: 'Profile not found',
|
||
storiesTab: 'Stories',
|
||
publicationsTab: 'Publications',
|
||
noStories: 'No stories yet',
|
||
noBio: 'No information shared yet',
|
||
goToMessage: 'Go to message',
|
||
story: 'Story',
|
||
commonGroups: 'Common groups',
|
||
more: 'More',
|
||
empty: 'Empty',
|
||
acceptRequest: 'Accept Request',
|
||
typingText: 'typing',
|
||
emojiFrequent: 'Frequent',
|
||
emojiGestures: 'Gestures',
|
||
emojiEmotions: 'Emotions',
|
||
emojiObjects: 'Objects',
|
||
emojiFood: 'Food',
|
||
emojiNature: 'Nature',
|
||
login: 'Login',
|
||
register: 'Register',
|
||
latinOnly: '(latin only, cannot be changed)',
|
||
displayNameLabel: 'Display name',
|
||
displayNamePlaceholder: 'Your name (any language)',
|
||
password: 'Password',
|
||
passwordPlaceholder: 'Enter password',
|
||
bioPlaceholder: 'Tell about yourself (optional)',
|
||
loginBtn: 'Login',
|
||
createAccount: 'Create account',
|
||
testAccounts: 'Test accounts: evgeniy, anastasia, artem, polina',
|
||
passwordForAll: 'Password for all:',
|
||
dontHaveAccount: "Don't have an account?",
|
||
alreadyHaveAccount: 'Already have an account?',
|
||
passwordRequirements: 'At least 8 characters, letters and numbers',
|
||
registerNow: 'Register',
|
||
loginNow: 'Login',
|
||
fileTooLarge: 'File too large (max 200MB)',
|
||
dropFileHere: 'Drop file here',
|
||
uploading: 'Uploading...',
|
||
uploadError: 'File upload error',
|
||
changePhoto: 'Change photo',
|
||
remove: 'Remove',
|
||
formatBold: 'Bold',
|
||
formatBoldHint: '**text**',
|
||
formatItalic: 'Italic',
|
||
formatItalicHint: '_text_',
|
||
formatStrike: 'Strikethrough',
|
||
formatStrikeHint: '~text~',
|
||
formatMono: 'Monospace',
|
||
formatMonoHint: '`text`',
|
||
draft: 'Draft:',
|
||
datePlaceholder: 'mm/dd/yyyy',
|
||
tenorKeyRequired: 'Tenor API key required for GIFs',
|
||
openConsoleRun: 'Open console and run:',
|
||
searchGifs: 'Search GIFs...',
|
||
trending: 'Trending',
|
||
error: 'Error',
|
||
friends: 'Contacts',
|
||
friendRequests: 'Contact requests',
|
||
friendsList: 'Contacts list',
|
||
noFriends: 'No contacts yet',
|
||
addFriend: 'Add to contacts',
|
||
removeFriend: 'Remove from contacts',
|
||
requestSent: 'Request sent',
|
||
searchFriends: 'Search by @username (min. 3 chars)',
|
||
searchResults: 'Search Results',
|
||
noSearchResults: 'No users found',
|
||
minCharsHint: 'Enter at least 3 characters after @',
|
||
selectContactToChat: 'Select a contact from the list to start a conversation or use search to find new people.',
|
||
backToChats: 'Back to Chats',
|
||
storyViewers: 'Who viewed',
|
||
noViewers: 'No one viewed yet',
|
||
replyToStory: 'Reply to story...',
|
||
send: 'Send',
|
||
favorites: 'Favorites',
|
||
favoritesDescription: 'Save important messages here',
|
||
privacy: 'Privacy',
|
||
hideStoryViews: 'Hide story views',
|
||
hideStoryViewsDesc: 'Others won\'t see that you viewed their story',
|
||
scheduledFor: 'Scheduled for',
|
||
messageScheduled: 'Message scheduled',
|
||
scheduledDelivered: 'Message sent to',
|
||
scheduledDeliveredAt: 'at',
|
||
scheduleIn1h: 'In 1 hour',
|
||
scheduleIn3h: 'In 3 hours',
|
||
scheduleTomorrow: 'Tomorrow at 9:00',
|
||
scheduleCustom: 'Choose date & time',
|
||
scheduleTime: 'Time',
|
||
scheduleDate: 'Date',
|
||
lastSeenAt: 'was',
|
||
justNow: 'just now',
|
||
loadStoriesError: 'Error loading stories',
|
||
loadChatsError: 'Error loading chats',
|
||
loadMessagesError: 'Error loading messages',
|
||
unreadMessages: 'Unread messages',
|
||
typeYourStoryPlaceholder: 'Write your story...',
|
||
uploadMedia: 'Upload media',
|
||
chooseBackground: 'Background',
|
||
viewedBy: 'Viewed by',
|
||
storyDetails: 'Details',
|
||
viewCountSuffix: 'people viewed this story',
|
||
storyPrivacyNote: 'Stories are encrypted and disappear in 24 hours. View receipts are only visible to you.',
|
||
storiesEditor: 'Stories Editor',
|
||
tools: 'Tools',
|
||
privacyNote: 'Choose who can view your new story.',
|
||
allUsers: 'All users',
|
||
onlyContacts: 'Only contacts',
|
||
selectedContacts: 'Selected contacts',
|
||
yourStory: 'Your story',
|
||
stickers: 'Stickers',
|
||
brush: 'Brush',
|
||
filters: 'Filters',
|
||
report: 'Report',
|
||
attachmentDiscardConfirm: 'You have attached files. If you switch to another chat, they will be lost. Continue?',
|
||
},
|
||
} as const;
|
||
|
||
interface LangState {
|
||
lang: Lang;
|
||
setLang: (lang: Lang) => void;
|
||
t: (key: keyof typeof translations['ru']) => any;
|
||
}
|
||
|
||
export const useLang = create<LangState>((set, get) => ({
|
||
lang: (localStorage.getItem(LANG_KEY) as Lang) || 'ru',
|
||
setLang: (lang) => {
|
||
localStorage.setItem(LANG_KEY, lang);
|
||
set({ lang });
|
||
},
|
||
t: (key) => {
|
||
const { lang } = get();
|
||
return translations[lang][key] || translations['ru'][key] || key;
|
||
},
|
||
}));
|