i18n russian (#1049)

Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
Denis Bykhov 2022-02-23 22:10:11 +06:00 committed by GitHub
parent 7a8f581741
commit 3e4188dac3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
125 changed files with 1055 additions and 329 deletions

View File

@ -13,13 +13,11 @@
// limitations under the License.
//
import type { IntlString } from '@anticrm/platform'
import { Builder, Model, Prop, UX, TypeString, TypeTimestamp, Index } from '@anticrm/model'
import { Domain, IndexKind } from '@anticrm/core'
import core, { TAttachedDoc } from '@anticrm/model-core'
import type { Attachment, Photo } from '@anticrm/attachment'
import activity from '@anticrm/activity'
import type { Attachment, Photo } from '@anticrm/attachment'
import { Domain, IndexKind } from '@anticrm/core'
import { Builder, Index, Model, Prop, TypeString, TypeTimestamp, UX } from '@anticrm/model'
import core, { TAttachedDoc } from '@anticrm/model-core'
import view from '@anticrm/model-view'
import attachment from './plugin'
@ -28,28 +26,28 @@ export { attachmentOperation } from './migration'
export const DOMAIN_ATTACHMENT = 'attachment' as Domain
@Model(attachment.class.Attachment, core.class.AttachedDoc, DOMAIN_ATTACHMENT)
@UX('File' as IntlString)
@UX(attachment.string.File)
export class TAttachment extends TAttachedDoc implements Attachment {
@Prop(TypeString(), 'Name' as IntlString)
@Prop(TypeString(), attachment.string.Name)
@Index(IndexKind.FullText)
name!: string
@Prop(TypeString(), 'File' as IntlString)
@Prop(TypeString(), attachment.string.File)
file!: string
@Prop(TypeString(), 'Size' as IntlString)
@Prop(TypeString(), attachment.string.Size)
size!: number
@Prop(TypeString(), 'Type' as IntlString)
@Prop(TypeString(), attachment.string.Type)
@Index(IndexKind.FullText)
type!: string
@Prop(TypeTimestamp(), 'Date' as IntlString)
@Prop(TypeTimestamp(), attachment.string.Date)
lastModified!: number
}
@Model(attachment.class.Photo, attachment.class.Attachment)
@UX('Photo' as IntlString)
@UX(attachment.string.Photo)
export class TPhoto extends TAttachment implements Photo {}
export function createModel (builder: Builder): void {

View File

@ -27,7 +27,14 @@ export default mergeIds(attachmentId, attachment, {
AttachmentPresenter: '' as AnyComponent
},
string: {
AddAttachment: '' as IntlString
AddAttachment: '' as IntlString,
Files: '' as IntlString,
File: '' as IntlString,
Name: '' as IntlString,
Size: '' as IntlString,
Type: '' as IntlString,
Photo: '' as IntlString,
Date: '' as IntlString
},
ids: {
TxAttachmentCreate: '' as Ref<TxViewlet>

View File

@ -21,7 +21,6 @@ import { Builder, Index, Model, Prop, TypeMarkup, UX } from '@anticrm/model'
import core, { TAttachedDoc, TDoc, TSpace } from '@anticrm/model-core'
import view from '@anticrm/model-view'
import workbench from '@anticrm/model-workbench'
import type { IntlString } from '@anticrm/platform'
import { ObjectDDParticipant } from '@anticrm/view'
import chunter from './plugin'
@ -34,21 +33,21 @@ export class TChannel extends TSpace implements Channel {}
@Model(chunter.class.Message, core.class.Doc, DOMAIN_CHUNTER)
export class TMessage extends TDoc implements Message {
@Prop(TypeMarkup(), 'Content' as IntlString)
@Prop(TypeMarkup(), chunter.string.Content)
@Index(IndexKind.FullText)
content!: string
}
@Model(chunter.class.Comment, core.class.AttachedDoc, DOMAIN_COMMENT)
@UX('Comment' as IntlString)
@UX(chunter.string.Comment)
export class TComment extends TAttachedDoc implements Comment {
@Prop(TypeMarkup(), 'Message' as IntlString)
@Prop(TypeMarkup(), chunter.string.Message)
@Index(IndexKind.FullText)
message!: string
}
@Model(chunter.class.Backlink, chunter.class.Comment)
@UX('Reference' as IntlString, chunter.icon.Chunter)
@UX(chunter.string.Reference, chunter.icon.Chunter)
export class TBacklink extends TComment implements Backlink {
backlinkId!: Ref<Doc>
backlinkClass!: Ref<Class<Doc>>
@ -67,7 +66,7 @@ export function createModel (builder: Builder): void {
})
builder.createDoc(view.class.ViewletDescriptor, core.space.Model, {
label: 'Chat' as IntlString,
label: chunter.string.Chat,
icon: view.icon.Table,
component: chunter.component.ChannelView
}, chunter.viewlet.Chat)

View File

@ -31,7 +31,12 @@ export default mergeIds(chunterId, chunter, {
string: {
ApplicationLabelChunter: '' as IntlString,
LeftComment: '' as IntlString,
MentionedIn: '' as IntlString
MentionedIn: '' as IntlString,
Content: '' as IntlString,
Comment: '' as IntlString,
Message: '' as IntlString,
Reference: '' as IntlString,
Chat: '' as IntlString
},
viewlet: {
Chat: '' as Ref<ViewletDescriptor>

View File

@ -44,7 +44,7 @@ export class TChannelProvider extends TDoc implements ChannelProvider {
@Model(contact.class.Contact, core.class.Doc, DOMAIN_CONTACT)
@UX(contact.string.Contact, contact.icon.Person, undefined, 'name')
export class TContact extends TDoc implements Contact {
@Prop(TypeString(), 'Name' as IntlString)
@Prop(TypeString(), contact.string.Name)
@Index(IndexKind.FullText)
name!: string
@ -146,9 +146,9 @@ export function createModel (builder: Builder): void {
config: [
'',
'city',
{ presenter: attachment.component.AttachmentsPresenter, label: 'Files', sortingKey: 'attachments' },
{ presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
'modifiedOn',
{ presenter: view.component.RolePresenter, label: 'Role' },
{ presenter: view.component.RolePresenter, label: view.string.Role },
'$lookup.channels'
]
})
@ -173,9 +173,9 @@ export function createModel (builder: Builder): void {
contact.class.ChannelProvider,
core.space.Model,
{
label: 'Phone' as IntlString,
label: contact.string.Phone,
icon: contact.icon.Phone,
placeholder: '+1 555 333 7777' as IntlString
placeholder: contact.string.PhonePlaceholder
},
contact.channelProvider.Phone
)
@ -184,9 +184,9 @@ export function createModel (builder: Builder): void {
contact.class.ChannelProvider,
core.space.Model,
{
label: 'LinkedIn' as IntlString,
label: contact.string.LinkedIn,
icon: contact.icon.LinkedIn,
placeholder: 'https://linkedin.com/in/jappleseed' as IntlString
placeholder: contact.string.LinkedInPlaceholder
},
contact.channelProvider.LinkedIn
)
@ -195,9 +195,9 @@ export function createModel (builder: Builder): void {
contact.class.ChannelProvider,
core.space.Model,
{
label: 'Twitter' as IntlString,
label: contact.string.Twitter,
icon: contact.icon.Twitter,
placeholder: '@appleseed' as IntlString
placeholder: contact.string.AtPlaceHolder
},
contact.channelProvider.Twitter
)
@ -206,9 +206,9 @@ export function createModel (builder: Builder): void {
contact.class.ChannelProvider,
core.space.Model,
{
label: 'GitHub' as IntlString,
label: contact.string.GitHub,
icon: contact.icon.GitHub,
placeholder: '@appleseed' as IntlString
placeholder: contact.string.AtPlaceHolder
},
contact.channelProvider.GitHub
)
@ -217,9 +217,9 @@ export function createModel (builder: Builder): void {
contact.class.ChannelProvider,
core.space.Model,
{
label: 'Facebook' as IntlString,
label: contact.string.Facebook,
icon: contact.icon.Facebook,
placeholder: 'https://fb.com/jappleseed' as IntlString
placeholder: contact.string.FacebookPlaceholder
},
contact.channelProvider.Facebook
)

View File

@ -48,7 +48,16 @@ export default mergeIds(contactId, contact, {
Person: '' as IntlString,
Organization: '' as IntlString,
Employee: '' as IntlString,
Value: '' as IntlString
Value: '' as IntlString,
Phone: '' as IntlString,
PhonePlaceholder: '' as IntlString,
LinkedIn: '' as IntlString,
LinkedInPlaceholder: '' as IntlString,
AtPlaceHolder: '' as IntlString,
FacebookPlaceholder: '' as IntlString,
Twitter: '' as IntlString,
GitHub: '' as IntlString,
Facebook: '' as IntlString
},
completion: {
PersonQuery: '' as Resource<ObjectSearchFactory>,

View File

@ -15,10 +15,16 @@
import type { Class, Ref, Type } from '@anticrm/core'
import core, { coreId } from '@anticrm/core'
import { mergeIds } from '@anticrm/platform'
import { IntlString, mergeIds } from '@anticrm/platform'
export default mergeIds(coreId, core, {
class: {
Type: '' as Ref<Class<Type<any>>>
},
string: {
Name: '' as IntlString,
Description: '' as IntlString,
Private: '' as IntlString,
Archived: '' as IntlString
}
})

View File

@ -31,35 +31,35 @@ import core from './component'
// C O R E
@Model(core.class.Obj, core.class.Obj)
export class TObj implements Obj {
@Prop(TypeRef(core.class.Class), 'Class' as IntlString)
@Prop(TypeRef(core.class.Class), core.string.Class)
@Index(IndexKind.Indexed)
_class!: Ref<Class<this>>
}
@Model(core.class.Doc, core.class.Obj)
export class TDoc extends TObj implements Doc {
@Prop(TypeRef(core.class.Doc), 'Id' as IntlString)
@Prop(TypeRef(core.class.Doc), core.string.Id)
// @Index(IndexKind.Indexed) // - automatically indexed by default.
_id!: Ref<this>
@Prop(TypeRef(core.class.Space), 'Space' as IntlString)
@Prop(TypeRef(core.class.Space), core.string.Space)
@Index(IndexKind.Indexed)
space!: Ref<Space>
@Prop(TypeTimestamp(), 'Modified' as IntlString)
@Prop(TypeTimestamp(), core.string.Modified)
modifiedOn!: Timestamp
@Prop(TypeRef(core.class.Account), 'Modified By' as IntlString)
@Prop(TypeRef(core.class.Account), core.string.ModifiedBy)
modifiedBy!: Ref<Account>
}
@Model(core.class.AttachedDoc, core.class.Doc)
export class TAttachedDoc extends TDoc implements AttachedDoc {
@Prop(TypeRef(core.class.Doc), 'Attached to' as IntlString)
@Prop(TypeRef(core.class.Doc), core.string.AttachedTo)
@Index(IndexKind.Indexed)
attachedTo!: Ref<Doc>
@Prop(TypeRef(core.class.Class), 'Attached to class' as IntlString)
@Prop(TypeRef(core.class.Class), core.string.AttachedToClass)
@Index(IndexKind.Indexed)
attachedToClass!: Ref<Class<Doc>>

View File

@ -28,12 +28,8 @@ import {
TRefTo,
TType,
TTypeBoolean,
TTypeDate,
TTypeString,
TTypeMarkup,
TTypeTimestamp,
TVersion,
TTypeNumber
TTypeDate, TTypeMarkup, TTypeNumber, TTypeString, TTypeTimestamp,
TVersion
} from './core'
import { TAccount, TSpace } from './security'
import {

View File

@ -15,7 +15,6 @@
import { Account, Arr, DOMAIN_MODEL, IndexKind, Ref, Space } from '@anticrm/core'
import { Index, Model, Prop, TypeBoolean, TypeString } from '@anticrm/model'
import type { IntlString } from '@anticrm/platform'
import core from './component'
import { TDoc } from './core'
@ -23,18 +22,18 @@ import { TDoc } from './core'
@Model(core.class.Space, core.class.Doc, DOMAIN_MODEL)
export class TSpace extends TDoc implements Space {
@Prop(TypeString(), 'Name' as IntlString)
@Prop(TypeString(), core.string.Name)
@Index(IndexKind.FullText)
name!: string
@Prop(TypeString(), 'Description' as IntlString)
@Prop(TypeString(), core.string.Description)
@Index(IndexKind.FullText)
description!: string
@Prop(TypeBoolean(), 'Private' as IntlString)
@Prop(TypeBoolean(), core.string.Private)
private!: boolean
@Prop(TypeBoolean(), 'Archived' as IntlString)
@Prop(TypeBoolean(), core.string.Archived)
archived!: boolean
members!: Arr<Ref<Account>>

View File

@ -14,20 +14,19 @@
// limitations under the License.
//
import type { IntlString } from '@anticrm/platform'
import { Builder, Model, TypeString, Prop, ArrOf, TypeBoolean, Index } from '@anticrm/model'
import core, { TAttachedDoc } from '@anticrm/model-core'
import contact from '@anticrm/model-contact'
import gmail from './plugin'
import type { Message, SharedMessage, SharedMessages } from '@anticrm/gmail'
import { Domain, IndexKind, Type } from '@anticrm/core'
import setting from '@anticrm/setting'
import activity from '@anticrm/activity'
import { Domain, IndexKind, Type } from '@anticrm/core'
import type { Message, SharedMessage, SharedMessages } from '@anticrm/gmail'
import { ArrOf, Builder, Index, Model, Prop, TypeBoolean, TypeString } from '@anticrm/model'
import contact from '@anticrm/model-contact'
import core, { TAttachedDoc } from '@anticrm/model-core'
import setting from '@anticrm/setting'
import gmail from './plugin'
export const DOMAIN_GMAIL = 'gmail' as Domain
function TypeSharedMessage (): Type<SharedMessage> {
return { _class: gmail.class.SharedMessage, label: 'Shared message' as IntlString }
return { _class: gmail.class.SharedMessage, label: gmail.string.SharedMessage }
}
@Model(gmail.class.Message, core.class.AttachedDoc, DOMAIN_GMAIL)
@ -35,44 +34,44 @@ export class TMessage extends TAttachedDoc implements Message {
@Prop(TypeString(), gmail.string.MessageID)
messageId!: string
@Prop(TypeString(), 'ReplyTo' as IntlString)
@Prop(TypeString(), gmail.string.ReplyTo)
@Index(IndexKind.FullText)
replyTo?: string
@Prop(TypeString(), 'From' as IntlString)
@Prop(TypeString(), gmail.string.From)
@Index(IndexKind.FullText)
from!: string
@Prop(TypeString(), 'To' as IntlString)
@Prop(TypeString(), gmail.string.To)
@Index(IndexKind.FullText)
to!: string
@Prop(TypeString(), 'Contact' as IntlString)
@Prop(TypeString(), contact.string.Contact)
@Index(IndexKind.FullText)
contact!: string
@Prop(TypeString(), 'Subject' as IntlString)
@Prop(TypeString(), gmail.string.Subject)
@Index(IndexKind.FullText)
subject!: string
@Prop(TypeString(), 'Message' as IntlString)
@Prop(TypeString(), gmail.string.Message)
@Index(IndexKind.FullText)
content!: string
@Prop(TypeString(), 'Message' as IntlString)
@Prop(TypeString(), gmail.string.Message)
@Index(IndexKind.FullText)
textContent!: string
@Prop(ArrOf(TypeString()), 'Copy' as IntlString)
@Prop(ArrOf(TypeString()), gmail.string.Copy)
copy?: string[]
@Prop(TypeBoolean(), 'Incoming' as IntlString)
@Prop(TypeBoolean(), gmail.string.Incoming)
incoming!: boolean
}
@Model(gmail.class.SharedMessages, core.class.AttachedDoc, DOMAIN_GMAIL)
export class TSharedMessages extends TAttachedDoc implements SharedMessages {
@Prop(ArrOf(TypeSharedMessage()), 'Messages' as IntlString)
@Prop(ArrOf(TypeSharedMessage()), gmail.string.Messages)
messages!: SharedMessage[]
}
@ -83,9 +82,9 @@ export function createModel (builder: Builder): void {
contact.class.ChannelProvider,
core.space.Model,
{
label: 'Email' as IntlString,
label: gmail.string.Email,
icon: contact.icon.Email,
placeholder: 'john.appleseed@apple.com' as IntlString,
placeholder: gmail.string.EmailPlaceholder,
presenter: gmail.component.Main,
integrationType: gmail.integrationType.Gmail
},

View File

@ -26,7 +26,14 @@ export default mergeIds(gmailId, gmail, {
MessageID: '' as IntlString,
IntegrationLabel: '' as IntlString,
IntegrationDescription: '' as IntlString,
SharedMessages: '' as IntlString
SharedMessages: '' as IntlString,
SharedMessage: '' as IntlString,
ReplyTo: '' as IntlString,
Message: '' as IntlString,
Messages: '' as IntlString,
Incoming: '' as IntlString,
Email: '' as IntlString,
EmailPlaceholder: '' as IntlString
},
ids: {
TxSharedCreate: '' as Ref<TxViewlet>

View File

@ -20,7 +20,6 @@ import { Builder, Collection, Index, Model, Prop, TypeRef, TypeString, UX } from
import attachment from '@anticrm/model-attachment'
import core, { TAttachedDoc } from '@anticrm/model-core'
import workbench from '@anticrm/model-workbench'
import type { IntlString } from '@anticrm/platform'
import type { } from '@anticrm/view'
import view from '@anticrm/view'
import inventory from './plugin'
@ -29,7 +28,7 @@ export const DOMAIN_INVENTORY = 'inventory' as Domain
@Model(inventory.class.Category, core.class.AttachedDoc, DOMAIN_INVENTORY)
@UX(inventory.string.Category, inventory.icon.Categories, undefined, 'name')
export class TCategory extends TAttachedDoc implements Category {
@Prop(TypeString(), 'Name' as IntlString)
@Prop(TypeString(), core.string.Name)
@Index(IndexKind.FullText)
name!: string
}
@ -41,7 +40,7 @@ export class TProduct extends TAttachedDoc implements Product {
@Prop(TypeRef(inventory.class.Category), inventory.string.Category)
declare attachedTo: Ref<Category>
@Prop(TypeString(), 'Name' as IntlString)
@Prop(TypeString(), core.string.Name)
@Index(IndexKind.FullText)
name!: string
@ -51,7 +50,7 @@ export class TProduct extends TAttachedDoc implements Product {
@Prop(Collection(inventory.class.Variant), inventory.string.Variants)
variants?: number
@Prop(Collection(attachment.class.Attachment), 'Attachments' as IntlString)
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments)
attachments?: number
}
@ -62,7 +61,7 @@ export class TVariant extends TAttachedDoc implements Variant {
@Prop(TypeRef(inventory.class.Product), inventory.string.Product)
declare attachedTo: Ref<Product>
@Prop(TypeString(), 'Name' as IntlString)
@Prop(TypeString(), core.string.Name)
@Index(IndexKind.FullText)
name!: string

View File

@ -13,7 +13,7 @@
// limitations under the License.
//
import core, { TxOperations } from '@anticrm/core'
import core, { Doc, Space, TxOperations } from '@anticrm/core'
import type { Client, Ref } from '@anticrm/core'
import task, { createKanban } from '@anticrm/task'
import type { KanbanTemplate } from '@anticrm/task'
@ -54,7 +54,7 @@ const defaultKanban = {
const createDefaultKanbanTemplate = async (client: TxOperations): Promise<Ref<KanbanTemplate>> =>
await createKanbanTemplate(client, {
kanbanId: lead.template.DefaultFunnel,
space: lead.space.FunnelTemplates,
space: lead.space.FunnelTemplates as Ref<Doc> as Ref<Space>,
title: 'Default funnel',
states: defaultKanban.states,
doneStates: defaultKanban.doneStates

View File

@ -26,8 +26,7 @@ import core from '@anticrm/model-core'
import task, { TSpaceWithStates, TTask } from '@anticrm/model-task'
import view from '@anticrm/model-view'
import workbench from '@anticrm/model-workbench'
import type { IntlString } from '@anticrm/platform'
import type {} from '@anticrm/view'
import type { } from '@anticrm/view'
import lead from './plugin'
@Model(lead.class.Funnel, task.class.SpaceWithStates)
@ -35,32 +34,32 @@ import lead from './plugin'
export class TFunnel extends TSpaceWithStates implements Funnel {}
@Model(lead.class.Lead, task.class.Task)
@UX('Lead' as IntlString, lead.icon.Lead, undefined, 'title')
@UX(lead.string.Lead, lead.icon.Lead, undefined, 'title')
export class TLead extends TTask implements Lead {
@Prop(TypeRef(contact.class.Contact), lead.string.Customer)
declare attachedTo: Ref<Customer>
@Prop(TypeString(), 'Title' as IntlString)
@Prop(TypeString(), lead.string.Title)
@Index(IndexKind.FullText)
title!: string
@Prop(Collection(chunter.class.Comment), 'Comments' as IntlString)
@Prop(Collection(chunter.class.Comment), chunter.string.Comments)
comments?: number
@Prop(Collection(attachment.class.Attachment), 'Attachments' as IntlString)
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments)
attachments?: number
@Prop(TypeRef(contact.class.Employee), 'Assignee' as IntlString)
@Prop(TypeRef(contact.class.Employee), lead.string.Assignee)
declare assignee: Ref<Employee> | null
}
@Mixin(lead.mixin.Customer, contact.class.Contact)
@UX('Customer' as IntlString, lead.icon.LeadApplication)
@UX(lead.string.Customer, lead.icon.LeadApplication)
export class TCustomer extends TPerson implements Customer {
@Prop(Collection(lead.class.Lead), 'Leads' as IntlString)
@Prop(Collection(lead.class.Lead), lead.string.Leads)
leads?: number
@Prop(TypeString(), 'Description' as IntlString)
@Prop(TypeString(), core.string.Description)
@Index(IndexKind.FullText)
description!: string
}
@ -134,7 +133,7 @@ export function createModel (builder: Builder): void {
const leadLookup: Lookup<Lead> =
{
attachedTo: [contact.class.Contact, { _id: { channels: lead.mixin.Customer } }],
attachedTo: [lead.mixin.Customer, { _id: { channels: contact.class.Channel } }],
state: task.class.State
}
@ -149,8 +148,8 @@ export function createModel (builder: Builder): void {
'',
'$lookup.attachedTo',
'$lookup.state',
{ presenter: attachment.component.AttachmentsPresenter, label: 'Files', sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: 'Comments', sortingKey: 'comments' },
{ presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: chunter.string.Comments, sortingKey: 'comments' },
'modifiedOn',
'$lookup.attachedTo.$lookup.channels'
]
@ -188,11 +187,8 @@ export function createModel (builder: Builder): void {
task.class.KanbanTemplateSpace,
core.space.Model,
{
name: 'Funnels',
description: 'Manage funnel statuses',
members: [],
private: false,
archived: false,
name: lead.string.Funnels,
description: lead.string.ManageFunnelStatuses,
icon: lead.component.TemplatesIcon
},
lead.space.FunnelTemplates

View File

@ -26,7 +26,11 @@ export default mergeIds(leadId, lead, {
string: {
Funnel: '' as IntlString,
Funnels: '' as IntlString,
LeadApplication: '' as IntlString
LeadApplication: '' as IntlString,
Lead: '' as IntlString,
Title: '' as IntlString,
Assignee: '' as IntlString,
ManageFunnelStatuses: '' as IntlString
},
component: {
CreateFunnel: '' as AnyComponent,

View File

@ -29,7 +29,7 @@ export class TLastView extends TAttachedDoc implements LastView {
@Prop(TypeTimestamp(), notification.string.LastView)
lastView!: Timestamp
@Prop(TypeRef(core.class.Account), 'Modified By' as IntlString)
@Prop(TypeRef(core.class.Account), core.string.ModifiedBy)
user!: Ref<Account>
}

View File

@ -13,7 +13,7 @@
// limitations under the License.
//
import core, { Ref, TxOperations } from '@anticrm/core'
import core, { Doc, Ref, Space, TxOperations } from '@anticrm/core'
import type { Client } from '@anticrm/core'
import { createKanbanTemplate } from '@anticrm/model-task'
@ -54,7 +54,7 @@ const defaultKanban = {
export const createDefaultKanbanTemplate = async (client: TxOperations): Promise<Ref<KanbanTemplate>> =>
await createKanbanTemplate(client, {
kanbanId: recruit.template.DefaultVacancy,
space: recruit.space.VacancyTemplates,
space: recruit.space.VacancyTemplates as Ref<Doc> as Ref<Space>,
title: 'Default vacancy',
states: defaultKanban.states,
doneStates: defaultKanban.doneStates

View File

@ -38,28 +38,27 @@ import tags from '@anticrm/model-tags'
import task, { TSpaceWithStates, TTask } from '@anticrm/model-task'
import view from '@anticrm/model-view'
import workbench from '@anticrm/model-workbench'
import type { IntlString } from '@anticrm/platform'
import { Applicant, Candidate, Candidates, Vacancy } from '@anticrm/recruit'
import recruit from './plugin'
@Model(recruit.class.Vacancy, task.class.SpaceWithStates)
@UX(recruit.string.Vacancy, recruit.icon.Vacancy)
export class TVacancy extends TSpaceWithStates implements Vacancy {
@Prop(TypeMarkup(), 'Full description' as IntlString)
@Prop(TypeMarkup(), recruit.string.FullDescription)
@Index(IndexKind.FullText)
fullDescription?: string
@Prop(Collection(attachment.class.Attachment), 'Attachments' as IntlString)
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments)
attachments?: number
@Prop(TypeDate(), 'Due date' as IntlString, recruit.icon.Calendar)
@Prop(TypeDate(), recruit.string.Due, recruit.icon.Calendar)
dueTo?: Timestamp
@Prop(TypeString(), 'Location' as IntlString, recruit.icon.Location)
@Prop(TypeString(), recruit.string.Location, recruit.icon.Location)
@Index(IndexKind.FullText)
location?: string
@Prop(TypeString(), 'Company' as IntlString, contact.icon.Company)
@Prop(TypeString(), recruit.string.Company, contact.icon.Company)
@Index(IndexKind.FullText)
company?: string
}
@ -69,22 +68,22 @@ export class TVacancy extends TSpaceWithStates implements Vacancy {
export class TCandidates extends TSpace implements Candidates {}
@Mixin(recruit.mixin.Candidate, contact.class.Person)
@UX('Candidate' as IntlString, recruit.icon.RecruitApplication)
@UX(recruit.string.Candidate, recruit.icon.RecruitApplication)
export class TCandidate extends TPerson implements Candidate {
@Prop(TypeString(), 'Title' as IntlString)
@Prop(TypeString(), recruit.string.Title)
@Index(IndexKind.FullText)
title?: string
@Prop(Collection(recruit.class.Applicant), 'Applications' as IntlString)
@Prop(Collection(recruit.class.Applicant), recruit.string.Applications)
applications?: number
@Prop(TypeBoolean(), 'Onsite' as IntlString)
@Prop(TypeBoolean(), recruit.string.Onsite)
onsite?: boolean
@Prop(TypeBoolean(), 'Remote' as IntlString)
@Prop(TypeBoolean(), recruit.string.Remote)
remote?: boolean
@Prop(TypeString(), 'Source' as IntlString)
@Prop(TypeString(), recruit.string.Source)
@Index(IndexKind.FullText)
source?: string
@ -93,7 +92,7 @@ export class TCandidate extends TPerson implements Candidate {
}
@Model(recruit.class.Applicant, task.class.Task)
@UX(recruit.string.Application, recruit.icon.Application, 'APP' as IntlString, 'number')
@UX(recruit.string.Application, recruit.icon.Application, recruit.string.ApplicationShort, 'number')
export class TApplicant extends TTask implements Applicant {
// We need to declare, to provide property with label
@Prop(TypeRef(recruit.mixin.Candidate), recruit.string.Candidate)
@ -201,9 +200,9 @@ export function createModel (builder: Builder): void {
'',
'title',
'city',
{ presenter: recruit.component.ApplicationsPresenter, label: 'Apps', sortingKey: 'applications' },
{ presenter: attachment.component.AttachmentsPresenter, label: 'Files', sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: 'Comments', sortingKey: 'comments' },
{ presenter: recruit.component.ApplicationsPresenter, label: recruit.string.ApplicationsShort, sortingKey: 'applications' },
{ presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: chunter.string.Comments, sortingKey: 'comments' },
{
// key: '$lookup.skills', // Required, since presenter require list of tag references or '' and TagsPopupPresenter
presenter: tags.component.TagsPresenter, // tags.component.TagsPresenter,
@ -239,8 +238,8 @@ export function createModel (builder: Builder): void {
'$lookup.assignee',
'$lookup.state',
'$lookup.doneState',
{ presenter: attachment.component.AttachmentsPresenter, label: 'Files', sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: 'Comments', sortingKey: 'comments' },
{ presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: chunter.string.Comments, sortingKey: 'comments' },
'modifiedOn',
'$lookup.attachedTo.$lookup.channels'
]
@ -274,8 +273,8 @@ export function createModel (builder: Builder): void {
'$lookup.assignee',
'$lookup.state',
'$lookup.doneState',
{ presenter: attachment.component.AttachmentsPresenter, label: 'Files', sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: 'Comments', sortingKey: 'comments' },
{ presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: chunter.string.Comments, sortingKey: 'comments' },
'modifiedOn',
'$lookup.attachedTo.$lookup.channels'
]
@ -305,7 +304,7 @@ export function createModel (builder: Builder): void {
view.class.Action,
core.space.Model,
{
label: 'Create application' as IntlString,
label: recruit.string.CreateApplication,
icon: recruit.icon.Create,
action: recruit.actionImpl.CreateApplication
},
@ -326,11 +325,8 @@ export function createModel (builder: Builder): void {
task.class.KanbanTemplateSpace,
core.space.Model,
{
name: 'Vacancies',
description: 'Manage vacancy statuses',
members: [],
private: false,
archived: false,
name: recruit.string.Vacancies,
description: recruit.string.ManageVacancyStatuses,
icon: recruit.component.TemplatesIcon
},
recruit.space.VacancyTemplates

View File

@ -31,12 +31,18 @@ export default mergeIds(recruitId, recruit, {
CreateApplication: '' as Resource<(object: Doc) => Promise<void>>
},
string: {
ApplicationShort: '' as IntlString,
ApplicationsShort: '' as IntlString,
RecruitApplication: '' as IntlString,
Vacancies: '' as IntlString,
CandidatePools: '' as IntlString,
SearchApplication: '' as IntlString,
Application: '' as IntlString,
AssignedRecruiter: '' as IntlString
AssignedRecruiter: '' as IntlString,
FullDescription: '' as IntlString,
Due: '' as IntlString,
Source: '' as IntlString,
ManageVacancyStatuses: '' as IntlString
},
validator: {
ApplicantValidator: '' as Resource<<T extends Doc>(doc: T, client: Client) => Promise<Status>>

View File

@ -13,7 +13,7 @@
// limitations under the License.
//
import core, { TxOperations } from '@anticrm/core'
import core, { Doc, TxOperations } from '@anticrm/core'
import type { Client, Ref, Space } from '@anticrm/core'
import { createKanban, genRanks } from '@anticrm/task'
import type { DoneStateTemplate, KanbanTemplate, StateTemplate } from '@anticrm/task'
@ -110,7 +110,7 @@ export async function createKanbanTemplate (client: TxOperations, data: KanbanTe
const createDefaultKanbanTemplate = async (client: TxOperations): Promise<Ref<KanbanTemplate>> =>
await createKanbanTemplate(client, {
kanbanId: task.template.DefaultProject,
space: task.space.ProjectTemplates,
space: task.space.ProjectTemplates as Ref<Doc> as Ref<Space>,
title: 'Default project',
states: defaultKanban.states,
doneStates: defaultKanban.doneStates

View File

@ -35,7 +35,7 @@ import core, { TAttachedDoc, TClass, TDoc, TSpace } from '@anticrm/model-core'
import presentation from '@anticrm/model-presentation'
import view from '@anticrm/model-view'
import workbench from '@anticrm/model-workbench'
import type { IntlString } from '@anticrm/platform'
import { IntlString } from '@anticrm/platform'
import type {
DoneState, DoneStateTemplate, Issue, Kanban,
KanbanCard, KanbanTemplate, KanbanTemplateSpace, LostState, LostStateTemplate, Project, Sequence, State, StateTemplate, Task,
@ -125,7 +125,7 @@ export class TSpaceWithStates extends TSpace {}
export class TProject extends TSpaceWithStates implements Project {}
@Model(task.class.Issue, task.class.Task, DOMAIN_TASK)
@UX('Task' as IntlString, task.icon.Task, 'Task' as IntlString, 'number')
@UX(task.string.Task, task.icon.Task, task.string.Task, 'number')
export class TIssue extends TTask implements Issue {
// We need to declare, to provide property with label
@Prop(TypeRef(core.class.Doc), task.string.TaskParent)
@ -142,7 +142,7 @@ export class TIssue extends TTask implements Issue {
@Prop(Collection(chunter.class.Comment), task.string.TaskComments)
comments!: number
@Prop(Collection(attachment.class.Attachment), task.string.TaskAttachments)
@Prop(Collection(attachment.class.Attachment), attachment.string.Attachments)
attachments!: number
@Prop(TypeString(), task.string.TaskLabels)
@ -165,8 +165,10 @@ export class TKanban extends TDoc implements Kanban {
attachedTo!: Ref<Space>
}
@Model(task.class.KanbanTemplateSpace, core.class.Space, DOMAIN_MODEL)
export class TKanbanTemplateSpace extends TSpace implements KanbanTemplateSpace {
@Model(task.class.KanbanTemplateSpace, core.class.Doc, DOMAIN_MODEL)
export class TKanbanTemplateSpace extends TDoc implements KanbanTemplateSpace {
name!: IntlString
description!: IntlString
icon!: AnyComponent
}
@ -293,8 +295,8 @@ export function createModel (builder: Builder): void {
'',
'name',
'$lookup.assignee',
{ presenter: attachment.component.AttachmentsPresenter, label: 'Files', sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: 'Comments', sortingKey: 'comments' },
{ presenter: attachment.component.AttachmentsPresenter, label: attachment.string.Files, sortingKey: 'attachments' },
{ presenter: chunter.component.CommentsPresenter, label: chunter.string.Comments, sortingKey: 'comments' },
'modifiedOn'
]
})
@ -344,11 +346,8 @@ export function createModel (builder: Builder): void {
task.class.KanbanTemplateSpace,
core.space.Model,
{
name: 'Projects',
description: 'Manage project statuses',
members: [],
private: false,
archived: false,
name: task.string.Projects,
description: task.string.ManageProjectStatues,
icon: task.component.TemplatesIcon
},
task.space.ProjectTemplates

View File

@ -70,7 +70,6 @@ export default mergeIds(taskId, task, {
TaskParent: '' as IntlString,
IssueName: '' as IntlString,
TaskComments: '' as IntlString,
TaskAttachments: '' as IntlString,
TaskLabels: '' as IntlString,
StateTemplateTitle: '' as IntlString,
StateTemplateColor: '' as IntlString,
@ -84,7 +83,8 @@ export default mergeIds(taskId, task, {
Kanban: '' as IntlString,
ApplicationLabelTask: '' as IntlString,
Projects: '' as IntlString,
SearchTask: '' as IntlString
SearchTask: '' as IntlString,
ManageProjectStatues: '' as IntlString
},
space: {
TasksPublic: '' as Ref<Space>

View File

@ -14,7 +14,6 @@
// limitations under the License.
//
import type { IntlString } from '@anticrm/platform'
import { Builder, Model, TypeString, TypeBoolean, Prop, ArrOf, Index } from '@anticrm/model'
import core, { TAttachedDoc } from '@anticrm/model-core'
import contact from '@anticrm/model-contact'
@ -27,22 +26,22 @@ import activity from '@anticrm/activity'
export const DOMAIN_TELEGRAM = 'telegram' as Domain
function TypeSharedMessage (): Type<SharedTelegramMessage> {
return { _class: telegram.class.SharedMessage, label: 'Shared message' as IntlString }
return { _class: telegram.class.SharedMessage, label: telegram.string.SharedMessage }
}
@Model(telegram.class.Message, core.class.AttachedDoc, DOMAIN_TELEGRAM)
export class TTelegramMessage extends TAttachedDoc implements TelegramMessage {
@Prop(TypeString(), 'Content' as IntlString)
@Prop(TypeString(), telegram.string.Content)
@Index(IndexKind.FullText)
content!: string
@Prop(TypeBoolean(), 'Incoming' as IntlString)
@Prop(TypeBoolean(), telegram.string.Incoming)
incoming!: boolean
}
@Model(telegram.class.SharedMessages, core.class.AttachedDoc, DOMAIN_TELEGRAM)
export class TSharedTelegramMessages extends TAttachedDoc implements SharedTelegramMessages {
@Prop(ArrOf(TypeSharedMessage()), 'Messages' as IntlString)
@Prop(ArrOf(TypeSharedMessage()), telegram.string.Messages)
messages!: SharedTelegramMessage[]
}
@ -53,9 +52,9 @@ export function createModel (builder: Builder): void {
contact.class.ChannelProvider,
core.space.Model,
{
label: 'Telegram' as IntlString,
label: telegram.string.Telegram,
icon: contact.icon.Telegram,
placeholder: '@appleseed' as IntlString,
placeholder: contact.string.AtPlaceHolder,
presenter: telegram.component.Chat,
integrationType: telegram.integrationType.Telegram
},
@ -66,8 +65,8 @@ export function createModel (builder: Builder): void {
setting.class.IntegrationType,
core.space.Model,
{
label: 'Telegram' as IntlString,
description: 'Use telegram integration' as IntlString,
label: telegram.string.Telegram,
description: telegram.string.TelegramIntegrationDesc,
icon: telegram.component.IconTelegram,
createComponent: telegram.component.Connect,
onDisconnect: telegram.handler.DisconnectHandler

View File

@ -23,7 +23,13 @@ import type { TxViewlet } from '@anticrm/activity'
export default mergeIds(telegramId, telegram, {
string: {
SharedMessages: '' as IntlString
SharedMessages: '' as IntlString,
SharedMessage: '' as IntlString,
Content: '' as IntlString,
Incoming: '' as IntlString,
Messages: '' as IntlString,
Telegram: '' as IntlString,
TelegramIntegrationDesc: '' as IntlString
},
ids: {
TxSharedCreate: '' as Ref<TxViewlet>

View File

@ -18,7 +18,6 @@ import { Domain, IndexKind } from '@anticrm/core'
import { Builder, Index, Model, Prop, TypeString } from '@anticrm/model'
import core, { TDoc } from '@anticrm/model-core'
import textEditor from '@anticrm/model-text-editor'
import { IntlString } from '@anticrm/platform'
import setting from '@anticrm/setting'
import type { MessageTemplate } from '@anticrm/templates'
import templates from './plugin'
@ -27,11 +26,11 @@ export const DOMAIN_TEMPLATES = 'templates' as Domain
@Model(templates.class.MessageTemplate, core.class.Doc, DOMAIN_TEMPLATES)
export class TMessageTemplate extends TDoc implements MessageTemplate {
@Prop(TypeString(), 'Title' as IntlString)
@Prop(TypeString(), templates.string.Title)
@Index(IndexKind.FullText)
title!: string;
@Prop(TypeString(), 'Message' as IntlString)
@Prop(TypeString(), templates.string.Message)
@Index(IndexKind.FullText)
message!: string;
}

View File

@ -15,7 +15,7 @@
//
import { Ref } from '@anticrm/core'
import { mergeIds, Resource } from '@anticrm/platform'
import { IntlString, mergeIds, Resource } from '@anticrm/platform'
import { SettingsCategory } from '@anticrm/setting'
import { templatesId } from '@anticrm/templates'
import templates from '@anticrm/templates-resources/src/plugin'
@ -35,5 +35,9 @@ export default mergeIds(templatesId, templates, {
},
action: {
ShowTemplates: '' as Resource<RefInputAction>
},
string: {
Title: '' as IntlString,
Message: '' as IntlString
}
})

View File

@ -171,7 +171,7 @@ export function createModel (builder: Builder): void {
view.class.ViewletDescriptor,
core.space.Model,
{
label: 'Table' as IntlString,
label: view.string.Table,
icon: view.icon.Table,
component: view.component.TableView
},
@ -182,7 +182,7 @@ export function createModel (builder: Builder): void {
view.class.Action,
core.space.Model,
{
label: 'Delete' as IntlString,
label: view.string.Delete,
icon: view.icon.Delete,
action: view.actionImpl.Delete
},
@ -198,7 +198,7 @@ export function createModel (builder: Builder): void {
view.class.Action,
core.space.Model,
{
label: 'Move' as IntlString,
label: view.string.Move,
icon: view.icon.Move,
action: view.actionImpl.Move
},

View File

@ -13,7 +13,7 @@
// limitations under the License.
//
import { mergeIds } from '@anticrm/platform'
import { IntlString, mergeIds } from '@anticrm/platform'
import type { Ref, Doc } from '@anticrm/core'
import type { Resource } from '@anticrm/platform'
import type { AnyComponent } from '@anticrm/ui'
@ -41,5 +41,11 @@ export default mergeIds(viewId, view, {
DatePresenter: '' as AnyComponent,
TableView: '' as AnyComponent,
RolePresenter: '' as AnyComponent
},
string: {
Table: '' as IntlString,
Delete: '' as IntlString,
Move: '' as IntlString,
Role: '' as IntlString
}
})

View File

@ -23,7 +23,7 @@ import core, { TDoc, TClass } from '@anticrm/model-core'
import workbench from './plugin'
@Model(workbench.class.Application, core.class.Doc, DOMAIN_MODEL)
@UX('Application' as IntlString)
@UX(workbench.string.Application)
export class TApplication extends TDoc implements Application {
label!: IntlString
icon!: Asset

View File

@ -24,7 +24,8 @@ export default mergeIds(workbenchId, workbench, {
Archive: '' as AnyComponent
},
string: {
Archive: '' as IntlString
Archive: '' as IntlString,
Application: '' as IntlString
},
function: {
HasArchiveSpaces: '' as Resource<(spaces: Space[]) => boolean>

View File

@ -0,0 +1,15 @@
{
"string": {
"Id": "Id",
"Space": "Space",
"Modified": "Modified",
"ModifiedBy": "Modified by",
"Class": "Class",
"AttachedTo": "Attached to",
"AttachedToClass": "Attached to class",
"Name": "Name",
"Description": "Description",
"Private": "Private",
"Archived": "Archived"
}
}

View File

@ -0,0 +1,15 @@
{
"string": {
"Id": "Id",
"Space": "Пространство",
"Modified": "Изменено",
"ModifiedBy": "Изменен",
"Class": "Класс",
"AttachedTo": "Прикреплен к",
"AttachedToClass": "Прикреплен к классу",
"Name": "Название",
"Description": "Описание",
"Private": "Личный",
"Archived": "Архивный"
}
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
import type { Plugin, StatusCode } from '@anticrm/platform'
import type { IntlString, Plugin, StatusCode } from '@anticrm/platform'
import { plugin } from '@anticrm/platform'
import { Mixin, Version } from '.'
import type { Account, ArrOf, AnyAttribute, AttachedDoc, Class, Doc, Interface, Obj, PropertyType, Ref, Space, Timestamp, Type, Collection, RefTo } from './classes'
@ -69,5 +69,14 @@ export default plugin(coreId, {
},
version: {
Model: '' as Ref<Version>
},
string: {
Id: '' as IntlString,
Space: '' as IntlString,
Modified: '' as IntlString,
ModifiedBy: '' as IntlString,
Class: '' as IntlString,
AttachedTo: '' as IntlString,
AttachedToClass: '' as IntlString
}
})

View File

@ -11,19 +11,26 @@
//
// See the License for the specific language governing permissions and
// limitations under the License.
import { addStringsLoader } from '@anticrm/platform'
import { coreId } from './component'
//
export * from './classes'
export * from './tx'
export * from './storage'
export * from './operations'
export * from './utils'
export * from './hierarchy'
export * from './memdb'
export * from './client'
export * from './operator'
export { coreId, default } from './component'
export * from './hierarchy'
export * from './measurements'
export * from './memdb'
export * from './objvalue'
export * from './operations'
export * from './operator'
export * from './query'
export * from './server'
export * from './measurements'
export * from './storage'
export * from './tx'
export * from './utils'
export { default, coreId } from './component'
addStringsLoader(coreId, async (lang: string) => {
return await import(`../lang/${lang}.json`)
})

View File

@ -21,6 +21,7 @@ import { setPlatformStatus } from './event'
import { IntlMessageFormat } from 'intl-messageformat'
import platform from './platform'
import { getMetadata } from './metadata'
/**
* @public
@ -29,8 +30,6 @@ export type Loader = (locale: string) => Promise<Record<string, string | Record<
type Messages = Record<string, IntlString | Record<string, IntlString>>
const locale = 'en'
const loaders = new Map<Plugin, Loader>()
const translations = new Map<Plugin, Messages | Status>()
const cache = new Map<IntlString, IntlMessageFormat | Status>()
@ -44,7 +43,7 @@ export function addStringsLoader (plugin: Plugin, loader: Loader): void {
loaders.set(plugin, loader)
}
async function loadTranslationsForComponent (plugin: Plugin): Promise<Messages | Status> {
async function loadTranslationsForComponent (plugin: Plugin, locale: string): Promise<Messages | Status> {
const loader = loaders.get(plugin)
if (loader === undefined) {
const status = new Status(Severity.ERROR, platform.status.NoLoaderForStrings, { plugin })
@ -60,12 +59,12 @@ async function loadTranslationsForComponent (plugin: Plugin): Promise<Messages |
}
}
async function getTranslation (message: IntlString): Promise<IntlString | Status> {
async function getTranslation (message: IntlString, locale: string): Promise<IntlString | Status> {
try {
const id = _parseId(message)
let messages = translations.get(id.component)
if (messages === undefined) {
messages = await loadTranslationsForComponent(id.component)
messages = await loadTranslationsForComponent(id.component, locale)
translations.set(id.component, messages)
}
if (messages instanceof Status) {
@ -90,6 +89,7 @@ async function getTranslation (message: IntlString): Promise<IntlString | Status
* @returns
*/
export async function translate<P extends Record<string, any>> (message: IntlString<P>, params: P): Promise<string> {
const locale = getMetadata(platform.metadata.locale) ?? 'en'
const compiled = cache.get(message)
if (compiled !== undefined) {
if (compiled instanceof Status) {
@ -97,7 +97,7 @@ export async function translate<P extends Record<string, any>> (message: IntlStr
}
return compiled.format(params)
} else {
const translation = await getTranslation(message)
const translation = await getTranslation(message, locale)
if (translation instanceof Status) {
cache.set(message, translation)
return message

View File

@ -27,11 +27,7 @@ export * from './metadata'
export * from './rpc'
addStringsLoader(platformId, async (lang: string) => {
switch (lang) {
case 'en':
return (await import('./lang/en.json'))
}
throw new Error('unsupported language')
return await import(`./lang/${lang}.json`)
})
/**

View File

@ -0,0 +1,12 @@
{
"status": {
"LoadingPlugin": "Загрузка плагина '<b>'{plugin}'</b>'...",
"UnknownError": "Неизвестная ошибка: {message}",
"InvalidId": "Некорректный Id: {id}",
"BadRequest": "Некорректный запрос",
"Forbidden": "Запрещено",
"Unauthorized": "Неавторизован",
"UnknownMethod": "Неизвестный метод: {method}",
"InternalServerError": "Внутренняя ошибка сервеа"
}
}

View File

@ -14,6 +14,8 @@
// limitations under the License.
*/
import { Metadata } from '.'
/**
* Id in format 'plugin.resource-kind.id'
*
@ -140,5 +142,8 @@ export default plugin(platformId, {
Unauthorized: '' as StatusCode,
UnknownMethod: '' as StatusCode<{ method: string }>,
InternalServerError: '' as StatusCode
},
metadata: {
locale: '' as Metadata<string>
}
})

View File

@ -0,0 +1,13 @@
{
"string": {
"Create": "Создать",
"Cancel": "Отменить",
"Ok": "Ок",
"Save": "Сохранить",
"Download": "Загрузить",
"Delete": "Удалить",
"NotSelected": "Не выделено",
"Deselect": "Снять выделение",
"AddSocialLinks": "Добавить контактную информацию"
}
}

View File

@ -3,8 +3,6 @@
"Suggested": "SUGGESTED",
"NoItems": "No items",
"EditorPlaceholder": "Start typing...",
"Edit": "Edit",
"Cancel": "Cancel",
"Save": "Save"
"Edit": "Edit"
}
}

View File

@ -0,0 +1,8 @@
{
"string": {
"Suggested": "РЕКОМЕНДУЕМЫЕ",
"NoItems": "Нет содержимого",
"EditorPlaceholder": "Начните печатать...",
"Edit": "Редактировать"
}
}

View File

@ -1,6 +1,6 @@
<script lang="ts">
import { IntlString } from '@anticrm/platform'
import { MessageViewer } from '@anticrm/presentation'
import presentation, { MessageViewer } from '@anticrm/presentation'
import { ActionIcon, IconCheck, IconClose, IconEdit } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import textEditorPlugin from '../plugin'
@ -41,7 +41,7 @@
icon={IconCheck}
size={'medium'}
direction={'bottom'}
label={textEditorPlugin.string.Save}
label={presentation.string.Save}
action={() => {
dispatch('value', rawValue)
content = rawValue
@ -53,7 +53,7 @@
size={'medium'}
icon={IconClose}
direction={'top'}
label={textEditorPlugin.string.Cancel}
label={presentation.string.Cancel}
action={() => {
mode = Mode.View
}}

View File

@ -35,8 +35,6 @@ export default plugin(textEditorId, {
Emoji: '' as IntlString,
GIF: '' as IntlString,
EditorPlaceholder: '' as IntlString,
Edit: '' as IntlString,
Cancel: '' as IntlString,
Save: '' as IntlString
Edit: '' as IntlString
}
})

View File

@ -30,6 +30,7 @@
"typescript": "^4.3.5"
},
"dependencies": {
"svelte": "^3.37.0"
"svelte": "^3.37.0",
"@anticrm/platform": "~0.6.5"
}
}

View File

@ -15,13 +15,14 @@
<script lang="ts">
import { setContext, onMount } from 'svelte'
import platform, { setMetadata } from '@anticrm/platform'
const getCurrentTheme = (): string => localStorage.getItem('theme') ?? 'theme-dark'
const getCurrnetFontSize = (): string => localStorage.getItem('fontsize') ?? 'normal-font'
const getCurrnetLanguage = (): string => localStorage.getItem('lang') ?? 'en'
const currentTheme = getCurrentTheme()
const currentFontSize = getCurrnetFontSize()
const currentLanguage = getCurrnetLanguage()
let currentLanguage = getCurrnetLanguage()
const setRootColors = (theme: string) => {
document.documentElement.setAttribute('class', `${theme} ${getCurrnetFontSize()}`)
@ -47,13 +48,16 @@
setContext('lang', {
currentLanguage: currentLanguage,
setLanguage: (lang: string) => {
currentLanguage = lang
localStorage.setItem('lang', lang)
location.reload()
}
})
onMount(() => {
setRootColors(currentTheme)
setRootFontSize(currentFontSize)
setMetadata(platform.metadata.locale, currentLanguage)
})
</script>

View File

@ -10,6 +10,9 @@
"Search": "Search",
"SearchDots": "Search...",
"Suggested": "Suggested",
"TimeTooltip": "{value}"
"TimeTooltip": "{value}",
"None": "None",
"English": "English",
"Russian": "Russian"
}
}

18
packages/ui/lang/ru.json Normal file
View File

@ -0,0 +1,18 @@
{
"string": {
"EditBoxPlaceholder": "Введите текст здесь",
"Cancel": "Отменить",
"Minutes": "{minutes, plural, =0 {меньше минуты назад} =1 {минуту назад} other {# минут назад}}",
"Hours": "{hours, plural, =0 {меньше часа назад} =1 {час назад} other {# часов назад}}",
"Days": "{days, plural, =0 {сегода} =1 {вчера} other {# дней назад}}",
"ShowMore": "Показать больше",
"ShowLess": "Показать меньше",
"Search": "Поиск",
"SearchDots": "Поиск...",
"Suggested": "Предложено",
"TimeTooltip": "{value}",
"None": "Нет",
"English": "Английский",
"Russian": "Русский"
}
}

View File

@ -23,7 +23,8 @@
import type { DropdownTextItem } from '../types'
import { showPopup } from '..'
import { createEventDispatcher } from 'svelte'
import { createEventDispatcher } from 'svelte'
import ui from '../plugin'
export let title: IntlString
export let caption: IntlString | undefined = undefined
@ -41,10 +42,9 @@ import { createEventDispatcher } from 'svelte'
$: if (selected === undefined && items[0] !== undefined) {
selected = items[0].id
}
const none = 'None' as IntlString
const dispatch = createEventDispatcher()
const none = ui.string.None
</script>
<div class="flex-col cursor-pointer"

View File

@ -15,16 +15,16 @@
<script lang="ts">
import { getContext } from 'svelte'
import type { IntlString } from '@anticrm/platform'
import { showPopup } from '../..'
import LangPopup from './LangPopup.svelte'
import ui from '../../plugin'
import Flags from './icons/Flags.svelte'
const { currentLanguage, setLanguage } = getContext('lang')
const langs
= [{ id: 'en', label: 'English' as IntlString },
{ id: 'ru', label: 'Russian' as IntlString }]
= [{ id: 'en', label: ui.string.English },
{ id: 'ru', label: ui.string.Russian }]
$: selected = langs.find(item => item.id === currentLanguage)
let trigger: HTMLElement

View File

@ -34,6 +34,9 @@ export default plugin(uiId, {
Search: '' as IntlString,
SearchDots: '' as IntlString,
Suggested: '' as IntlString,
TimeTooltip: '' as IntlString
TimeTooltip: '' as IntlString,
None: '' as IntlString,
English: '' as IntlString,
Russian: '' as IntlString
}
})

View File

@ -2,9 +2,13 @@
"string": {
"Delete": "Delete",
"Edit": "Edit",
"Options": "Options",
"Edited": "edited",
"DocCreated": "created {_class}",
"DocDeleted": "deleted {_class}"
"DocDeleted": "deleted {_class}",
"Activity": "Activity",
"Changed": "changed",
"To": "to",
"Unset": "unset",
"NoEmployee": "No employee"
}
}

View File

@ -0,0 +1,14 @@
{
"string": {
"Delete": "Удалить",
"Edit": "Редактировать",
"Edited": "отредактировал(а)",
"DocCreated": "создал(а) {_class}",
"DocDeleted": "удалил(а) {_class}",
"Activity": "Активность",
"Changed": "изменил(а)",
"To": "на",
"Unset": "сбросил",
"NoEmployee": "Не сотрудник"
}
}

View File

@ -18,7 +18,7 @@
import chunter from '@anticrm/chunter'
import { Doc, SortingOrder } from '@anticrm/core'
import { createQuery, getClient } from '@anticrm/presentation'
import { Component, Grid, IconActivity, Scroller } from '@anticrm/ui'
import { Component, Grid, IconActivity, Label, Scroller } from '@anticrm/ui'
import { ActivityKey, activityKey, DisplayTx, newActivity } from '../activity'
import TxView from './TxView.svelte'
@ -54,7 +54,7 @@
<div class="ac-header short mirror-tool divide">
<div class="ac-header__wrap-title">
<div class="ac-header__icon flex-center icon"><IconActivity size={'small'} /></div>
<span class="ac-header__title">Activity</span>
<span class="ac-header__title"><Label label={activity.string.Activity} /></span>
</div>
</div>
{/if}
@ -86,7 +86,7 @@
<div class="ac-header short mirror-tool">
<div class="ac-header__wrap-title">
<div class="ac-header__icon flex-center icon"><IconActivity size={'small'} /></div>
<span class="ac-header__title">Activity</span>
<span class="ac-header__title"><Label label={activity.string.Activity} /></span>
</div>
</div>
<div class="p-activity">

View File

@ -15,7 +15,7 @@
-->
<script lang="ts">
import type { TxViewlet } from '@anticrm/activity'
import activity from '@anticrm/activity'
import activity from '../plugin'
import contact, { EmployeeAccount, formatName } from '@anticrm/contact'
import core, { AnyAttribute, Doc, Ref } from '@anticrm/core'
import { Asset, getResource } from '@anticrm/platform'
@ -124,7 +124,7 @@
{#if employee}
{formatName(employee.name)}
{:else}
No employee
<Label label={activity.string.NoEmployee} />
{/if}
</div>
{#if viewlet && viewlet?.editable}
@ -141,7 +141,9 @@
</div>
{:else if viewlet && viewlet.label}
<div class="flex-center">
<Label label={viewlet.label} params={viewlet.labelParams ?? {}} />
<span class="lower">
<Label label={viewlet.label} params={viewlet.labelParams ?? {}} />
</span>
{#if viewlet.labelComponent}
<Component
is={viewlet.labelComponent}
@ -154,9 +156,9 @@
{#each model as m, i}
{#await getValue(client, m, tx.updateTx.operations) then value}
{#if value === null}
<span>unset <Label label={m.label} /></span>
<span class="lower"><Label label={activity.string.Unset} /> <Label label={m.label} /></span>
{:else}
<span class:flex-grow={hasMessageType}>changed <Label label={m.label} /> to</span>
<span class="lower" class:flex-grow={hasMessageType}><Label label={activity.string.Changed} /> <Label label={m.label} /> <Label label={activity.string.To} /></span>
{#if hasMessageType}
<div class="time"><TimeSince value={tx.tx.modifiedOn} /></div>
{/if}
@ -176,9 +178,9 @@
{#each model as m}
{#await getValue(client, m, tx.mixinTx.attributes) then value}
{#if value === null}
<span>unset <Label label={m.label} /></span>
<span><Label label={activity.string.Unset} /> <span class="lower"><Label label={m.label} /></span></span>
{:else}
<span>changed <Label label={m.label} /> to</span>
<span><Label label={activity.string.Changed} /> <span class="lower"><Label label={m.label} /></span> <Label label={activity.string.To} /></span>
{#if isMessageType(m.attribute)}
<div class="strong message emphasized">
<svelte:component this={m.presenter} {value} />

View File

@ -19,8 +19,11 @@ import { mergeIds } from '@anticrm/platform'
export default mergeIds(activityId, activity, {
string: {
Activity: '' as IntlString,
DocCreated: '' as IntlString,
DocDeleted: '' as IntlString
DocDeleted: '' as IntlString,
Changed: '' as IntlString,
To: '' as IntlString,
Unset: '' as IntlString,
NoEmployee: '' as IntlString
}
})

View File

@ -56,8 +56,8 @@ export default plugin(activityId, {
string: {
Delete: '' as IntlString,
Edit: '' as IntlString,
Options: '' as IntlString,
Edited: '' as IntlString
Edited: '' as IntlString,
Activity: '' as IntlString
},
icon: {
Activity: '' as Asset

View File

@ -4,6 +4,13 @@
"NoAttachments": "There are no attachments for this",
"AddAttachment": "uploaded an attachment",
"Attachments": "Attachments",
"Photos": "Photos"
"Photos": "Photos",
"File": "File",
"Files": "Files",
"Type": "Type",
"Size": "Size",
"Photo": "Photo",
"Date": "Date",
"Name": "Name"
}
}

View File

@ -0,0 +1,16 @@
{
"string": {
"UploadDropFilesHere": "Загрузите или перетащите файлы сюда",
"NoAttachments": "Нет вложений",
"AddAttachment": "загрузил вложение",
"Attachments": "Вложения",
"Photos": "Фотографии",
"File": "Файл",
"Files": "Файлы",
"Type": "Тип",
"Size": "Размер",
"Photo": "Фотография",
"Date": "Дата",
"Name": "Название"
}
}

View File

@ -33,7 +33,6 @@
let loading = 0
const client = getClient()
const hierarchy = client.getHierarchy()
async function createAttachment (file: File) {
loading++
@ -73,12 +72,11 @@
}
let dragover = false
$: classLabel = hierarchy.getClass(_class).label
</script>
<div class="attachments-container">
<div class="flex-row-center">
<span class="title">Attachments</span>
<span class="title"><Label label={attachment.string.Attachments} /></span>
{#if loading}
<Spinner />
{:else}
@ -117,9 +115,6 @@
<UploadDuo size={'large'} />
<div class="text-sm content-dark-color mt-2">
<Label label={attachment.string.NoAttachments} />
<span class="lower">
<Label label={classLabel} />
</span>
</div>
<div class="text-sm">
<div class='over-underline' on:click={() => inputFile.click()}><Label label={attachment.string.UploadDropFilesHere} /></div>

View File

@ -2,7 +2,6 @@
"string": {
"ApplicationLabelChunter": "Chat",
"LeftComment": "left a comment",
"AddAttachment": "uploaded an attachment",
"Channels": "Channels",
"CreateChannel": "New Channel",
"ChannelName": "Name",
@ -15,6 +14,12 @@
"EditCancel": "Cancel",
"Comments" : "Comments",
"MentionedIn": "mentioned this ",
"ContactInfo": "Contact Info"
"ContactInfo": "Contact Info",
"Content": "Content",
"Comment": "Comment",
"Message": "Message",
"Reference": "Reference",
"Chat": "Chat",
"In": "In"
}
}

View File

@ -0,0 +1,25 @@
{
"string": {
"ApplicationLabelChunter": "Чат",
"LeftComment": "оставил(а) комментарий",
"Channels": "Каналы",
"CreateChannel": "Создать канал",
"ChannelName": "Название",
"ChannelNamePlaceholder": "Канал",
"ChannelDescription": "Описание",
"MakePrivate": "Сделать личным",
"MakePrivateDescription": "Только пользователи могут видеть это",
"Channel": "Канал ",
"EditUpdate": "Сохранить...",
"EditCancel": "Отменить",
"Comments" : "Комментарии",
"MentionedIn": "упомянул(а) ",
"ContactInfo": "Контактная информация",
"Content": "Содержимое",
"Comment": "Комментарий",
"Message": "Сообщение",
"Reference": "Ссылка",
"Chat": "Чат",
"In": "в"
}
}

View File

@ -16,8 +16,10 @@
import type { Backlink } from '@anticrm/chunter'
import type { Doc } from '@anticrm/core'
import { createQuery, getClient } from '@anticrm/presentation'
import { Label } from '@anticrm/ui'
import { AttributeModel } from '@anticrm/view'
import { getObjectPresenter } from '@anticrm/view-resources'
import chunter from '../../plugin'
// export let tx: TxCreateDoc<Backlink>
export let value: Backlink
@ -25,15 +27,26 @@
const client = getClient()
let presenter: AttributeModel | undefined
let targetPresenter: AttributeModel | undefined
const docQuery = createQuery()
const targetQuery = createQuery()
let doc: Doc | undefined
let target: Doc | undefined
$: docQuery.query(value.backlinkClass, { _id: value.backlinkId }, (r) => {
doc = r.shift()
})
$: className = client.getHierarchy().getClass(value.attachedToClass).label.toLocaleLowerCase()
$: targetQuery.query(value.attachedToClass, { _id: value.attachedTo }, (r) => {
target = r.shift()
})
$: if (target !== undefined) {
getObjectPresenter(client, target._class, { key: '' }).then((p) => {
targetPresenter = p
})
}
$: if (doc !== undefined) {
getObjectPresenter(client, doc._class, { key: '' }).then((p) => {
@ -43,7 +56,12 @@
</script>
{#if presenter}
{className} in
{#if targetPresenter}
<div class="ml-2">
<svelte:component this={targetPresenter.presenter} value={target} />
</div>
{/if}
<span class="lower">&nbsp; <Label label={chunter.string.In} /></span>
<div class="ml-2">
<svelte:component this={presenter.presenter} value={doc} />
</div>

View File

@ -31,6 +31,7 @@ export default mergeIds(chunterId, chunter, {
ChannelNamePlaceholder: '' as IntlString,
ChannelDescription: '' as IntlString,
MakePrivate: '' as IntlString,
MakePrivateDescription: '' as IntlString
MakePrivateDescription: '' as IntlString,
In: '' as IntlString
}
})

View File

@ -32,6 +32,18 @@
"Person": "Person",
"Organization": "Organization",
"Employee": "Employee",
"Value": "Value"
"Value": "Value",
"FullDescription": "Full description",
"Phone": "Phone",
"LinkedIn": "LinkedIn",
"GitHub": "GitHub",
"Twitter": "Twitter",
"PhonePlaceholder": "+1 555 333 7777",
"LinkedInPlaceholder": "https://linkedin.com/in/jappleseed",
"AtPlaceHolder": "@appleseed",
"FacebookPlaceholder": "https://fb.com/jappleseed",
"Facebook": "Facebook",
"SocialLinks": "Socail links",
"ViewActivity": "View activity"
}
}

View File

@ -0,0 +1,49 @@
{
"string": {
"Apply": "Применить",
"Contacts": "Контакты",
"Persons": "Люди",
"Organizations": "Организации",
"CreatePerson": "Создать персону",
"CreatePersons": "Создать папку для людей",
"CreateOrganization": "Создать организацию",
"OrganizationNamePlaceholder": "Apple",
"OrganizationsNamePlaceholder": "Организации",
"PersonFirstNamePlaceholder": "John",
"PersonLastNamePlaceholder": "Appleseed",
"PersonLocationPlaceholder": "Местоположение",
"PersonsNamePlaceholder": "Папка",
"CreateOrganizations": "Создать папку для организаций",
"Name": "Имя",
"SelectFolder": "Выбрать папку",
"OrganizationsFolder": "Папка с организациями",
"PersonsFolder": "Папка с людьми",
"MakePrivate": "Сделать личным",
"MakePrivateDescription": "Только пользователи могут видеть это",
"Create": "Контакт",
"SearchEmployee": "Поиск сотрудника...",
"SearchPerson": "Поиск персоны...",
"SearchOrganization": "Поиск организации...",
"ContactInfo": "Контактная информация",
"Contact": "Контакт",
"Location": "Местоположение",
"Channel": "Канал",
"ChannelProvider": "Провайдер канала",
"Person": "Персона",
"Organization": "Организация",
"Employee": "Сотрудник",
"Value": "Значение",
"FullDescription": "Полное описание",
"Phone": "Телефон",
"LinkedIn": "LinkedIn",
"GitHub": "GitHub",
"Twitter": "Twitter",
"PhonePlaceholder": "+1 555 333 7777",
"LinkedInPlaceholder": "https://linkedin.com/in/jappleseed",
"AtPlaceHolder": "@appleseed",
"FacebookPlaceholder": "https://fb.com/jappleseed",
"Facebook": "Facebook",
"SocialLinks": "Контактная информация",
"ViewActivity": "Посмотреть активность"
}
}

View File

@ -16,7 +16,7 @@
<script lang="ts">
import type { IntlString, Asset } from '@anticrm/platform'
import { CircleButton, closeTooltip } from '@anticrm/ui'
import { CircleButton, closeTooltip, Label } from '@anticrm/ui'
import IconCopy from './icons/Copy.svelte'
interface Item {
@ -43,7 +43,7 @@
<div class="flex-row-center">
<CircleButton icon={value.icon} size={'x-large'} />
<div class="flex-col caption-color clear-mins ml-3">
<div class="text-sm font-medium">{value.label}</div>
<div class="text-sm font-medium"><Label label={value.label} /></div>
<div class="overflow-label">{value.value}</div>
</div>
<div class="button" on:click|preventDefault={copyLink}>

View File

@ -51,7 +51,7 @@
if (provider) {
const notification = (item as Channel)._id !== undefined ? isNew((item as Channel), lastViews) : false
return {
label: provider.label as IntlString,
label: provider.label,
icon: provider.icon as Asset,
value: item.value,
presenter: provider.presenter,

View File

@ -1,3 +1,4 @@
<!--
// Copyright © 2020, 2021 Anticrm Platform Contributors.
// Copyright © 2021 Hardcore Engineering Inc.

View File

@ -16,7 +16,7 @@
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte'
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
import { CircleButton, EditBox, IconActivity } from '@anticrm/ui'
import { CircleButton, EditBox, IconActivity, Label } from '@anticrm/ui'
import { getClient, createQuery } from '@anticrm/presentation'
import setting from '@anticrm/setting'
import { IntegrationType } from '@anticrm/setting'
@ -64,7 +64,7 @@
<div class="flex-row-center">
<div class='over-underline flex-row-center' on:click>
<CircleButton icon={IconActivity} size={'small'} primary on:click />
<span class="ml-2 text-sm">View activity</span>
<span class="ml-2 text-sm"><Label label={contact.string.ViewActivity} /></span>
</div>
</div>
</div>

View File

@ -16,7 +16,7 @@
<script lang="ts">
import { createEventDispatcher, onMount, afterUpdate } from 'svelte'
import { getCurrentAccount, Ref, Space } from '@anticrm/core'
import { CircleButton, EditBox, IconActivity } from '@anticrm/ui'
import { CircleButton, EditBox, IconActivity, Label } from '@anticrm/ui'
import { getClient, createQuery, EditableAvatar, AttributeEditor } from '@anticrm/presentation'
import { getResource } from '@anticrm/platform'
import attachment from '@anticrm/attachment'
@ -101,7 +101,7 @@
<div class="flex-row-center">
<div class="over-underline flex-row-center" on:click>
<CircleButton icon={IconActivity} size={'small'} primary on:click />
<span class="ml-2 text-sm">View activity</span>
<span class="ml-2 text-sm"><Label label={contact.string.ViewActivity} /></span>
</div>
</div>
</div>

View File

@ -16,7 +16,7 @@
<script lang="ts">
import { AttachedData, Ref } from '@anticrm/core'
import { createEventDispatcher } from 'svelte'
import { EditBox, Button, ScrollBox } from '@anticrm/ui'
import { EditBox, Button, ScrollBox, Label } from '@anticrm/ui'
import { getClient } from '@anticrm/presentation'
import { ChannelProvider, Channel } from '@anticrm/contact'
@ -57,7 +57,7 @@
<div class="popup">
<ScrollBox vertical stretch>
<div class="popup-block">
<span>Contact Links</span>
<span><Label label={contact.string.SocialLinks} /></span>
{#each providers as provider, i}
<EditBox
label={provider.label}

View File

@ -38,6 +38,8 @@ export default mergeIds(contactId, contact, {
Name: '' as IntlString,
MakePrivate: '' as IntlString,
MakePrivateDescription: '' as IntlString,
Create: '' as IntlString
Create: '' as IntlString,
SocialLinks: '' as IntlString,
ViewActivity: '' as IntlString
}
})

View File

@ -21,6 +21,12 @@
"NewMessageTo": "New message to",
"Cancel": "Cancel",
"SubjectPlaceholder": "Message subject",
"CopyPlaceholder": "Copy to"
"CopyPlaceholder": "Copy to",
"ReplyTo": "Reply to",
"Message": "Message",
"Messages": "Messages",
"Incoming": "Incoming",
"Email": "Email",
"EmailPlaceholder": "john.appleseed@apple.com"
}
}

View File

@ -0,0 +1,32 @@
{
"string": {
"MessageID": "MessageID",
"IntegrationLabel": "Gmail",
"IntegrationDescription": "Используйте интеграцию с Gmail",
"SharedMessages": "общие письма",
"To": "Кому:",
"From": "От:",
"Copy": "Копия",
"MessagesSelected": "сообщений выбрано",
"PublishSelected": "Опубликовать выбранное",
"YouAnd": "Вы и",
"CreateMessage": "Создать сообщение",
"ShareMessages": "Поделиться сообщениями",
"Connect": "Подключить",
"RedirectGoogle": "Вы будете перенаправлены на страницу авторизации Google",
"ConnectGmai": "Подключить Gmail",
"Reply": "Ответить",
"Subject": "Тема",
"Send": "Отправить",
"NewMessageTo": "Новое сообщение to",
"Cancel": "Отменить",
"SubjectPlaceholder": "Тема сообщения",
"CopyPlaceholder": "Копия",
"ReplyTo": "Ответить на",
"Message": "Сообщение",
"Messages": "Сообщения",
"Incoming": "Входящие",
"Email": "Email",
"EmailPlaceholder": "john.appleseed@apple.com"
}
}

View File

@ -0,0 +1,23 @@
{
"status": {
"CategoryRequired": "Требуется категория",
"NameRequired": "Требуется название"
},
"string": {
"Categories": "Категории",
"Category": "Категория",
"CreateCategoryShort": "Категория",
"CreateCategory": "Создать категорию",
"CreateSubcategory": "Создать подкатегорию",
"Inventory": "Инвентарь",
"CreateProductShort": "Продукт",
"CreateProduct": "Создать продукт",
"Products": "Продукты",
"Product": "Продукт",
"Variant": "Вариант",
"SKU": "Артикул",
"Variants": "Варианты",
"NoVariantsForProduct": "Нет вариантов для этого продукта.",
"CreateVariant": "Создать вариант"
}
}

View File

@ -14,6 +14,11 @@
"Customer": "Customer",
"Customers": "Customers",
"Leads": "Leads",
"SelectCustomer": "Select customer"
"SelectCustomer": "Select customer",
"Lead": "Lead",
"Assignee": "Assignee",
"Title": "Title",
"LeadPlaceholder": "The simple lead",
"ManageFunnelStatuses": "Manage funnel statuses"
}
}

View File

@ -0,0 +1,24 @@
{
"string": {
"CreateFunnel": "Создать воронку",
"CreateLead": "Создать сделку",
"Funnel": "Воронка",
"FunnelName": "Название воронки",
"Funnels": "Воронки",
"MakePrivate": "Сделать личным",
"MakePrivateDescription": "Только пользователи могут видеть это",
"LeadApplication": "Сделки",
"SelectFunnel": "Выбрать воронку",
"LeadName": "Название сделки",
"More": "Еще...",
"Customer": "Клиент",
"Customers": "Клиенты",
"Leads": "Сделки",
"SelectCustomer": "Выбрать клиента",
"Lead": "Сделка",
"Assignee": "Назначена",
"Title": "Загаловок",
"LeadPlaceholder": "Простая сделка",
"ManageFunnelStatuses": "Управление статусами воронки"
}
}

View File

@ -98,7 +98,7 @@
label={lead.string.LeadName}
bind:value={title}
icon={lead.icon.Lead}
placeholder="The simple lead"
placeholder={lead.string.LeadPlaceholder}
maxWidth={'16rem'}
focus
/>

View File

@ -41,7 +41,7 @@
label={lead.string.LeadName}
bind:value={object.title}
icon={lead.icon.Lead}
placeholder="The simple lead"
placeholder={lead.string.LeadPlaceholder}
maxWidth="39rem"
focus
on:change={(evt) => change('title', object.title)}

View File

@ -31,7 +31,8 @@ export default mergeIds(leadId, lead, {
SelectCustomer: '' as IntlString,
Customers: '' as IntlString,
Leads: '' as IntlString,
NoLeadsForDocument: '' as IntlString
NoLeadsForDocument: '' as IntlString,
LeadPlaceholder: '' as IntlString
},
component: {
CreateCustomer: '' as AnyComponent,

View File

@ -0,0 +1,30 @@
{
"status": {
"RequiredField": "Требуется заполнить {field}",
"FieldsDoNotMatch": "{field} не совпадает {field2}",
"ConnectingToServer": "Подключение к серверуConnecting to server....",
"IncorrectValue": "Неправильное значение {field}"
},
"string": {
"LogIn": "Вход",
"SignUp": "Регистрация",
"CreateWorkspace": "Создать рабочее пространство",
"HaveWorkspace": "Уже есть рабочее пространство?",
"LastName": "Фамилия",
"FirstName": "Имя",
"Join": "Присоедениться",
"Email": "Email",
"Password": "Пароль",
"Workspace": "Рабочее пространство",
"DoNotHaveAnAccount": "Нет учетной записи?",
"PasswordRepeat": "Повторите пароль",
"HaveAccount": "Уже есть учетная запись?",
"SelectWorkspace": "Выбрать рабочее пространство",
"Copy": "Копировать",
"Close": "Закрыть",
"InviteDescription": "Поделитесь ссылкой чтобы пригласить других участников",
"WantAnotherWorkspace": "Хотите создать другое рабочее пространство?",
"ChangeAccount": "Сменить пользователя",
"NotSeeingWorkspace": "Не видите ваше рабочее пространство?"
}
}

View File

@ -0,0 +1,11 @@
{
"string": {
"LastView": "Последний просмотр",
"Notification": "Увдомление",
"Notifications": "Уведомления",
"NoNotifications": "Нет уведомлений",
"MentionNotification": "Упомянул",
"EmailNotification": "по email",
"PlatformNotification": "в системе"
}
}

View File

@ -9,8 +9,7 @@
"CreateVacancy": "Create Vacancy",
"MakePrivate": "Make Private",
"Vacancy": "Vacancy",
"VacancyPlaceholder": "Please type vacancy name",
"CandidatesName": "Pool name *",
"VacancyPlaceholder": "Software Engineer",
"MakePrivateDescription": "Only members can see it",
"CreateAnApplication": "Create an application",
"NoApplicationsForCandidate": "There are no applications for this candidate.",
@ -18,15 +17,14 @@
"SelectVacancy": "Select vacancy",
"Candidate": "Candidate",
"CreateCandidate": "Create Candidate",
"AssignRecruiter": "Assigned recruiter",
"UnAssignRecruiter": "Unassigned recruiter",
"AssignRecruiter": "Assign recruiter",
"UnAssignRecruiter": "Unassign recruiter",
"Recruiters": "Recruiters",
"Create": "Create",
"Applications": "Applications",
"ThisVacancyIsPrivate": "This vacancy is private",
"Description": "Description",
"Company": "Company",
"Save": "Save",
"Edit": "Edit",
"Delete": "Delete",
"WorkLocationPreferences": "Work location preferences",
@ -36,7 +34,22 @@
"Application": "Application",
"AssignedRecruiter": "Assigned recruiter",
"SkillLabel": "Skill",
"SkillsLabel": "Skills"
"SkillsLabel": "Skills",
"General": "General",
"Members": "Members",
"Yes": "Yes",
"No": "No",
"NA": "N/A",
"ApplicationShort": "APP",
"ApplicationsShort": "Apps",
"Due": "Due date",
"Location": "Location",
"Title": "Title",
"Source": "Source",
"PersonFirstNamePlaceholder": "John",
"PersonLastNamePlaceholder": "Appleseed",
"PersonLocationPlaceholder": "Location",
"ManageVacancyStatuses": "Manage vacancy statuses"
},
"status": {
"CandidateRequired": "Please select candidate",

View File

@ -0,0 +1,58 @@
{
"string": {
"RecruitApplication": "Рекрутинг",
"Vacancies": "Вакансии",
"CandidatePools": "Пул кандидатов",
"Candidates": "Кандидаты",
"VacancyName": "Название вакансии *",
"VacancyDescription": "Описание вакансии",
"CreateVacancy": "Создать вакансию",
"Vacancy": "Вакансия",
"VacancyPlaceholder": "Разработчик",
"MakePrivate": "Сделать личным",
"MakePrivateDescription": "Только пользователи могут видеть это",
"CreateAnApplication": "Создать претендента",
"NoApplicationsForCandidate": "Нет претендентов для данного кандидата.",
"CreateApplication": "Создать претендента",
"SelectVacancy": "Выбрать вакансию",
"Candidate": "Кандидат",
"CreateCandidate": "Создать кандидата",
"AssignRecruiter": "Назначить рекрутера",
"UnAssignRecruiter": "Отменить назначение рекрутера",
"Recruiters": "Рекрутеры",
"Create": "Создать",
"Applications": "Претенденты",
"ThisVacancyIsPrivate": "Эта вакансия личная",
"Description": "Описание",
"Company": "Компания",
"Edit": "Редактировать",
"Delete": "Удалить",
"WorkLocationPreferences": "Предпочтения по местоположению работы",
"Onsite": "Onsite",
"Remote": "Удаленно",
"SearchApplication": "Поиск претендента...",
"Application": "Претендент",
"AssignedRecruiter": "Назначенные рекрутер",
"SkillLabel": "Навык",
"SkillsLabel": "Навыки",
"General": "Основное",
"Members": "Пользователи",
"Yes": "Да",
"No": "Нет",
"NA": "Н/Д",
"ApplicationShort": "APP",
"ApplicationsShort": "Apps",
"Due": "Срок",
"Location": "Местоположение",
"Title": "Заголовок",
"Source": "Источник",
"PersonFirstNamePlaceholder": "John",
"PersonLastNamePlaceholder": "Appleseed",
"PersonLocationPlaceholder": "Местоположение",
"ManageVacancyStatuses": "Управление статусами вакансии"
},
"status": {
"CandidateRequired": "Пожалуйста выберите кандидата",
"VacancyRequired": "Пожалуйста выберите вакансию"
}
}

View File

@ -18,13 +18,13 @@
import { Ref } from '@anticrm/core'
import { getClient } from '@anticrm/presentation'
import type { Applicant } from '@anticrm/recruit'
import { Icon } from '@anticrm/ui'
import { Icon, Label } from '@anticrm/ui'
import recruit from '../plugin'
export let value: Applicant
const client = getClient()
const shortLabel = client.getHierarchy().getClass(value._class).shortLabel?.toUpperCase()
const shortLabel = client.getHierarchy().getClass(value._class).shortLabel
let person: Person| undefined
@ -36,7 +36,7 @@
<div class='flex item'>
<Icon icon={recruit.icon.Application} size={'large'} />
<div class='ml-2'>
{shortLabel}-{value.number}
{#if shortLabel}<Label label={shortLabel} />-{/if}{value.number}
</div>
{#if person}
<div class='ml-1'>{formatName(person.name)}</div>

View File

@ -17,7 +17,7 @@
import { getClient } from '@anticrm/presentation'
import type { Applicant } from '@anticrm/recruit'
import recruit from '@anticrm/recruit'
import { Icon } from '@anticrm/ui'
import { Icon, Label } from '@anticrm/ui'
import { showPanel } from '@anticrm/ui/src/panelup'
import view from '@anticrm/view'
@ -33,6 +33,6 @@
{#if value && shortLabel}
<div class="sm-tool-icon" on:click={show}>
<span class="icon"><Icon icon={recruit.icon.Application} size={'small'} /></span>&nbsp;{shortLabel}-{value.number}
<span class="icon"><Icon icon={recruit.icon.Application} size={'small'} /></span>&nbsp{#if shortLabel}<Label label={shortLabel} />-{/if}{value.number}
</div>
{/if}

View File

@ -36,7 +36,7 @@
<div class="applications-container">
<div class="flex-row-center">
<div class="title">Applications</div>
<div class="title"><Label label={recruit.string.Applications} /></div>
<CircleButton icon={IconAdd} size={'small'} selected on:click={createApp} />
</div>
{#if applications > 0}

View File

@ -16,12 +16,11 @@
<script lang="ts">
import type { IntlString } from '@anticrm/platform'
import presentation from '@anticrm/presentation'
import { Button,Grid,IconClose,Label } from '@anticrm/ui'
import { createEventDispatcher } from 'svelte'
import { Label, Button, Grid, IconClose } from '@anticrm/ui'
import recruit from '../plugin'
import Avatar from '../../img/avatar.png'
import recruit from '../plugin'
export let label: IntlString
const dispatch = createEventDispatcher()
@ -46,7 +45,7 @@
</Grid>
</div>
<div class="abs-rb-content">
<Button label={recruit.string.Save} />
<Button label={presentation.string.Save} />
</div>
</div>

View File

@ -156,7 +156,7 @@
const categories = await client.findAll(tags.class.TagCategory, {})
// Tag elements
const skillTagElements = new Map(Array.from((await client.findAll(tags.class.TagElement, { _id: { $in: skills.map(it => it.tag) } })).map(it => ([it._id, it]))))
const skillTagElements = new Map((await client.findAll(tags.class.TagElement, { _id: { $in: skills.map(it => it.tag) } })).map(it => ([it._id, it])))
for (const skill of skills) {
// Create update tag if missing
if (!skillTagElements.has(skill.tag)) {
@ -375,10 +375,10 @@
<EditableAvatar bind:direct={avatar} avatar={object.avatar} size={'large'} on:done={onAvatarDone} />
</div>
<div class="flex-col">
<div class="fs-title"><EditBox placeholder="John" maxWidth="10rem" bind:value={firstName} /></div>
<div class="fs-title mb-1"><EditBox placeholder="Appleseed" maxWidth="10rem" bind:value={lastName} /></div>
<div class="text-sm"><EditBox placeholder="Title" maxWidth="10rem" bind:value={object.title} /></div>
<div class="text-sm"><EditBox placeholder="Location" maxWidth="10rem" bind:value={object.city} /></div>
<div class="fs-title"><EditBox placeholder={recruit.string.PersonFirstNamePlaceholder} maxWidth="10rem" bind:value={firstName} /></div>
<div class="fs-title mb-1"><EditBox placeholder={recruit.string.PersonLastNamePlaceholder} maxWidth="10rem" bind:value={lastName} /></div>
<div class="text-sm"><EditBox placeholder={recruit.string.Title} maxWidth="10rem" bind:value={object.title} /></div>
<div class="text-sm"><EditBox placeholder={recruit.string.Location} maxWidth="10rem" bind:value={object.city} /></div>
</div>
</div>

View File

@ -59,7 +59,7 @@
on:close={() => { dispatch('close') }}
>
<Grid column={1} rowGap={1.5}>
<EditBox label={recruit.string.VacancyName} bind:value={name} icon={Vacancy} placeholder="Software Engineer" maxWidth={'16rem'} focus/>
<EditBox label={recruit.string.VacancyName} bind:value={name} icon={Vacancy} placeholder={recruit.string.VacancyPlaceholder} maxWidth={'16rem'} focus/>
<Dropdown icon={Company} label={recruit.string.Company} placeholder={'Company'} />
<Component is={task.component.KanbanTemplateSelector} props={{

View File

@ -45,7 +45,7 @@
$: updateObject(_id)
const tabs: IntlString[] = ['General' as IntlString, 'Members' as IntlString, 'Activity' as IntlString]
const tabs: IntlString[] = [recruit.string.General, recruit.string.Members, activity.string.Activity]
let selected = 0
function onChange (key:string, value: any): void {

View File

@ -16,13 +16,14 @@
<script lang="ts">
import type { IntlString } from '@anticrm/platform'
import { Label } from '@anticrm/ui'
import recruit from '../plugin'
export let value: boolean | undefined
function getLabel(value: boolean | undefined): IntlString {
if (value === true) return 'Yes' as IntlString
if (value === false) return 'No' as IntlString
return 'N/A' as IntlString
if (value === true) return recruit.string.Yes
if (value === false) return recruit.string.No
return recruit.string.NA
}
</script>

View File

@ -31,7 +31,6 @@ export default mergeIds(recruitId, recruit, {
VacancyDescription: '' as IntlString,
MakePrivate: '' as IntlString,
MakePrivateDescription: '' as IntlString,
CandidatesName: '' as IntlString,
CandidatesDescription: '' as IntlString,
CreateAnApplication: '' as IntlString,
NoApplicationsForCandidate: '' as IntlString,
@ -51,14 +50,22 @@ export default mergeIds(recruitId, recruit, {
ThisVacancyIsPrivate: '' as IntlString,
Description: '' as IntlString,
Company: '' as IntlString,
Save: '' as IntlString,
Edit: '' as IntlString,
Delete: '' as IntlString,
WorkLocationPreferences: '' as IntlString,
Onsite: '' as IntlString,
Remote: '' as IntlString,
SkillLabel: '' as IntlString,
SkillsLabel: '' as IntlString
SkillsLabel: '' as IntlString,
General: '' as IntlString,
Members: '' as IntlString,
Yes: '' as IntlString,
No: '' as IntlString,
NA: '' as IntlString,
PersonFirstNamePlaceholder: '' as IntlString,
PersonLastNamePlaceholder: '' as IntlString,
Location: '' as IntlString,
Title: '' as IntlString
},
space: {
CandidatesPublic: '' as Ref<Space>

View File

@ -14,7 +14,6 @@
"CurrentPassword": "Current password",
"NewPassword": "New password",
"Disconnect": "Disconnect",
"Save": "Save",
"Saving": "Saving...",
"Saved": "Saved",
"Add": "Add",

View File

@ -0,0 +1,27 @@
{
"string": {
"Setting": "Настройки",
"ManageStatuses": "Управление статусами",
"Integrations": "Интеграции",
"Support": "Поддержка",
"Privacy": "Конфиденциальность",
"Terms": "Условия",
"EditProfile": "Редактировать профиль",
"Folders": "Папки",
"Templates": "Шаблоны",
"Delete": "Удалить",
"ChangePassword": "Изменить пароль",
"CurrentPassword": "Текущий пароль",
"NewPassword": "Новый пароль",
"Disconnect": "Отключить",
"Saving": "Сохранение...",
"Saved": "Сохранено",
"Add": "Добавить",
"LearnMore": "Узнать больше",
"EnterCurrentPassword": "Введите текущий пароль",
"EnterNewPassword": "Введите новый пароль",
"RepeatNewPassword": "Повторите новый пароль",
"Signout": "Выйти",
"Settings": "Настройки"
}
}

View File

@ -14,13 +14,14 @@
-->
<script lang="ts">
import setting from '@anticrm/setting'
import presentation from '@anticrm/presentation'
import { Button, EditBox, Icon, Label } from '@anticrm/ui'
import { changePassword } from '@anticrm/login-resources'
let oldPassword: string = ''
let password: string = ''
let password2: string = ''
let label = setting.string.Save
let label = presentation.string.Save
let saved = false
$: disabled =
@ -34,7 +35,7 @@
label = setting.string.Saved
} catch (e) {
console.log(e)
label = setting.string.Save
label = presentation.string.Save
saved = false
}
}

View File

@ -47,10 +47,10 @@
</div>
<div class="flex-grow flex-col">
<div class="fs-title overflow-label">
{f.name}
<Label label={f.name} />
</div>
<div class="text-sm content-dark-color overflow-label">
{f.description}
<Label label={f.description} />
</div>
</div>
{#if f._id === folder?._id}

View File

@ -15,7 +15,7 @@
-->
<script lang="ts">
import type { Ref } from '@anticrm/core'
import type { Doc, Ref, Space } from '@anticrm/core'
import { AttributeEditor, createQuery, getClient } from '@anticrm/presentation'
import setting from '@anticrm/setting'
import task, { genRanks, KanbanTemplate, KanbanTemplateSpace } from '@anticrm/task'
@ -29,7 +29,7 @@
let templateMap = new Map<Ref<KanbanTemplate>, KanbanTemplate>()
const templatesQ = createQuery()
$: if (folder !== undefined) {
templatesQ.query(task.class.KanbanTemplate, { space: folder._id }, (result) => {
templatesQ.query(task.class.KanbanTemplate, { space: folder._id as Ref<Doc> as Ref<Space> }, (result) => {
templates = result
})
}
@ -50,7 +50,7 @@
const space = folder._id
const template = await client.createDoc(task.class.KanbanTemplate, space, {
const template = await client.createDoc(task.class.KanbanTemplate, space as Ref<Doc> as Ref<Space>, {
doneStatesC: 0,
statesC: 0,
title: 'New Template'
@ -73,7 +73,7 @@
await Promise.all(doneStates.map(async (ds) => {
await client.addCollection(
ds.class,
space,
space as Ref<Doc> as Ref<Space>,
template,
task.class.KanbanTemplate,
'doneStatesC',

View File

@ -106,7 +106,6 @@ export default plugin(settingId, {
ChangePassword: '' as IntlString,
CurrentPassword: '' as IntlString,
NewPassword: '' as IntlString,
Save: '' as IntlString,
Saving: '' as IntlString,
Saved: '' as IntlString,
EnterCurrentPassword: '' as IntlString,

Some files were not shown because too many files have changed in this diff Show More