More translations

This commit is contained in:
Eduard Kuzmenko 2021-03-25 22:07:00 +04:00
parent 445e6d8ece
commit 49a3fe551e
24 changed files with 205 additions and 96 deletions

View File

@ -11,6 +11,7 @@ import { FocusDirection } from "../helpers/fastSmoothScroll";
import CheckboxField from "./checkboxField";
import appProfileManager from "../lib/appManagers/appProfileManager";
import { safeAssign } from "../helpers/object";
import { LangPackKey, _i18n } from "../lib/langPack";
type PeerType = 'contacts' | 'dialogs' | 'channelParticipants';
@ -57,6 +58,8 @@ export default class AppSelectPeers {
private tempIds: {[k in keyof AppSelectPeers['loadedWhat']]: number} = {};
private peerId = 0;
private placeholder: LangPackKey;
constructor(options: {
appendTo: AppSelectPeers['appendTo'],
@ -69,6 +72,7 @@ export default class AppSelectPeers {
multiSelect?: AppSelectPeers['multiSelect'],
rippleEnabled?: boolean,
avatarSize?: AppSelectPeers['avatarSize'],
placeholder?: LangPackKey
}) {
safeAssign(this, options);
@ -94,7 +98,12 @@ export default class AppSelectPeers {
this.input = document.createElement('input');
this.input.classList.add('selector-search-input');
this.input.placeholder = !this.peerType.includes('dialogs') ? 'Add People...' : 'Select chat';
if(this.placeholder) {
_i18n(this.input, this.placeholder, undefined, 'placeholder');
} else {
_i18n(this.input, !this.peerType.includes('dialogs') ? 'SendMessageTo' : 'SelectChat', undefined, 'placeholder');
}
this.input.type = 'text';
if(this.multiSelect) {

View File

@ -13,6 +13,7 @@ import PopupPinMessage from "../popups/unpinMessage";
import { copyTextToClipboard } from "../../helpers/clipboard";
import PopupSendNow from "../popups/sendNow";
import { toast } from "../toast";
import I18n, { LangPackKey } from "../../lib/langPack";
export default class ChatContextMenu {
private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true})[];
@ -150,19 +151,19 @@ export default class ChatContextMenu {
private init() {
this.buttons = [{
icon: 'send2',
text: 'Send Now',
text: 'Chat.Context.Scheduled.SendNow',
onClick: this.onSendScheduledClick,
verify: () => this.chat.type === 'scheduled' && !this.message.pFlags.is_outgoing
}, {
icon: 'send2',
text: 'Send Now selected',
text: 'Message.Context.Selection.SendNow',
onClick: this.onSendScheduledClick,
verify: () => this.chat.type === 'scheduled' && this.chat.selection.selectedMids.has(this.mid) && !this.chat.selection.selectionSendNowBtn.hasAttribute('disabled'),
notDirect: () => true,
withSelection: true
}, {
icon: 'schedule',
text: 'Reschedule',
text: 'Chat.Context.Scheduled.Reschedule',
onClick: () => {
this.chat.input.scheduleSending(() => {
this.appMessagesManager.editMessage(this.message, this.message.message, {
@ -195,30 +196,30 @@ export default class ChatContextMenu {
verify: () => !!this.message.message && !this.isTextSelected
}, {
icon: 'copy',
text: 'Copy Selected Text',
text: 'Chat.CopySelectedText',
onClick: this.onCopyClick,
verify: () => !!this.message.message && this.isTextSelected
}, {
icon: 'copy',
text: 'Copy selected',
text: 'Message.Context.Selection.Copy',
onClick: this.onCopyClick,
verify: () => this.chat.selection.selectedMids.has(this.mid) && !![...this.chat.selection.selectedMids].find(mid => !!this.chat.getMessage(mid).message),
notDirect: () => true,
withSelection: true
}, {
icon: 'copy',
text: 'Copy Link',
text: 'CopyLink',
onClick: this.onCopyAnchorLinkClick,
verify: () => this.isAnchorTarget,
withSelection: true
}, {
icon: 'link',
text: 'Copy Link',
text: 'CopyLink',
onClick: this.onCopyLinkClick,
verify: () => this.appPeersManager.isChannel(this.peerId) && !this.message.pFlags.is_outgoing
}, {
icon: 'pin',
text: 'Pin',
text: 'Message.Context.Pin',
onClick: this.onPinClick,
verify: () => !this.message.pFlags.is_outgoing &&
this.message._ !== 'messageService' &&
@ -227,12 +228,12 @@ export default class ChatContextMenu {
this.chat.type !== 'scheduled',
}, {
icon: 'unpin',
text: 'Unpin',
text: 'Message.Context.Unpin',
onClick: this.onUnpinClick,
verify: () => this.message.pFlags.pinned && this.appPeersManager.canPinMessage(this.peerId),
}, {
icon: 'revote',
text: 'Revote',
text: 'Chat.Poll.Unvote',
onClick: this.onRetractVote,
verify: () => {
const poll = this.message.media?.poll as Poll;
@ -241,7 +242,7 @@ export default class ChatContextMenu {
cancelEvent: true */
}, {
icon: 'stop',
text: 'Stop poll',
text: 'Chat.Poll.Stop',
onClick: this.onStopPoll,
verify: () => {
const poll = this.message.media?.poll;
@ -255,7 +256,7 @@ export default class ChatContextMenu {
verify: () => this.chat.type !== 'scheduled' && !this.message.pFlags.is_outgoing && this.message._ !== 'messageService'
}, {
icon: 'forward',
text: 'Forward selected',
text: 'Message.Context.Selection.Forward',
onClick: this.onForwardClick,
verify: () => this.chat.selection.selectionForwardBtn &&
this.chat.selection.selectedMids.has(this.mid) &&
@ -264,14 +265,14 @@ export default class ChatContextMenu {
withSelection: true
}, {
icon: 'select',
text: 'Select',
text: 'Message.Context.Select',
onClick: this.onSelectClick,
verify: () => !this.message.action && !this.chat.selection.selectedMids.has(this.mid) && this.isSelectable,
notDirect: () => true,
withSelection: true
}, {
icon: 'select',
text: 'Clear selection',
text: 'Message.Context.Selection.Clear',
onClick: this.onClearSelectionClick,
verify: () => this.chat.selection.selectedMids.has(this.mid),
notDirect: () => true,
@ -283,7 +284,7 @@ export default class ChatContextMenu {
verify: () => this.appMessagesManager.canDeleteMessage(this.message)
}, {
icon: 'delete danger',
text: 'Delete selected',
text: 'Message.Context.Selection.Delete',
onClick: this.onDeleteClick,
verify: () => this.chat.selection.selectedMids.has(this.mid) && !this.chat.selection.selectionDeleteBtn.hasAttribute('disabled'),
notDirect: () => true,
@ -334,14 +335,17 @@ export default class ChatContextMenu {
const username = this.appPeersManager.getPeerUsername(this.peerId);
const msgId = this.appMessagesManager.getServerMessageId(this.mid);
let url = 'https://t.me/';
let key: LangPackKey;
if(username) {
url += username + '/' + msgId;
toast('Link copied to clipboard.');
key = 'LinkCopied';
} else {
url += 'c/' + Math.abs(this.peerId) + '/' + msgId;
toast('This link will only work for chat members.');
key = 'LinkCopiedPrivateInfo';
}
toast(I18n.format(key, true));
copyTextToClipboard(url);
};

View File

@ -15,6 +15,7 @@ import ListenerSetter from "../../helpers/listenerSetter";
import PopupSendNow from "../popups/sendNow";
import appNavigationController from "../appNavigationController";
import { isMobileSafari } from "../../helpers/userAgent";
import I18n, { i18n, _i18n } from "../../lib/langPack";
const MAX_SELECTION_LENGTH = 100;
//const MIN_CLICK_MOVE = 32; // minimum bubble height
@ -214,7 +215,8 @@ export default class ChatSelection {
private updateContainer(forceSelection = false) {
if(!this.selectedMids.size && !forceSelection) return;
this.selectionCountEl.innerText = this.selectedMids.size + ' Message' + (this.selectedMids.size === 1 ? '' : 's');
this.selectionCountEl.textContent = '';
this.selectionCountEl.append(i18n('Chat.Selection.MessagesCount', [this.selectedMids.size]));
let cantForward = !this.selectedMids.size, cantDelete = !this.selectedMids.size, cantSend = !this.selectedMids.size;
for(const mid of this.selectedMids.values()) {
@ -348,7 +350,7 @@ export default class ChatSelection {
if(this.chat.type === 'scheduled') {
this.selectionSendNowBtn = Button('btn-primary btn-transparent btn-short text-bold selection-container-send', {icon: 'send2'});
this.selectionSendNowBtn.append('Send Now');
_i18n(this.selectionSendNowBtn, 'Chat.Context.Scheduled.SendNow');
this.listenerSetter.add(this.selectionSendNowBtn, 'click', () => {
new PopupSendNow(this.bubbles.peerId, [...this.selectedMids], () => {
this.cancelSelection();
@ -356,7 +358,7 @@ export default class ChatSelection {
});
} else {
this.selectionForwardBtn = Button('btn-primary btn-transparent text-bold selection-container-forward', {icon: 'forward'});
this.selectionForwardBtn.append('Forward');
_i18n(this.selectionForwardBtn, 'Forward');
this.listenerSetter.add(this.selectionForwardBtn, 'click', () => {
new PopupForward(this.bubbles.peerId, [...this.selectedMids], () => {
this.cancelSelection();
@ -365,7 +367,7 @@ export default class ChatSelection {
}
this.selectionDeleteBtn = Button('btn-primary btn-transparent danger text-bold selection-container-delete', {icon: 'delete'});
this.selectionDeleteBtn.append('Delete');
_i18n(this.selectionDeleteBtn, 'Delete');
this.listenerSetter.add(this.selectionDeleteBtn, 'click', () => {
new PopupDeleteMessages(this.bubbles.peerId, [...this.selectedMids], this.chat.type, () => {
this.cancelSelection();
@ -461,7 +463,7 @@ export default class ChatSelection {
} else {
const diff = MAX_SELECTION_LENGTH - this.selectedMids.size - 1;
if(diff < 0) {
toast('Max selection count reached.');
toast(I18n.format('Chat.Selection.LimitToast', true));
return;
/* const it = this.selectedMids.values();
do {

View File

@ -18,7 +18,7 @@ export default class DialogsContextMenu {
private init() {
this.buttons = [{
icon: 'unread',
text: 'Mark as unread',
text: 'MarkAsUnread',
onClick: this.onUnreadClick,
verify: () => {
const isUnread = !!(this.dialog.pFlags?.unread_mark || this.dialog.unread_count);
@ -26,7 +26,7 @@ export default class DialogsContextMenu {
}
}, {
icon: 'readchats',
text: 'Mark as read',
text: 'MarkAsRead',
onClick: this.onUnreadClick,
verify: () => {
const isUnread = !!(this.dialog.pFlags?.unread_mark || this.dialog.unread_count);
@ -34,7 +34,7 @@ export default class DialogsContextMenu {
}
}, {
icon: 'pin',
text: 'Pin',
text: 'ChatList.Context.Pin',
onClick: this.onPinClick,
verify: () => {
const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.filters[this.filterId].pinned_peers.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;
@ -42,7 +42,7 @@ export default class DialogsContextMenu {
}
}, {
icon: 'unpin',
text: 'Unpin',
text: 'ChatList.Context.Unpin',
onClick: this.onPinClick,
verify: () => {
const isPinned = this.filterId > 1 ? appMessagesManager.filtersStorage.filters[this.filterId].pinned_peers.includes(this.dialog.peerId) : !!this.dialog.pFlags?.pinned;
@ -50,7 +50,7 @@ export default class DialogsContextMenu {
}
}, {
icon: 'mute',
text: 'Mute',
text: 'ChatList.Context.Mute',
onClick: this.onMuteClick,
verify: () => {
const isMuted = this.dialog.notify_settings && this.dialog.notify_settings.mute_until > (Date.now() / 1000 | 0);
@ -58,7 +58,7 @@ export default class DialogsContextMenu {
}
}, {
icon: 'unmute',
text: 'Unmute',
text: 'ChatList.Context.Unmute',
onClick: this.onMuteClick,
verify: () => {
const isMuted = this.dialog.notify_settings && this.dialog.notify_settings.mute_until > (Date.now() / 1000 | 0);

View File

@ -1,7 +1,7 @@
import { getRichValue, isInputEmpty } from "../helpers/dom";
import { debounce } from "../helpers/schedulers";
import { checkRTL } from "../helpers/string";
import { i18n, LangPackKey } from "../lib/langPack";
import { i18n, LangPackKey, _i18n } from "../lib/langPack";
import RichTextProcessor from "../lib/richtextprocessor";
let init = () => {
@ -59,7 +59,7 @@ export enum InputState {
};
export type InputFieldOptions = {
placeholder?: string,
placeholder?: LangPackKey,
label?: LangPackKey,
name?: string,
maxLength?: number,
@ -134,11 +134,15 @@ class InputField {
}
} else {
this.container.innerHTML = `
<input type="text" ${name ? `name="${name}"` : ''} ${placeholder ? `placeholder="${placeholder}"` : ''} autocomplete="off" ${label ? 'required=""' : ''} class="input-field-input">
<input type="text" ${name ? `name="${name}"` : ''} autocomplete="off" ${label ? 'required=""' : ''} class="input-field-input">
`;
input = this.container.firstElementChild as HTMLElement;
input.addEventListener('input', () => checkAndSetRTL(input));
if(placeholder) {
_i18n(input, placeholder, undefined, 'placeholder');
}
}
if(label) {

View File

@ -1,4 +1,5 @@
//import { getRichValue } from "../helpers/dom";
import { LangPackKey } from "../lib/langPack";
import InputField from "./inputField";
export default class InputSearch {
@ -12,7 +13,7 @@ export default class InputSearch {
public onChange: (value: string) => void;
public onClear: () => void;
constructor(placeholder: string, onChange?: (value: string) => void) {
constructor(placeholder: LangPackKey, onChange?: (value: string) => void) {
this.inputField = new InputField({
placeholder,
plainText: true

View File

@ -123,13 +123,13 @@ export function formatPhoneNumber(str: string) {
return {formatted: str, country};
}
export function parseMenuButtonsTo(to: {[name: string]: HTMLElement}, elements: HTMLCollection | NodeListOf<HTMLElement>) {
/* export function parseMenuButtonsTo(to: {[name: string]: HTMLElement}, elements: HTMLCollection | NodeListOf<HTMLElement>) {
Array.from(elements).forEach(el => {
const match = el.className.match(/(?:^|\s)menu-(.+?)(?:$|\s)/);
if(!match) return;
to[match[1]] = el as HTMLElement;
});
}
} */
let onMouseMove = (e: MouseEvent) => {
let rect = openedMenu.getBoundingClientRect();

View File

@ -17,7 +17,7 @@ export default class PopupForward extends PopupPickUser {
appImManager.chat.input.initMessagesForward(fromPeerId, mids.slice());
},
onClose,
placeholder: 'Forward to...',
placeholder: 'ShareModal.Search.ForwardPlaceholder',
chatRightsAction: 'send_messages'
});
}

View File

@ -1,6 +1,7 @@
import { isTouchSupported } from "../../helpers/touchSupport";
import AppSelectPeers from "../appSelectPeers";
import PopupElement from ".";
import { LangPackKey, _i18n } from "../../lib/langPack";
export default class PopupPickUser extends PopupElement {
protected selector: AppSelectPeers;
@ -9,7 +10,7 @@ export default class PopupPickUser extends PopupElement {
peerTypes: AppSelectPeers['peerType'],
onSelect?: (peerId: number) => Promise<void> | void,
onClose?: () => void,
placeholder: string,
placeholder: LangPackKey,
chatRightsAction?: AppSelectPeers['chatRightsAction'],
peerId?: number,
}) {
@ -47,11 +48,11 @@ export default class PopupPickUser extends PopupElement {
rippleEnabled: false,
avatarSize: 46,
peerId: options.peerId,
placeholder: options.placeholder
});
//this.scrollable = new Scrollable(this.body);
this.selector.input.placeholder = options.placeholder;
this.title.append(this.selector.input);
}
}

View File

@ -117,7 +117,7 @@ export default class PrivacySection {
type: 'privacy',
skippable: true,
title: exception.titleLangKey,
placeholder: 'Add Users or Groups...',
placeholder: 'PrivacyModal.Search.Placeholder',
takeOut: (newPeerIds) => {
_peerIds.length = 0;
_peerIds.push(...newPeerIds);

View File

@ -8,7 +8,6 @@ import rootScope from "../../lib/rootScope";
import { attachClickEvent, findUpClassName, findUpTag } from "../../helpers/dom";
import { SearchGroup } from "../appSearch";
import "../avatar";
import { parseMenuButtonsTo } from "../misc";
import Scrollable, { ScrollableX } from "../scrollable";
import InputSearch from "../inputSearch";
import SidebarSlider from "../slider";
@ -69,8 +68,8 @@ export class AppSidebarLeft extends SidebarSlider {
takeOut: (peerIds) => {
new AppNewGroupTab(this).open(peerIds);
},
title: 'Add Members',
placeholder: 'Add People...'
title: 'GroupAddMembers',
placeholder: 'SendMessageTo'
});
};
@ -126,23 +125,33 @@ export class AppSidebarLeft extends SidebarSlider {
this.menuEl = this.toolsBtn.querySelector('.btn-menu');
this.newBtnMenu = this.sidebarEl.querySelector('#new-menu');
const _newBtnMenu = ButtonMenu([{
icon: 'newchannel',
text: 'NewChannel',
onClick: () => {
new AppNewChannelTab(this).open();
}
}, {
icon: 'newgroup',
text: 'NewGroup',
onClick: onNewGroupClick
}, {
icon: 'newprivate',
text: 'NewPrivateChat',
onClick: onContactsClick
}]);
_newBtnMenu.classList.add('top-left');
this.newBtnMenu.append(_newBtnMenu);
this.inputSearch.input.addEventListener('focus', () => this.initSearch(), {once: true});
parseMenuButtonsTo(this.newButtons, this.newBtnMenu.firstElementChild.children);
//parseMenuButtonsTo(this.newButtons, this.newBtnMenu.firstElementChild.children);
this.archivedCount = document.createElement('span');
this.archivedCount.className = 'archived-count badge badge-24 badge-gray';
btnArchive.element.append(this.archivedCount);
attachClickEvent(this.newButtons.privateChat, onContactsClick);
attachClickEvent(this.newButtons.channel, (e) => {
new AppNewChannelTab(this).open();
});
attachClickEvent(this.newButtons.group, onNewGroupClick);
rootScope.on('dialogs_archived_unread', (e) => {
this.archivedCount.innerText = '' + formatNumber(e.count, 1);
this.archivedCount.classList.toggle('hide', !e.count);

View File

@ -2,6 +2,7 @@ import { SliderSuperTab } from "../../slider";
import AppSelectPeers from "../../appSelectPeers";
import { putPreloader } from "../../misc";
import Button from "../../button";
import { LangPackKey, _i18n } from "../../../lib/langPack";
export default class AppAddMembersTab extends SliderSuperTab {
private nextBtn: HTMLButtonElement;
@ -40,8 +41,8 @@ export default class AppAddMembersTab extends SliderSuperTab {
}
public open(options: {
title: string,
placeholder: string,
title: LangPackKey,
placeholder: LangPackKey,
peerId?: number,
type: AppAddMembersTab['peerType'],
takeOut?: AppAddMembersTab['takeOut'],
@ -50,7 +51,7 @@ export default class AppAddMembersTab extends SliderSuperTab {
}) {
const ret = super.open();
this.title.innerHTML = options.title;
this.setTitle(options.title);
this.peerType = options.type;
this.takeOut = options.takeOut;
this.skippable = options.skippable;
@ -60,9 +61,9 @@ export default class AppAddMembersTab extends SliderSuperTab {
onChange: this.skippable ? null : (length) => {
this.nextBtn.classList.toggle('is-visible', !!length);
},
peerType: ['contacts']
peerType: ['contacts'],
placeholder: options.placeholder
});
this.selector.input.placeholder = options.placeholder;
if(options.selectedPeerIds) {
this.selector.addInitial(options.selectedPeerIds);

View File

@ -31,7 +31,7 @@ export default class AppBlockedUsersTab extends SliderSuperTab {
attachClickEvent(btnAdd, (e) => {
new PopupPickUser({
peerTypes: ['contacts'],
placeholder: 'Block user...',
placeholder: 'BlockModal.Search.Placeholder',
onSelect: (peerId) => {
//console.log('block', peerId);
appUsersManager.toggleBlock(peerId, true);

View File

@ -275,7 +275,7 @@ export default class AppEditFolderTab extends SliderSuperTab {
}
if(peers.length) {
showMore.innerHTML = `<div class="tgico-down"></div><div>Show ${Math.min(20, peers.length)} more chat${peers.length > 1 ? 's' : ''}</div>`;
showMore.lastElementChild.replaceWith(i18n('FilterShowMoreChats', [peers.length]));
} else if(showMore) {
showMore.remove();
}
@ -286,11 +286,14 @@ export default class AppEditFolderTab extends SliderSuperTab {
let showMore: HTMLElement;
if(peers.length) {
showMore = document.createElement('div');
showMore.classList.add('show-more');
showMore.classList.add('show-more', 'rp-overflow');
showMore.addEventListener('click', () => renderMore(20));
showMore.innerHTML = `<div class="tgico-down"></div><div>Show ${Math.min(20, peers.length)} more chat${peers.length > 1 ? 's' : ''}</div>`;
ripple(showMore);
const down = document.createElement('div');
down.classList.add('tgico-down');
showMore.append(down, i18n('FilterShowMoreChats', [peers.length]));
container.append(showMore);
}

View File

@ -211,10 +211,10 @@ export default class AppIncludedChatsTab extends SliderSuperTab {
appendTo: this.container,
onChange: this.onSelectChange,
peerType: ['dialogs'],
renderResultsFunc: this.renderResults
renderResultsFunc: this.renderResults,
placeholder: 'Search'
});
this.selector.selected = new Set(selectedPeers);
this.selector.input.placeholder = 'Search';
const _add = this.selector.add.bind(this.selector);
this.selector.add = (peerId, title, scroll) => {

View File

@ -6,6 +6,7 @@ import InputField from "../../inputField";
import { SliderSuperTab } from "../../slider";
import AvatarEdit from "../../avatarEdit";
import AppAddMembersTab from "./addMembers";
import { _i18n } from "../../../lib/langPack";
export default class AppNewChannelTab extends SliderSuperTab {
private uploadAvatar: () => Promise<InputFile> = null;
@ -17,7 +18,7 @@ export default class AppNewChannelTab extends SliderSuperTab {
protected init() {
this.container.classList.add('new-channel-container');
this.title.innerText = 'New Channel';
this.setTitle('NewChannel');
this.avatarEdit = new AvatarEdit((_upload) => {
this.uploadAvatar = _upload;
@ -27,12 +28,12 @@ export default class AppNewChannelTab extends SliderSuperTab {
inputWrapper.classList.add('input-wrapper');
this.channelNameInputField = new InputField({
label: 'Channel Name',
label: 'Channel.ChannelNameHolder',
maxLength: 128
});
this.channelDescriptionInputField = new InputField({
label: 'Description (optional)',
label: 'Channel.DescriptionPlaceholder',
maxLength: 255
});
@ -49,7 +50,7 @@ export default class AppNewChannelTab extends SliderSuperTab {
const caption = document.createElement('div');
caption.classList.add('caption');
caption.innerText = 'You can provide an optional description for your channel.';
_i18n(caption, 'Channel.DescriptionHolderDescrpiton');
this.nextBtn = Button('btn-corner btn-circle', {icon: 'arrow_next'});
@ -70,8 +71,8 @@ export default class AppNewChannelTab extends SliderSuperTab {
peerId: channelId,
type: 'channel',
skippable: true,
title: 'Add Members',
placeholder: 'Add People...',
title: 'GroupAddMembers',
placeholder: 'SendMessageTo',
takeOut: (peerIds) => {
return appChatsManager.inviteToChannel(Math.abs(channelId), peerIds);
}

View File

@ -8,6 +8,7 @@ import Button from "../../button";
import InputField from "../../inputField";
import { SliderSuperTab } from "../../slider";
import AvatarEdit from "../../avatarEdit";
import { i18n } from "../../../lib/langPack";
export default class AppNewGroupTab extends SliderSuperTab {
private searchGroup = new SearchGroup(' ', 'contacts', true, 'new-group-members disable-hover', false);
@ -19,7 +20,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
protected init() {
this.container.classList.add('new-group-container');
this.title.innerText = 'New Group';
this.setTitle('NewGroup');
this.avatarEdit = new AvatarEdit((_upload) => {
this.uploadAvatar = _upload;
@ -29,7 +30,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
inputWrapper.classList.add('input-wrapper');
this.groupNameInputField = new InputField({
label: 'Group Name',
label: 'CreateGroup.NameHolder',
maxLength: 128
});
@ -99,7 +100,8 @@ export default class AppNewGroupTab extends SliderSuperTab {
}
});
this.searchGroup.nameEl.innerText = this.userIds.length + ' members';
this.searchGroup.nameEl.textContent = '';
this.searchGroup.nameEl.append(i18n('Members', [this.userIds.length]));
this.searchGroup.setActive();
});

View File

@ -154,7 +154,7 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
openPermissions(peerId);
}, 0);
},
placeholder: 'Add Exception...',
placeholder: 'ExceptionModal.Search.Placeholder',
peerId: -this.chatId,
});
}

View File

@ -2,7 +2,7 @@ const App = {
id: 1025907,
hash: '452b0359b988148995f22ff0f4229750',
version: '0.4.0',
langPackVersion: '0.0.2',
langPackVersion: '0.0.3',
domains: [] as string[],
baseDcId: 2
};

View File

@ -117,13 +117,7 @@
</div>
</div>
<div class="transition-item sidebar-search" id="search-container"></div>
<button class="btn-circle rp btn-corner tgico-newchat_filled btn-menu-toggle" id="new-menu">
<div class="btn-menu top-left">
<div class="btn-menu-item menu-channel tgico-newchannel rp">New Channel</div>
<div class="btn-menu-item menu-group tgico-newgroup rp">New Group</div>
<div class="btn-menu-item menu-privateChat tgico-newprivate rp">New Private Chat</div>
</div>
</button>
<button class="btn-circle rp btn-corner tgico-newchat_filled btn-menu-toggle" id="new-menu"></button>
</div>
</div>
</div>

View File

@ -1,4 +1,6 @@
const lang = {
"AttachAlbum": "Album",
"BlockModal.Search.Placeholder": "Block user...",
"FilterIncludeExcludeInfo": "Choose chats and types of chats that will\nappear and never appear in this folder.",
"FilterNameInputLabel": "Folder Name",
"FilterMenuDelete": "Delete Folder",
@ -20,7 +22,13 @@ const lang = {
"EditProfile.Username.Taken": "Username is already taken",
"EditProfile.Username.Invalid": "Username is invalid",
"EditProfile.Username.Help": "You can choose a username on Telegram. If you do, people will be able to find you by this username and contact you without needing your phone number.\n\nYou can use az, 09 and underscores. Minimum length is 5 characters.",
"ExceptionModal.Search.Placeholder": "Add exception...",
"ChatList.Menu.Archived": "Archived",
"Chat.Selection.MessagesCount": {
"one_value": "%d Message",
"other_value": "%d Messages",
},
"Chat.Selection.LimitToast": "Max selection count reached.",
"Saved": "Saved",
"General.Keyboard": "Keyboard",
"General.SendShortcut.Enter": "Send by Enter",
@ -33,12 +41,19 @@ const lang = {
"ChatBackground.Blur": "Blur Wallpaper Image",
"Notifications.Sound": "Notification Sound",
"Notifications.MessagePreview": "Message preview",
"NewPrivateChat": "New Private Chat",
"Message.Context.Selection.Copy": "Copy selected",
"Message.Context.Selection.Clear": "Clear selection",
"Message.Context.Selection.Delete": "Delete selected",
"Message.Context.Selection.Forward": "Forward selected",
"Message.Context.Selection.SendNow": "Send Now selected",
"Checkbox.Enabled": "Enabled",
"Checkbox.Disabled": "Disabled",
"Privacy.Devices": {
"one_value": "%1$d device",
"other_value": "%1$d devices"
},
"PrivacyModal.Search.Placeholder": "Add Users or Groups...",
// * android
"ActionCreateChannel": "Channel created",
@ -56,8 +71,21 @@ const lang = {
"ActionInviteUser": "un1 joined the group via invite link",
"ActionPinnedNoText": "un1 pinned a message",
"ActionMigrateFromGroup": "This group was upgraded to a supergroup",
"AttachPhoto": "Photo",
"AttachVideo": "Video",
"AttachGif": "GIF",
"AttachLocation": "Location",
"AttachLiveLocation": "Live Location",
"AttachContact": "Contact",
"AttachDocument": "File",
"AttachSticker": "Sticker",
"AttachAudio": "Voice message",
"AttachRound": "Video message",
"AttachGame": "Game",
//"ChannelJoined": "You joined this channel",
"ChannelMegaJoined": "You joined this group",
"Channel.DescriptionPlaceholder": "Description (optional)",
"Draft": "Draft",
"FilterAlwaysShow": "Include Chats",
"FilterNeverShow": "Exclude Chats",
"FilterInclude": "Included Chats",
@ -67,6 +95,11 @@ const lang = {
"FilterNew": "New Folder",
"Filters": "Folders",
"FilterRecommended": "Recommended Folders",
"FilterShowMoreChats": {
"one_value": "Show %1$d More Chat",
"other_value": "Show %1$d More Chats"
},
"FromYou": "You",
"Add": "Add",
"Chats": {
"one_value": "%1$d chat",
@ -84,7 +117,12 @@ const lang = {
"one_value": "%1$d user",
"other_value": "%1$d users"
},
"Members": {
"one_value": "%1$d member",
"other_value": "%1$d members"
},
"UsernameHelpLink": "This link opens a chat with you:\n%1$s",
"NewChannel": "New Channel",
"NewGroup": "New Group",
"Contacts": "Contacts",
"SavedMessages": "Saved Messages",
@ -108,6 +146,8 @@ const lang = {
"NotificationsGroups": "Groups",
"NotificationsChannels": "Channels",
"NotificationsOther": "Other",
"MarkAsUnread": "Mark as unread",
"MarkAsRead": "Mark as read",
"ContactJoined": "Contact joined Telegram",
"Loading": "Loading...",
"Unblock": "Unblock",
@ -143,6 +183,20 @@ const lang = {
"ArchivedChats": "Archived Chats",
"Cancel": "Cancel",
"HistoryCleared": "History was cleared",
"Archive": "Archive",
"Unarchive": "Unarchive",
"Delete": "Delete",
"Reply": "Reply",
"Edit": "Edit",
"Forward": "Forward",
"CopyLink": "Copy Link",
"Copy": "Copy",
"Search": "Search",
"LinkCopied": "Link copied to clipboard",
"LinkCopiedPrivateInfo": "This link will only work for members of this chat.",
"GroupAddMembers": "Add Members",
"SendMessageTo": "Add people...",
"SelectChat": "Select Chat",
// * macos
"AccountSettings.Filters": "Chat Folders",
@ -150,6 +204,7 @@ const lang = {
"AccountSettings.PrivacyAndSecurity": "Privacy and Security",
"AccountSettings.Language": "Language",
"Bio.Description": "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco",
"Chat.CopySelectedText": "Copy Selected Text",
"Chat.Date.ScheduledFor": "Scheduled for %@",
//"Chat.Date.ScheduledUntilOnline": "Scheduled until online",
"Chat.Date.ScheduledForToday": "Scheduled for today",
@ -159,6 +214,14 @@ const lang = {
"Chat.Service.Channel.RemovedPhoto": "Channel photo removed",
"Chat.Service.Channel.UpdatedVideo": "Channel video updated",
"Chat.Service.BotPermissionAllowed": "You allowed this bot to message you when you logged in on %@",
"Chat.Poll.Unvote": "Retract Vote",
"Chat.Poll.Stop": "Stop Poll",
"Chat.Poll.Stop.Confirm.Header": "Stop Poll?",
"Chat.Poll.Stop.Confirm.Text": "If you stop this poll now, nobody will be able to vote in it anymore. This action cannot be undone.",
"ChatList.Context.Mute": "Mute",
"ChatList.Context.Unmute": "Unmute",
"ChatList.Context.Pin": "Pin",
"ChatList.Context.Unpin": "Unpin",
"ChatList.Service.Call.incoming": "Incoming Call (%@)",
"ChatList.Service.Call.outgoing": "Outgoing Call (%@)",
"ChatList.Service.Call.Cancelled": "Cancelled Call",
@ -177,6 +240,9 @@ const lang = {
"ChatList.Filter.MutedChats": "Muted",
"ChatList.Filter.ReadChats": "Read",
"ChatList.Filter.Archive": "Archived",
"Channel.ChannelNameHolder": "Channel Name",
"Channel.DescriptionHolderDescrpiton": "You can provide an optional description for your channel.",
"CreateGroup.NameHolder": "Group Name",
"Date.Today": "Today",
"EditAccount.Username": "Username",
"EditAccount.Title": "Edit Profile",
@ -186,6 +252,7 @@ const lang = {
"Telegram.InstalledStickerPacksController": "Stickers",
"Telegram.NotificationSettingsViewController": "Notifications",
"Stickers.SuggestStickers": "Suggest Stickers by Emoji",
"ShareModal.Search.ForwardPlaceholder": "Forward to...",
"InstalledStickers.LoopAnimated": "Loop Animated Stickers",
"PrivacyAndSecurity.Item.On": "On",
"PrivacyAndSecurity.Item.Off": "Off",
@ -211,7 +278,10 @@ const lang = {
"one_value": "%d user",
"other_value": "%d users"
},
"RecentSessions.Error.FreshReset": "For security reasons, you can't terminate older sessions from a device that you've just connected. Please use an earlier connection or wait for a few hours."
"RcentSessions.Error.FreshReset": "For security reasons, you can't terminate older sessions from a device that you've just connected. Please use an earlier connection or wait for a few hours.",
"Message.Context.Select": "Select",
"Message.Context.Pin": "Pin",
"Message.Context.Unpin": "Unpin",
};
export default lang;

View File

@ -29,6 +29,7 @@ import DEBUG, { MOUNT_CLASS_TO } from "../../config/debug";
import appNotificationsManager from "./appNotificationsManager";
import { InputNotifyPeer } from "../../layer";
import PeerTitle from "../../components/peerTitle";
import { i18n } from "../langPack";
type DialogDom = {
avatarEl: AvatarElement,
@ -1069,7 +1070,8 @@ export class AppDialogsManager {
if(draftMessage) {
const bold = document.createElement('b');
bold.classList.add('danger');
bold.innerHTML = 'Draft: ';
bold.append(i18n('Draft'));
bold.append(': ');
dom.lastMessageSpan.prepend(bold);
} else if(peer._ !== 'peerUser' && peerId !== lastMessage.fromId && !lastMessage.action) {
const sender = appPeersManager.getPeer(lastMessage.fromId);
@ -1077,7 +1079,7 @@ export class AppDialogsManager {
const senderBold = document.createElement('b');
if(sender.id === rootScope.myId) {
senderBold.innerHTML = 'You';
senderBold.append(i18n('FromYou'));
} else {
//str = sender.first_name || sender.last_name || sender.username;
senderBold.append(new PeerTitle({

View File

@ -8,7 +8,7 @@ import { randomLong } from "../../helpers/random";
import { splitStringByLength, limitSymbols, escapeRegExp } from "../../helpers/string";
import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MessagesPeerDialogs, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update } from "../../layer";
import { InvokeApiOptions } from "../../types";
import I18n, { join, langPack, LangPackKey, _i18n } from "../langPack";
import I18n, { i18n, join, langPack, LangPackKey, _i18n } from "../langPack";
import { logger, LogLevels } from "../logger";
import type { ApiFileManager } from '../mtproto/apiFileManager';
//import apiManager from '../mtproto/apiManager';
@ -2505,10 +2505,6 @@ export class AppMessagesManager {
const parts: (HTMLElement | string)[] = [];
const addPart = (part: string | HTMLElement, text?: string) => {
if(text) {
part += ', ';
}
if(plain) {
parts.push(part);
} else {
@ -2517,6 +2513,10 @@ export class AppMessagesManager {
else el.append(part);
parts.push(el);
}
if(text) {
parts.push(', ');
}
};
if(message.media) {
@ -2538,7 +2538,7 @@ export class AppMessagesManager {
if(usingFullAlbum) {
text = this.getAlbumText(message.grouped_id).message;
addPart('Album', text);
addPart(i18n('AttachAlbum'), text);
}
} else {
usingFullAlbum = false;
@ -2548,31 +2548,31 @@ export class AppMessagesManager {
const media = message.media;
switch(media._) {
case 'messageMediaPhoto':
addPart('Photo', message.message);
addPart(i18n('AttachPhoto'), message.message);
break;
case 'messageMediaDice':
addPart(plain ? media.emoticon : RichTextProcessor.wrapEmojiText(media.emoticon));
break;
case 'messageMediaGeo':
addPart('Geolocation');
addPart(i18n('AttachLiveLocation'));
break;
case 'messageMediaPoll':
addPart(plain ? '📊' + ' ' + (media.poll.question || 'poll') : media.poll.rReply);
break;
case 'messageMediaContact':
addPart('Contact');
addPart(i18n('AttachContact'));
break;
case 'messageMediaDocument':
let document = media.document;
if(document.type === 'video') {
addPart('Video', message.message);
addPart(i18n('AttachVideo'), message.message);
} else if(document.type === 'voice') {
addPart('Voice message', message.message);
addPart(i18n('AttachAudio'), message.message);
} else if(document.type === 'gif') {
addPart('GIF', message.message);
addPart(i18n('AttachGif'), message.message);
} else if(document.type === 'round') {
addPart('Video message', message.message);
addPart(i18n('AttachRound'), message.message);
} else if(document.type === 'sticker') {
addPart(((plain ? document.stickerEmojiRaw : document.stickerEmoji) || '') + 'Sticker');
text = '';

View File

@ -459,6 +459,12 @@
}
}
.new-group-container {
.search-group {
margin-top: .5rem;
}
}
.edit-folder-container {
.folder-category-button:nth-child(n+2) {
pointer-events: none;