Temp language commit
This commit is contained in:
parent
4d0e2ea138
commit
945acf5df0
@ -1,6 +1,7 @@
|
||||
import { i18n, LangPackKey } from "../lib/langPack";
|
||||
import { ripple } from "./ripple";
|
||||
|
||||
const Button = (className: string, options: Partial<{noRipple: true, onlyMobile: true, icon: string, rippleSquare: true, text: string, disabled: boolean}> = {}) => {
|
||||
const Button = (className: string, options: Partial<{noRipple: true, onlyMobile: true, icon: string, rippleSquare: true, text: LangPackKey, disabled: boolean}> = {}) => {
|
||||
const button = document.createElement('button');
|
||||
button.className = className + (options.icon ? ' tgico-' + options.icon : '');
|
||||
|
||||
@ -21,7 +22,7 @@ const Button = (className: string, options: Partial<{noRipple: true, onlyMobile:
|
||||
}
|
||||
|
||||
if(options.text) {
|
||||
button.append(options.text);
|
||||
button.append(i18n(options.text));
|
||||
}
|
||||
|
||||
return button;
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { attachClickEvent, AttachClickOptions, cancelEvent, CLICK_EVENT_NAME } from "../helpers/dom";
|
||||
import ListenerSetter from "../helpers/listenerSetter";
|
||||
import { i18n, LangPackKey } from "../lib/langPack";
|
||||
import { closeBtnMenu } from "./misc";
|
||||
import { ripple } from "./ripple";
|
||||
|
||||
export type ButtonMenuItemOptions = {
|
||||
icon: string,
|
||||
text: string,
|
||||
text: LangPackKey,
|
||||
onClick: (e: MouseEvent | TouchEvent) => void,
|
||||
element?: HTMLElement,
|
||||
options?: AttachClickOptions
|
||||
@ -18,7 +19,7 @@ const ButtonMenuItem = (options: ButtonMenuItemOptions) => {
|
||||
const {icon, text, onClick} = options;
|
||||
const el = document.createElement('div');
|
||||
el.className = 'btn-menu-item tgico-' + icon;
|
||||
el.innerText = text;
|
||||
el.append(i18n(text));
|
||||
|
||||
ripple(el);
|
||||
|
||||
|
@ -1,6 +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 RichTextProcessor from "../lib/richtextprocessor";
|
||||
|
||||
let init = () => {
|
||||
@ -59,7 +60,7 @@ export enum InputState {
|
||||
|
||||
export type InputFieldOptions = {
|
||||
placeholder?: string,
|
||||
label?: string,
|
||||
label?: LangPackKey,
|
||||
name?: string,
|
||||
maxLength?: number,
|
||||
showLengthOn?: number,
|
||||
@ -97,7 +98,6 @@ class InputField {
|
||||
|
||||
this.container.innerHTML = `
|
||||
<div ${placeholder ? `data-placeholder="${placeholder}"` : ''} contenteditable="true" class="input-field-input"></div>
|
||||
${label ? `<label>${label}</label>` : ''}
|
||||
`;
|
||||
|
||||
input = this.container.firstElementChild as HTMLElement;
|
||||
@ -135,7 +135,6 @@ class InputField {
|
||||
} else {
|
||||
this.container.innerHTML = `
|
||||
<input type="text" ${name ? `name="${name}"` : ''} ${placeholder ? `placeholder="${placeholder}"` : ''} autocomplete="off" ${label ? 'required=""' : ''} class="input-field-input">
|
||||
${label ? `<label>${label}</label>` : ''}
|
||||
`;
|
||||
|
||||
input = this.container.firstElementChild as HTMLElement;
|
||||
@ -143,7 +142,9 @@ class InputField {
|
||||
}
|
||||
|
||||
if(label) {
|
||||
this.label = this.container.lastElementChild as HTMLLabelElement;
|
||||
this.label = document.createElement('label');
|
||||
i18n_({element: this.label, key: label});
|
||||
this.container.append(this.label);
|
||||
}
|
||||
|
||||
let processInput: () => void;
|
||||
|
@ -23,6 +23,7 @@ import AppNewChannelTab from "./tabs/newChannel";
|
||||
import AppContactsTab from "./tabs/contacts";
|
||||
import AppArchivedTab from "./tabs/archivedTab";
|
||||
import AppAddMembersTab from "./tabs/addMembers";
|
||||
import { i18n_, LangPackKey } from "../../lib/langPack";
|
||||
|
||||
export const LEFT_COLUMN_ACTIVE_CLASSNAME = 'is-left-column-shown';
|
||||
|
||||
@ -413,7 +414,7 @@ export class SettingSection {
|
||||
public caption: HTMLElement;
|
||||
|
||||
constructor(options: {
|
||||
name?: string,
|
||||
name?: LangPackKey,
|
||||
caption?: string,
|
||||
noDelimiter?: boolean
|
||||
}) {
|
||||
@ -432,7 +433,7 @@ export class SettingSection {
|
||||
if(options.name) {
|
||||
this.title = document.createElement('div');
|
||||
this.title.classList.add('sidebar-left-h2', 'sidebar-left-section-name');
|
||||
this.title.innerHTML = options.name;
|
||||
i18n_({element: this.title, key: options.name});
|
||||
this.content.append(this.title);
|
||||
}
|
||||
|
||||
@ -451,7 +452,7 @@ export class SettingSection {
|
||||
}
|
||||
}
|
||||
|
||||
export const generateSection = (appendTo: Scrollable, name?: string, caption?: string) => {
|
||||
export const generateSection = (appendTo: Scrollable, name?: LangPackKey, caption?: string) => {
|
||||
const section = new SettingSection({name, caption});
|
||||
appendTo.append(section.container);
|
||||
return section.content;
|
||||
|
@ -16,6 +16,7 @@ import rootScope from "../../../lib/rootScope";
|
||||
import AppEditFolderTab from "./editFolder";
|
||||
import Row from "../../row";
|
||||
import { SettingSection } from "..";
|
||||
import { i18n_ } from "../../../lib/langPack";
|
||||
|
||||
export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
private createFolderBtn: HTMLElement;
|
||||
@ -101,7 +102,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
|
||||
protected init() {
|
||||
this.container.classList.add('chat-folders-container');
|
||||
this.title.innerText = 'Chat Folders';
|
||||
this.setTitle('ChatList.Filter.List.Title');
|
||||
|
||||
this.scrollable.container.classList.add('chat-folders');
|
||||
|
||||
@ -110,20 +111,20 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
|
||||
const caption = document.createElement('div');
|
||||
caption.classList.add('caption');
|
||||
caption.innerHTML = `Create folders for different groups of chats<br>and quickly switch between them.`;
|
||||
i18n_({element: caption, key: 'ChatList.Filter.Header'});
|
||||
|
||||
this.createFolderBtn = Button('btn-primary btn-color-primary btn-create-folder', {
|
||||
text: 'Create Folder',
|
||||
text: 'ChatList.Filter.NewTitle',
|
||||
icon: 'add'
|
||||
});
|
||||
|
||||
this.foldersSection = new SettingSection({
|
||||
name: 'Folders'
|
||||
name: 'ChatList.Filter.List.Header'
|
||||
});
|
||||
this.foldersSection.container.style.display = 'none';
|
||||
|
||||
this.suggestedSection = new SettingSection({
|
||||
name: 'Recommended folders'
|
||||
name: 'ChatList.Filter.Recommended.Header'
|
||||
});
|
||||
this.suggestedSection.container.style.display = 'none';
|
||||
|
||||
@ -207,9 +208,7 @@ export default class AppChatFoldersTab extends SliderSuperTab {
|
||||
|
||||
suggestedFilters.forEach(filter => {
|
||||
const div = this.renderFolder(filter);
|
||||
const button = document.createElement('button');
|
||||
button.classList.add('btn-primary', 'btn-color-primary');
|
||||
button.innerText = 'Add';
|
||||
const button = Button('btn-primary btn-color-primary', {text: 'ChatList.Filter.Recommended.Add'});
|
||||
div.append(button);
|
||||
this.suggestedSection.content.append(div);
|
||||
|
||||
|
@ -5,6 +5,7 @@ import { SliderSuperTab } from "../../slider";
|
||||
import { attachClickEvent } from "../../../helpers/dom";
|
||||
import EditPeer from "../../editPeer";
|
||||
import { UsernameInputField } from "../../usernameInputField";
|
||||
import { i18n_ } from "../../../lib/langPack";
|
||||
|
||||
// TODO: аватарка не поменяется в этой вкладке после изменения почему-то (если поставить в другом клиенте, и потом тут проверить, для этого ещё вышел в чатлист)
|
||||
|
||||
@ -21,7 +22,7 @@ export default class AppEditProfileTab extends SliderSuperTab {
|
||||
|
||||
protected async init() {
|
||||
this.container.classList.add('edit-profile-container');
|
||||
this.title.innerText = 'Edit Profile';
|
||||
this.setTitle('EditAccount.Title');
|
||||
|
||||
const inputFields: InputField[] = [];
|
||||
|
||||
@ -30,17 +31,17 @@ export default class AppEditProfileTab extends SliderSuperTab {
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
this.firstNameInputField = new InputField({
|
||||
label: 'Name',
|
||||
label: 'Login.Register.FirstName.Placeholder',
|
||||
name: 'first-name',
|
||||
maxLength: 70
|
||||
});
|
||||
this.lastNameInputField = new InputField({
|
||||
label: 'Last Name',
|
||||
label: 'Login.Register.LastName.Placeholder',
|
||||
name: 'last-name',
|
||||
maxLength: 64
|
||||
});
|
||||
this.bioInputField = new InputField({
|
||||
label: 'Bio (optional)',
|
||||
label: 'AccountSettings.Bio',
|
||||
name: 'bio',
|
||||
maxLength: 70
|
||||
});
|
||||
@ -49,7 +50,7 @@ export default class AppEditProfileTab extends SliderSuperTab {
|
||||
|
||||
const caption = document.createElement('div');
|
||||
caption.classList.add('caption');
|
||||
caption.innerHTML = 'Any details such as age, occupation or city. Example:<br>23 y.o. designer from San Francisco.';
|
||||
i18n_({element: caption, key: 'Bio.Description'});
|
||||
|
||||
inputFields.push(this.firstNameInputField, this.lastNameInputField, this.bioInputField);
|
||||
this.scrollable.append(inputWrapper, caption);
|
||||
@ -68,14 +69,14 @@ export default class AppEditProfileTab extends SliderSuperTab {
|
||||
{
|
||||
const h2 = document.createElement('div');
|
||||
h2.classList.add('sidebar-left-h2');
|
||||
h2.innerText = 'Username';
|
||||
i18n_({element: h2, key: 'EditAccount.Username'});
|
||||
|
||||
const inputWrapper = document.createElement('div');
|
||||
inputWrapper.classList.add('input-wrapper');
|
||||
|
||||
this.usernameInputField = new UsernameInputField({
|
||||
peerId: 0,
|
||||
label: 'Username (optional)',
|
||||
label: 'EditAccount.Username',
|
||||
name: 'username',
|
||||
plainText: true,
|
||||
listenerSetter: this.listenerSetter,
|
||||
|
@ -32,7 +32,7 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
|
||||
const btnMenu = ButtonMenuToggle({}, 'bottom-left', [{
|
||||
icon: 'logout',
|
||||
text: 'Log Out',
|
||||
text: 'EditAccount.Logout',
|
||||
onClick: () => {
|
||||
apiManager.logOut();
|
||||
}
|
||||
@ -96,12 +96,12 @@ export default class AppSettingsTab extends SliderSuperTab {
|
||||
buttonsDiv.classList.add('profile-buttons');
|
||||
|
||||
const className = 'profile-button btn-primary btn-transparent';
|
||||
buttonsDiv.append(this.buttons.edit = Button(className, {icon: 'edit', text: 'Edit Profile'}));
|
||||
buttonsDiv.append(this.buttons.folders = Button(className, {icon: 'folder', text: 'Chat Folders'}));
|
||||
buttonsDiv.append(this.buttons.general = Button(className, {icon: 'settings', text: 'General Settings'}));
|
||||
buttonsDiv.append(this.buttons.notifications = Button(className, {icon: 'unmute', text: 'Notifications'}));
|
||||
buttonsDiv.append(this.buttons.privacy = Button(className, {icon: 'lock', text: 'Privacy and Security'}));
|
||||
buttonsDiv.append(this.buttons.language = Button(className, {icon: 'language', text: 'Language', disabled: true}));
|
||||
buttonsDiv.append(this.buttons.edit = Button(className, {icon: 'edit', text: 'EditAccount.Title'}));
|
||||
buttonsDiv.append(this.buttons.folders = Button(className, {icon: 'folder', text: 'AccountSettings.Filters'}));
|
||||
buttonsDiv.append(this.buttons.general = Button(className, {icon: 'settings', text: 'Telegram.GeneralSettingsViewController'}));
|
||||
buttonsDiv.append(this.buttons.notifications = Button(className, {icon: 'unmute', text: 'AccountSettings.Notifications'}));
|
||||
buttonsDiv.append(this.buttons.privacy = Button(className, {icon: 'lock', text: 'AccountSettings.PrivacyAndSecurity'}));
|
||||
buttonsDiv.append(this.buttons.language = Button(className, {icon: 'language', text: 'AccountSettings.Language'}));
|
||||
|
||||
this.scrollable.append(this.avatarElem, this.nameDiv, this.phoneDiv, buttonsDiv);
|
||||
this.scrollable.container.classList.add('profile-content-wrapper');
|
||||
|
@ -1,5 +1,6 @@
|
||||
import EventListenerBase from "../helpers/eventListenerBase";
|
||||
import ListenerSetter from "../helpers/listenerSetter";
|
||||
import { i18n, LangPackKey } from "../lib/langPack";
|
||||
import ButtonIcon from "./buttonIcon";
|
||||
import Scrollable from "./scrollable";
|
||||
import SidebarSlider from "./slider";
|
||||
@ -92,6 +93,11 @@ export default class SliderSuperTab implements SliderTab {
|
||||
this.listenerSetter.removeAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected setTitle(key: LangPackKey) {
|
||||
this.title.innerHTML = '';
|
||||
this.title.append(i18n(key));
|
||||
}
|
||||
}
|
||||
|
||||
export class SliderSuperTabEventable extends SliderSuperTab {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { MOUNT_CLASS_TO } from "../config/debug";
|
||||
import { LangPackString } from "../layer";
|
||||
import apiManager from "./mtproto/mtprotoworker";
|
||||
|
||||
@ -31,8 +32,26 @@ export const langPack: {[actionType: string]: string} = {
|
||||
"messageActionBotAllowed": "You allowed this bot to message you when logged in {}"
|
||||
};
|
||||
|
||||
export namespace Internationalization {
|
||||
let strings: {[key: string]: LangPackString} = {};
|
||||
namespace Strings {
|
||||
export type Bio = 'Bio.Description';
|
||||
|
||||
export type LoginRegister = 'Login.Register.FirstName.Placeholder' | 'Login.Register.LastName.Placeholder';
|
||||
|
||||
export type EditAccount = 'EditAccount.Logout' | 'EditAccount.Title' | 'EditAccount.Title' | 'EditAccount.Username';
|
||||
|
||||
export type AccountSettings = 'AccountSettings.Filters' | 'AccountSettings.Notifications' | 'AccountSettings.PrivacyAndSecurity' | 'AccountSettings.Language' | 'AccountSettings.Bio';
|
||||
|
||||
export type Telegram = 'Telegram.GeneralSettingsViewController';
|
||||
|
||||
export type ChatFilters = 'ChatList.Filter.Header' | 'ChatList.Filter.NewTitle' | 'ChatList.Filter.List.Header' | 'ChatList.Filter.Recommended.Header' | 'ChatList.Filter.Recommended.Add' | 'ChatList.Filter.List.Title';
|
||||
|
||||
export type LangPackKey = AccountSettings | EditAccount | Telegram | ChatFilters | LoginRegister | Bio | string;
|
||||
}
|
||||
|
||||
export type LangPackKey = Strings.LangPackKey;
|
||||
|
||||
namespace I18n {
|
||||
let strings: Partial<{[key in LangPackKey]: LangPackString}> = {};
|
||||
|
||||
export function getLangPack(langCode: string) {
|
||||
return apiManager.invokeApi('langpack.getLangPack', {
|
||||
@ -41,14 +60,86 @@ export namespace Internationalization {
|
||||
}).then(langPack => {
|
||||
strings = {};
|
||||
for(const string of langPack.strings) {
|
||||
strings[string.key] = string;
|
||||
strings[string.key as LangPackKey] = string;
|
||||
}
|
||||
|
||||
const elements = Array.from(document.querySelectorAll(`.i18n`)) as HTMLElement[];
|
||||
elements.forEach(element => {
|
||||
const instance = weakMap.get(element);
|
||||
|
||||
if(instance) {
|
||||
instance.update();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function _(key: keyof typeof strings, ...args: any[]) {
|
||||
let str = strings[key];
|
||||
export function getString(key: LangPackKey, args?: any[]) {
|
||||
const str = strings[key];
|
||||
let out = '';
|
||||
|
||||
if(str) {
|
||||
if(str._ === 'langPackStringPluralized') {
|
||||
out = str.one_value;
|
||||
} else if(str._ === 'langPackString') {
|
||||
out = str.value;
|
||||
} else {
|
||||
out = '[' + key + ']';
|
||||
}
|
||||
} else {
|
||||
out = '[' + key + ']';
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
const weakMap: WeakMap<HTMLElement, IntlElement> = new WeakMap();
|
||||
|
||||
export type IntlElementOptions = {
|
||||
element?: HTMLElement,
|
||||
property?: 'innerHTML' | 'placeholder'
|
||||
key: LangPackKey,
|
||||
args?: any[]
|
||||
};
|
||||
export class IntlElement {
|
||||
public element: IntlElementOptions['element'];
|
||||
public key: IntlElementOptions['key'];
|
||||
public args: IntlElementOptions['args'];
|
||||
public property: IntlElementOptions['property'] = 'innerHTML';
|
||||
|
||||
return str;
|
||||
constructor(options: IntlElementOptions) {
|
||||
this.element = options.element || document.createElement('span');
|
||||
this.element.classList.add('i18n');
|
||||
|
||||
this.update(options);
|
||||
weakMap.set(this.element, this);
|
||||
}
|
||||
|
||||
public update(options?: IntlElementOptions) {
|
||||
if(options) {
|
||||
Object.assign(this, options);
|
||||
}
|
||||
|
||||
(this.element as any)[this.property] = getString(this.key, this.args);
|
||||
}
|
||||
}
|
||||
|
||||
export function i18n(key: LangPackKey, args?: any[]) {
|
||||
return new IntlElement({key, args}).element;
|
||||
}
|
||||
|
||||
export function i18n_(options: IntlElementOptions) {
|
||||
return new IntlElement(options).element;
|
||||
}
|
||||
}
|
||||
|
||||
export {I18n};
|
||||
export default I18n;
|
||||
|
||||
const i18n = I18n.i18n;
|
||||
export {i18n};
|
||||
|
||||
const i18n_ = I18n.i18n_;
|
||||
export {i18n_};
|
||||
|
||||
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.I18n = I18n);
|
||||
|
Loading…
x
Reference in New Issue
Block a user