erudit 4.0.0-dev.1 → 4.0.0-dev.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/app.vue +1 -2
- package/app/components/FancyBold.vue +0 -1
- package/app/components/FancyCard.vue +1 -2
- package/app/components/ads/AdsBannerAside.vue +1 -2
- package/app/components/ads/AdsReplacer.vue +2 -2
- package/app/components/aside/AsideListItem.vue +1 -1
- package/app/components/aside/AsideSwitch.vue +18 -8
- package/app/components/aside/major/PaneSwitcher.vue +1 -1
- package/app/components/aside/minor/AsideMinorPlainHeader.vue +2 -3
- package/app/components/aside/minor/content/AsideMinorContentTopic.vue +1 -4
- package/app/components/aside/minor/content/ButtonPaneContributions.vue +2 -4
- package/app/components/aside/minor/content/ButtonPaneImprove.vue +2 -3
- package/app/components/aside/minor/content/Contribution.vue +1 -1
- package/app/components/aside/minor/content/TocItem.vue +35 -21
- package/app/components/aside/minor/news/AsideMinorNews.vue +1 -2
- package/app/components/aside/minor/news/NewsItem.vue +2 -2
- package/app/components/aside/minor/news/elements/Ref.vue +1 -1
- package/app/components/main/MainContentChild.vue +2 -3
- package/app/components/main/MainDescription.vue +1 -1
- package/app/components/main/MainQuickLink.vue +20 -5
- package/app/components/main/MainQuickLinks.vue +1 -3
- package/app/components/main/MainQuote.vue +3 -6
- package/app/components/main/MainSection.vue +6 -21
- package/app/components/main/MainTitle.vue +1 -2
- package/app/components/main/MainTopicPartSwitch.vue +1 -1
- package/app/components/main/connections/Deps.vue +1 -1
- package/app/components/main/connections/Externals.vue +92 -34
- package/app/components/main/connections/MainConnections.vue +61 -8
- package/app/components/main/connections/MainConnectionsButton.vue +3 -2
- package/app/components/main/connections/ScrollPane.vue +2 -3
- package/app/components/main/contentStats/Item.vue +1 -2
- package/app/components/main/contentStats/MainContentStats.vue +6 -3
- package/app/components/preview/Preview.vue +1 -2
- package/app/components/preview/PreviewScreen.vue +1 -2
- package/app/components/site/SiteAside.vue +2 -4
- package/app/components/site/SiteMain.vue +1 -4
- package/app/components/tree/TreeItem.vue +1 -1
- package/app/composables/og.ts +19 -2
- package/app/pages/contributor/[contributorId].vue +1 -2
- package/app/pages/index.vue +1 -4
- package/app/styles/main.css +0 -1
- package/package.json +4 -4
- package/server/api/language/functions.ts +2 -2
- package/server/api/language/phrase/[phraseKey].ts +4 -1
- package/server/erudit/cameos/build.ts +77 -27
- package/server/erudit/content/global/build.ts +27 -1
- package/server/erudit/content/nav/build.ts +36 -4
- package/server/erudit/content/repository/elementSnippets.ts +51 -11
- package/server/erudit/content/repository/externals.ts +38 -9
- package/server/erudit/content/resolve/index.ts +172 -21
- package/server/erudit/content/resolve/topic.ts +93 -32
- package/server/erudit/content/resolve/utils/insertContentResolved.ts +48 -9
- package/server/erudit/content/search.ts +31 -3
- package/server/erudit/contributors/build.ts +106 -51
- package/server/erudit/db/repository/pushFile.ts +7 -4
- package/server/erudit/db/schema/content.ts +2 -2
- package/server/erudit/db/schema/contentSnippets.ts +3 -4
- package/server/erudit/language/list/en.ts +3 -96
- package/server/erudit/language/list/ru.ts +3 -97
- package/server/erudit/language/setup.ts +2 -2
- package/server/erudit/language/types.ts +2 -2
- package/server/erudit/news/build.ts +85 -48
- package/server/erudit/sponsors/build.ts +77 -26
- package/shared/types/contentConnections.ts +2 -2
- package/shared/types/elementSnippet.ts +9 -3
- package/shared/types/language.ts +2 -0
|
@@ -1,50 +1,111 @@
|
|
|
1
|
-
import { readdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { like } from 'drizzle-orm';
|
|
1
|
+
import { existsSync, readdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { eq, like } from 'drizzle-orm';
|
|
3
3
|
import { globSync } from 'glob';
|
|
4
4
|
import { isRawElement, type AnySchema, type ProseElement } from '@jsprose/core';
|
|
5
5
|
import {
|
|
6
|
+
contributorIdToPropertyName,
|
|
6
7
|
globalContributorsObject,
|
|
7
8
|
globalContributorsTypes,
|
|
8
9
|
type ContributorDefinition,
|
|
9
10
|
} from '@erudit-js/core/contributor';
|
|
10
11
|
|
|
11
|
-
// Trigger globalThis update
|
|
12
12
|
$CONTRIBUTOR;
|
|
13
13
|
|
|
14
|
+
let initialBuild = true;
|
|
15
|
+
|
|
16
|
+
const contributorsRoot = () => `${ERUDIT.config.paths.project}/contributors`;
|
|
17
|
+
|
|
18
|
+
const contributorsTypesPath = () =>
|
|
19
|
+
`${ERUDIT.config.paths.build}/types/contributors.d.ts`;
|
|
20
|
+
|
|
14
21
|
export async function buildContributors() {
|
|
15
|
-
if (!ERUDIT.config.public.project.contributors?.enabled)
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
22
|
+
if (!ERUDIT.config.public.project.contributors?.enabled) return;
|
|
18
23
|
|
|
19
24
|
ERUDIT.log.debug.start('Building contributors...');
|
|
20
25
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
.delete(ERUDIT.db.schema.files)
|
|
24
|
-
.where(like(ERUDIT.db.schema.files.role, 'contributor:%'));
|
|
26
|
+
const isInitial = initialBuild;
|
|
27
|
+
initialBuild = false;
|
|
25
28
|
|
|
26
|
-
const contributorIds =
|
|
27
|
-
`${ERUDIT.config.paths.project}/contributors/*/`,
|
|
28
|
-
{ posix: true },
|
|
29
|
-
).map((dirPath) => dirPath.split('/').pop() as string);
|
|
29
|
+
const contributorIds = collectContributorIds(isInitial);
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
if (!contributorIds.size) {
|
|
32
|
+
ERUDIT.log.info(
|
|
33
|
+
isInitial
|
|
34
|
+
? 'Skipping contributors — no contributors found.'
|
|
35
|
+
: 'Skipping contributors — nothing changed.',
|
|
36
|
+
);
|
|
37
|
+
return;
|
|
33
38
|
}
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
for (const id of contributorIds) {
|
|
41
|
+
await cleanupContributor(id);
|
|
42
|
+
}
|
|
36
43
|
|
|
37
|
-
|
|
38
|
-
`${
|
|
39
|
-
globalContributorsTypes($CONTRIBUTOR),
|
|
44
|
+
const existingIds = [...contributorIds].filter((id) =>
|
|
45
|
+
existsSync(`${contributorsRoot()}/${id}`),
|
|
40
46
|
);
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
syncContributorGlobals(existingIds);
|
|
49
|
+
|
|
50
|
+
if (!existingIds.length) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for (const id of existingIds) {
|
|
55
|
+
await buildContributor(id);
|
|
44
56
|
}
|
|
45
57
|
|
|
46
58
|
ERUDIT.log.success(
|
|
47
|
-
|
|
59
|
+
isInitial
|
|
60
|
+
? `Contributors build complete! (${ERUDIT.log.stress(contributorIds.size)})`
|
|
61
|
+
: `Contributors updated: ${ERUDIT.log.stress(existingIds.join(', '))}`,
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
//
|
|
66
|
+
//
|
|
67
|
+
//
|
|
68
|
+
|
|
69
|
+
function collectContributorIds(initial: boolean): Set<string> {
|
|
70
|
+
if (initial) {
|
|
71
|
+
return new Set(
|
|
72
|
+
globSync(`${contributorsRoot()}/*/`, { posix: true }).map(
|
|
73
|
+
(p) => p.split('/').at(-1)!,
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const ids = new Set<string>();
|
|
79
|
+
|
|
80
|
+
for (const file of ERUDIT.changedFiles.values()) {
|
|
81
|
+
if (!file.startsWith(`${contributorsRoot()}/`)) continue;
|
|
82
|
+
const id = file.replace(`${contributorsRoot()}/`, '').split('/')[0];
|
|
83
|
+
if (id) ids.add(id);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return ids;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function cleanupContributor(contributorId: string) {
|
|
90
|
+
await ERUDIT.db
|
|
91
|
+
.delete(ERUDIT.db.schema.contributors)
|
|
92
|
+
.where(eq(ERUDIT.db.schema.contributors.contributorId, contributorId));
|
|
93
|
+
|
|
94
|
+
await ERUDIT.db
|
|
95
|
+
.delete(ERUDIT.db.schema.files)
|
|
96
|
+
.where(
|
|
97
|
+
like(ERUDIT.db.schema.files.role, `contributor:${contributorId}%`),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
delete $CONTRIBUTOR[contributorIdToPropertyName(contributorId)];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function syncContributorGlobals(contributorIds: string[]) {
|
|
104
|
+
Object.assign($CONTRIBUTOR, globalContributorsObject(contributorIds));
|
|
105
|
+
|
|
106
|
+
writeFileSync(
|
|
107
|
+
contributorsTypesPath(),
|
|
108
|
+
globalContributorsTypes($CONTRIBUTOR),
|
|
48
109
|
);
|
|
49
110
|
}
|
|
50
111
|
|
|
@@ -53,59 +114,53 @@ async function buildContributor(contributorId: string) {
|
|
|
53
114
|
`Building contributor ${ERUDIT.log.stress(contributorId)}...`,
|
|
54
115
|
);
|
|
55
116
|
|
|
56
|
-
const
|
|
57
|
-
const files = readdirSync(
|
|
117
|
+
const dir = `${contributorsRoot()}/${contributorId}`;
|
|
118
|
+
const files = readdirSync(dir);
|
|
58
119
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
?.split('.')
|
|
62
|
-
.pop();
|
|
63
|
-
|
|
64
|
-
if (avatarExtension) {
|
|
120
|
+
const avatar = files.find((f) => f.startsWith('avatar.'));
|
|
121
|
+
if (avatar) {
|
|
65
122
|
await ERUDIT.repository.db.pushFile(
|
|
66
|
-
`${
|
|
123
|
+
`${dir}/${avatar}`,
|
|
67
124
|
`contributor:${contributorId}`,
|
|
68
125
|
);
|
|
69
126
|
}
|
|
70
127
|
|
|
71
|
-
let
|
|
128
|
+
let def: ContributorDefinition | undefined;
|
|
72
129
|
|
|
73
130
|
try {
|
|
74
|
-
|
|
75
|
-
} catch (
|
|
76
|
-
if (!String(
|
|
77
|
-
ERUDIT.log.error(
|
|
78
|
-
|
|
79
|
-
);
|
|
80
|
-
console.log(error);
|
|
131
|
+
def = await ERUDIT.import(`${dir}/contributor`);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
if (!String(err).includes('Cannot find module')) {
|
|
134
|
+
ERUDIT.log.error(`Failed to load contributor ${contributorId}:`);
|
|
135
|
+
console.error(err);
|
|
81
136
|
}
|
|
82
137
|
}
|
|
83
138
|
|
|
84
139
|
let description: ProseElement<AnySchema> | undefined;
|
|
85
140
|
|
|
86
|
-
if (isRawElement(
|
|
87
|
-
const
|
|
88
|
-
|
|
141
|
+
if (isRawElement(def?.description)) {
|
|
142
|
+
const resolved = await ERUDIT.repository.prose.resolve(
|
|
143
|
+
def.description,
|
|
89
144
|
false,
|
|
90
145
|
);
|
|
91
146
|
|
|
92
|
-
for (const file of
|
|
147
|
+
for (const file of resolved.files) {
|
|
93
148
|
await ERUDIT.repository.db.pushFile(
|
|
94
149
|
file,
|
|
95
150
|
`contributor:${contributorId}`,
|
|
96
151
|
);
|
|
97
152
|
}
|
|
98
153
|
|
|
99
|
-
description =
|
|
154
|
+
description = resolved.proseElement;
|
|
100
155
|
}
|
|
101
156
|
|
|
102
157
|
await ERUDIT.db.insert(ERUDIT.db.schema.contributors).values({
|
|
103
158
|
contributorId,
|
|
104
|
-
avatarExtension,
|
|
105
|
-
displayName:
|
|
106
|
-
short:
|
|
107
|
-
links:
|
|
108
|
-
editor:
|
|
109
|
-
description
|
|
159
|
+
avatarExtension: avatar?.split('.').pop(),
|
|
160
|
+
displayName: def?.displayName,
|
|
161
|
+
short: def?.short,
|
|
162
|
+
links: def?.links,
|
|
163
|
+
editor: def?.editor,
|
|
164
|
+
description,
|
|
110
165
|
});
|
|
111
166
|
}
|
|
@@ -16,8 +16,11 @@ export async function pushFile(filepath: string, role: string): Promise<void> {
|
|
|
16
16
|
'',
|
|
17
17
|
);
|
|
18
18
|
|
|
19
|
-
await ERUDIT.db
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
await ERUDIT.db
|
|
20
|
+
.insert(ERUDIT.db.schema.files)
|
|
21
|
+
.values({
|
|
22
|
+
path: relativePath,
|
|
23
|
+
role,
|
|
24
|
+
})
|
|
25
|
+
.onConflictDoNothing();
|
|
23
26
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
2
2
|
import type { ContentFlags } from '@erudit-js/core/content/flags';
|
|
3
3
|
import type { ContentType } from '@erudit-js/core/content/type';
|
|
4
|
-
import type {
|
|
4
|
+
import type { ContentExternalItem } from '@erudit-js/core/content/externals';
|
|
5
5
|
import type { ContentSeo } from '@erudit-js/core/content/seo';
|
|
6
6
|
|
|
7
7
|
export const content = sqliteTable('content', {
|
|
@@ -13,6 +13,6 @@ export const content = sqliteTable('content', {
|
|
|
13
13
|
hidden: integer({ mode: 'boolean' }).notNull(),
|
|
14
14
|
flags: text({ mode: 'json' }).$type<ContentFlags>(),
|
|
15
15
|
decorationExtension: text(),
|
|
16
|
-
externals: text({ mode: 'json' }).$type<
|
|
16
|
+
externals: text({ mode: 'json' }).$type<ContentExternalItem[]>(),
|
|
17
17
|
seo: text({ mode: 'json' }).$type<ContentSeo>(),
|
|
18
18
|
});
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
2
2
|
import type { ContentProseType } from '@erudit-js/core/content/prose';
|
|
3
|
+
import type { SnippetData } from '@erudit-js/prose';
|
|
3
4
|
|
|
4
5
|
export const contentSnippets = sqliteTable('contentSnippets', {
|
|
5
6
|
snippetId: integer().primaryKey({ autoIncrement: true }),
|
|
6
7
|
contentFullId: text().notNull(),
|
|
7
8
|
contentProseType: text().notNull().$type<ContentProseType>(),
|
|
8
|
-
title: text().notNull(),
|
|
9
|
-
description: text(),
|
|
10
|
-
elementId: text().notNull(),
|
|
11
9
|
schemaName: text().notNull(),
|
|
10
|
+
elementId: text().notNull(),
|
|
11
|
+
snippetData: text({ mode: 'json' }).$type<SnippetData>().notNull(),
|
|
12
12
|
search: integer({ mode: 'boolean' }).notNull(),
|
|
13
|
-
searchSynonyms: text({ mode: 'json' }).$type<string[]>(),
|
|
14
13
|
quick: integer({ mode: 'boolean' }).notNull(),
|
|
15
14
|
seo: integer({ mode: 'boolean' }).notNull(),
|
|
16
15
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
export const phrases: LanguagePhrases = {
|
|
2
2
|
language_code: 'en',
|
|
3
3
|
language_name: 'English',
|
|
4
4
|
erudit: 'Erudit',
|
|
@@ -97,107 +97,14 @@ const en: LanguagePhrases = {
|
|
|
97
97
|
`Summary of the topic "${contentTitle}": key definitions, theorems, properties and examples of their use. All the most important things in a concise form!`,
|
|
98
98
|
practice_seo_description: (contentTitle: string) =>
|
|
99
99
|
`Various problems with hints and answers on the topic "${contentTitle}". Interesting conditions, hints and detailed solutions. Turn knowledge into a skill!`,
|
|
100
|
+
externals_own: 'Own',
|
|
101
|
+
externals_from: 'From',
|
|
100
102
|
|
|
101
103
|
default_index_title: 'Erudit',
|
|
102
104
|
default_index_short: 'Modern digital textbooks!',
|
|
103
105
|
default_site_info_short: 'Modern textbook',
|
|
104
|
-
|
|
105
|
-
// _language_title: 'English',
|
|
106
|
-
// _language_code: 'en',
|
|
107
|
-
// site_info_title: 'Erudit',
|
|
108
|
-
// site_info_slogan: 'Modern textbook',
|
|
109
|
-
// seo_index_title: 'Erudit - CMS for eductional sites',
|
|
110
|
-
// seo_index_description:
|
|
111
|
-
// 'Erudit is a CMS for creating and managing perfect educational sites, maintained by the community.',
|
|
112
|
-
// seo_article_description: (contentTitle) =>
|
|
113
|
-
// `Clear and interesting explanation of the topic "${contentTitle}". Illustrative examples, important properties, interesting facts, life applications, clear proofs. Here you will definitely understand the topic!`,
|
|
114
|
-
// seo_summary_description: (contentTitle) =>
|
|
115
|
-
// `Summary of the topic "${contentTitle}": key definitions, theorems, properties and examples of their use. All the most important things in a concise form!`,
|
|
116
|
-
// seo_practice_description: (contentTitle) =>
|
|
117
|
-
// `Various problems with hints and answers on the topic "${contentTitle}". Interesting conditions, hints and detailed solutions. Turn knowledge into a skill!`,
|
|
118
|
-
// index: 'Index',
|
|
119
|
-
// pages: 'Pages',
|
|
120
|
-
// search: 'Search',
|
|
121
|
-
// language: 'Language',
|
|
122
|
-
// other: 'Other',
|
|
123
|
-
// ads_replacer:
|
|
124
|
-
// 'Help us develop the project.<br><strong>Disable your ads blocker!</strong>',
|
|
125
|
-
// theme: 'Theme',
|
|
126
|
-
// theme_system: 'System',
|
|
127
|
-
// theme_light: 'Light',
|
|
128
|
-
// theme_dark: 'Dark',
|
|
129
|
-
// content: 'Content',
|
|
130
|
-
// main_page: 'Main page',
|
|
131
|
-
// contributors: 'Contributors',
|
|
132
|
-
// contributors_page_description:
|
|
133
|
-
// 'List of people who contributed to the project materials: suggested valuable ideas, made corrections to existing material or wrote their own!',
|
|
134
|
-
// contributors_page_invite:
|
|
135
|
-
// 'You can also help the project, make a contribution and get on this page!',
|
|
136
|
-
// become_contributor: 'Become a contributor',
|
|
137
|
-
// contributor: 'Contributor',
|
|
138
|
-
// contribution: 'Contribution',
|
|
139
|
-
// contributions_explain: (count) =>
|
|
140
|
-
// `Contributed to ${m(count, 'material', 'materials')}`,
|
|
141
|
-
// contributor_description: (name) =>
|
|
142
|
-
// `Page with information about the contributor "${name}" and his contribution to the project.`,
|
|
143
|
-
// editor: 'Editor',
|
|
144
|
-
// add_translation: 'Add translation',
|
|
145
|
-
// empty_nav: 'Empty navigation',
|
|
146
|
-
|
|
147
|
-
// popover_dependencies: 'Dependencies',
|
|
148
|
-
// popover_dependencies_description:
|
|
149
|
-
// 'There is no royal way into this topic! You can only figure it out if you know the following topics:',
|
|
150
|
-
// to_index: 'To index',
|
|
151
|
-
// about_book: 'About book',
|
|
152
|
-
// close: 'Close',
|
|
153
|
-
// back: 'Back',
|
|
154
|
-
// goto: 'Go to',
|
|
155
|
-
// error: 'Error!',
|
|
156
|
-
// external_link: 'External link',
|
|
157
|
-
// external_link_warn: 'You are going to visit external resource!',
|
|
158
|
-
// internal_link: 'Internal link',
|
|
159
|
-
// internal_link_warn: 'You are going to visit internal site page!',
|
|
160
|
-
// book: 'Textbook',
|
|
161
|
-
// group: 'Group',
|
|
162
|
-
// topic: 'Topic',
|
|
163
|
-
// topics: 'Topics',
|
|
164
|
-
// article: 'Article',
|
|
165
|
-
// summary: 'Summary',
|
|
166
|
-
// practice: 'Practice',
|
|
167
|
-
// element_id: 'Element ID',
|
|
168
|
-
// preview_missing_title: 'Element not found!',
|
|
169
|
-
// preview_missing_explain: `Can't find the element with specified ID in this page!<br>Perhaps the element ID is specified incorrectly or the element has been changed/deleted.`,
|
|
170
|
-
// preview_missing_explain_mismatch: `Can't find the element with specified ID in this page!<br>The version of the linked page is different from the current version of the page!<br>This is most likely the cause of the error.`,
|
|
171
|
-
// preview_hash_mismatch_title: 'Page version mismatch!',
|
|
172
|
-
// preview_hash_mismatch_explain:
|
|
173
|
-
// 'The version of the page you see now is different from the version of the page the original link led to!<br>The content may be different from what you expected to see.',
|
|
174
|
-
// current_page_hash: 'Current hash',
|
|
175
|
-
// expected_page_hash: 'Expected hash',
|
|
176
|
-
// empty_toc: 'Empty table of contents...',
|
|
177
|
-
// no_contributors: 'No contributors...',
|
|
178
|
-
// make_contribution: 'Make a contribution',
|
|
179
|
-
// material_improvement: 'Material improvement',
|
|
180
|
-
// how_to_improve: 'How to improve?',
|
|
181
|
-
// edit_page: 'Edit page',
|
|
182
|
-
// report_problem: 'Report a problem',
|
|
183
|
-
// references: 'References',
|
|
184
|
-
// reference_source_featured: 'Featured source',
|
|
185
|
-
// references_description:
|
|
186
|
-
// 'A list of external sources that were used to write this material. If there is an asterisk next to the title, it is a featured source and is worth reading if you want to delve deeper into the material.',
|
|
187
|
-
// sponsors: 'Sponsors',
|
|
188
|
-
// sponsors_description:
|
|
189
|
-
// 'People and organizations that support the project financially. Thanks to them, we can continue to develop the project and improve the quality of materials. If you want to support the project, you can become a sponsor too!',
|
|
190
|
-
// become_sponsor: 'Become a sponsor',
|
|
191
|
-
// toc: 'Table of contents',
|
|
192
|
-
// mentions: (count) => m(count, 'mention', 'mentions'),
|
|
193
|
-
// start_learning: 'Start learning!',
|
|
194
|
-
// x_contributors: (count) => m(count, 'Contributor', 'Contributors'),
|
|
195
|
-
// x_sponsors: (count) => m(count, 'Sponsor', 'Sponsors'),
|
|
196
|
-
// show_all: 'Show all',
|
|
197
106
|
};
|
|
198
107
|
|
|
199
|
-
export default en;
|
|
200
|
-
|
|
201
108
|
export function m(
|
|
202
109
|
number: number,
|
|
203
110
|
one: string,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
export const phrases: LanguagePhrases = {
|
|
2
2
|
language_code: 'ru',
|
|
3
3
|
language_name: 'Русский',
|
|
4
4
|
erudit: 'Erudit',
|
|
@@ -98,108 +98,14 @@ const ru: LanguagePhrases = {
|
|
|
98
98
|
`Конспект темы «${contentTitle}»: ключевые определения, теоремы, свойства и примеры их использвания. Все самое важное и в кратком виде!`,
|
|
99
99
|
practice_seo_description: (contentTitle: string) =>
|
|
100
100
|
`Разнообразные задачи с подсказками и ответами по теме «${contentTitle}». Интересные условия, подсказки и подробные решения. Превратите знания в навык!`,
|
|
101
|
+
externals_own: 'Собственные',
|
|
102
|
+
externals_from: 'Из',
|
|
101
103
|
|
|
102
104
|
default_index_title: 'Erudit',
|
|
103
105
|
default_index_short: 'Современные цифровые учебники!',
|
|
104
106
|
default_site_info_short: 'Современный учебник',
|
|
105
|
-
|
|
106
|
-
// _language_title: 'Русский',
|
|
107
|
-
// _language_code: 'ru',
|
|
108
|
-
// site_info_title: 'Erudit',
|
|
109
|
-
// site_info_slogan: 'Современный учебник',
|
|
110
|
-
// seo_index_title: 'Erudit - CMS для образовательных сайтов',
|
|
111
|
-
// seo_index_description:
|
|
112
|
-
// 'Erudit — CMS для создания и управления идеальными образовательными сайтами, которые поддерживаются сообществом.',
|
|
113
|
-
// seo_article_description: (contentTitle) =>
|
|
114
|
-
// `Понятное и интересное объяснение темы «${contentTitle}». Показательные примеры, важные свойства, интересные факты, применение в жизни, понятные доказательства. Здесь вы точно разберетесь!`,
|
|
115
|
-
// seo_summary_description: (contentTitle) =>
|
|
116
|
-
// `Конспект темы «${contentTitle}»: ключевые определения, теоремы, свойства и примеры их использвания. Все самое важное и в кратком виде!`,
|
|
117
|
-
// seo_practice_description: (contentTitle) =>
|
|
118
|
-
// `Разнообразные задачи с подсказками и ответами по теме «${contentTitle}». Интересные условия, подсказки и подробные решения. Превратите знания в навык!`,
|
|
119
|
-
// index: 'Оглавление',
|
|
120
|
-
// pages: 'Страницы',
|
|
121
|
-
// search: 'Поиск',
|
|
122
|
-
// language: 'Язык',
|
|
123
|
-
// other: 'Другое',
|
|
124
|
-
// ads_replacer:
|
|
125
|
-
// 'Помогите улучшать проект.<br><strong>Включите показ рекламы!</strong>',
|
|
126
|
-
// theme: 'Тема',
|
|
127
|
-
// theme_system: 'Системная',
|
|
128
|
-
// theme_light: 'Светлая',
|
|
129
|
-
// theme_dark: 'Темная',
|
|
130
|
-
// content: 'Контент',
|
|
131
|
-
// main_page: 'Главная страница',
|
|
132
|
-
// contributors: 'Авторы',
|
|
133
|
-
// contributors_page_description:
|
|
134
|
-
// 'Список людей, которые внесли вклад в материалы проекта: предложили ценные идеи, вносили корректировки в существующий материал или же написали собственный!',
|
|
135
|
-
// contributors_page_invite:
|
|
136
|
-
// 'Вы тоже можете помочь проекту, внести свой вклад и попасть на эту страницу!',
|
|
137
|
-
// become_contributor: 'Стать автором',
|
|
138
|
-
// contributor: 'Автор',
|
|
139
|
-
// contribution: 'Вклад',
|
|
140
|
-
// contributions_explain: (count) =>
|
|
141
|
-
// `Вклад в ${m(count, 'материал', 'материала', 'материалов')}`,
|
|
142
|
-
// contributor_description: (name) =>
|
|
143
|
-
// `Страница с информацией о авторе "${name}" и его вкладе в проект.`,
|
|
144
|
-
// editor: 'Редактор',
|
|
145
|
-
// add_translation: 'Добавить перевод',
|
|
146
|
-
// empty_nav: 'Пустая навигация',
|
|
147
|
-
// popover_dependencies: 'Зависимости',
|
|
148
|
-
// popover_dependencies_description:
|
|
149
|
-
// 'Царского пути в эту тему нет! Вы сможете разобраться только если знаете следующие темы:',
|
|
150
|
-
// to_index: 'К оглавлению',
|
|
151
|
-
// about_book: 'Об учебнике',
|
|
152
|
-
// close: 'Закрыть',
|
|
153
|
-
// back: 'Назад',
|
|
154
|
-
// goto: 'Перейти',
|
|
155
|
-
// error: 'Ошибка!',
|
|
156
|
-
// external_link: 'Внешняя ссылка',
|
|
157
|
-
// external_link_warn: 'Вы собираетесь перейти на внешний ресурс!',
|
|
158
|
-
// internal_link: 'Внутренняя ссылка',
|
|
159
|
-
// internal_link_warn: 'Вы собираетесь перейти на внутреннюю страницу сайта!',
|
|
160
|
-
// book: 'Учебник',
|
|
161
|
-
// group: 'Группа',
|
|
162
|
-
// topic: 'Тема',
|
|
163
|
-
// topics: 'Темы',
|
|
164
|
-
// article: 'Статья',
|
|
165
|
-
// summary: 'Конспект',
|
|
166
|
-
// practice: 'Задачи',
|
|
167
|
-
// element_id: 'ID элемента',
|
|
168
|
-
// preview_missing_title: 'Элемент не найден!',
|
|
169
|
-
// preview_missing_explain:
|
|
170
|
-
// 'Не удалось найти на этой странице элемент с указанным ID!<br>Возможно, ID элемента указан неправильно или элемент был изменен/удален.',
|
|
171
|
-
// preview_missing_explain_mismatch: `Не удалось найти на этой странице элемент с указанным ID!<br>Версия страницы, на которую вела ссылка, отличается от текущей версии страницы!<br>Скорее всего, именно это и является причиной ошибки.`,
|
|
172
|
-
// preview_hash_mismatch_title: 'Несовпадение версий страницы!',
|
|
173
|
-
// preview_hash_mismatch_explain:
|
|
174
|
-
// 'Версия страницы, которую вы видите сейчас отличается от версии страницы, на которую вела исходная ссылка!<br>Содержимое может отличаться от того, что вы ожидали увидеть.',
|
|
175
|
-
// current_page_hash: 'Текущий хеш',
|
|
176
|
-
// expected_page_hash: 'Ожидаемый хеш',
|
|
177
|
-
// empty_toc: 'Пустая таблица содержимого...',
|
|
178
|
-
// no_contributors: 'Авторов нет...',
|
|
179
|
-
// make_contribution: 'Внести свой вклад',
|
|
180
|
-
// material_improvement: 'Улучшение материала',
|
|
181
|
-
// how_to_improve: 'Как улучшить?',
|
|
182
|
-
// edit_page: 'Редактировать страницу',
|
|
183
|
-
// report_problem: 'Сообщить о проблеме',
|
|
184
|
-
// references: 'Источники',
|
|
185
|
-
// reference_source_featured: 'Избранный источник',
|
|
186
|
-
// references_description:
|
|
187
|
-
// 'Список внешних источников, которые использовались при написании этого материала. Если рядом с названием стоит звездочка, то это избранный источник и с ним стоит ознакомиться, если вы хотите глубже погрузиться в материал.',
|
|
188
|
-
// sponsors: 'Спонсоры',
|
|
189
|
-
// sponsors_description:
|
|
190
|
-
// 'Список людей и организаций, которые поддерживают проект финансово. Благодаря им проект может существовать и развиваться. Если вы хотите помочь проекту, то тоже можете стать спонсором и попасть на эту страницу!',
|
|
191
|
-
// become_sponsor: 'Стать спонсором',
|
|
192
|
-
// toc: 'Содержание',
|
|
193
|
-
// mentions: (count: number) =>
|
|
194
|
-
// m(count, 'упоминание', 'упоминания', 'упоминаний'),
|
|
195
|
-
// start_learning: 'Начать изучение!',
|
|
196
|
-
// x_contributors: (count: number) => m(count, 'Автор', 'Автора', 'Авторов'),
|
|
197
|
-
// x_sponsors: (count: number) => m(count, 'Спонсор', 'Спонсора', 'Спонсоров'),
|
|
198
|
-
// show_all: 'Показать все',
|
|
199
107
|
};
|
|
200
108
|
|
|
201
|
-
export default ru;
|
|
202
|
-
|
|
203
109
|
export function m(
|
|
204
110
|
number: number,
|
|
205
111
|
one: string,
|
|
@@ -2,7 +2,7 @@ import { serverLanguages } from './list';
|
|
|
2
2
|
|
|
3
3
|
export async function setupServerLanguage() {
|
|
4
4
|
ERUDIT.language = {
|
|
5
|
-
phrases: {},
|
|
5
|
+
phrases: {} as any,
|
|
6
6
|
functions: {},
|
|
7
7
|
};
|
|
8
8
|
|
|
@@ -19,7 +19,7 @@ export async function setupServerLanguage() {
|
|
|
19
19
|
|
|
20
20
|
const languageModule = await serverLanguages[targetLanguage]();
|
|
21
21
|
|
|
22
|
-
ERUDIT.language.phrases = languageModule.
|
|
22
|
+
ERUDIT.language.phrases = languageModule.phrases;
|
|
23
23
|
|
|
24
24
|
for (const [funcKey, funcValue] of Object.entries(languageModule)) {
|
|
25
25
|
if (typeof funcValue === 'function') {
|
|
@@ -6,8 +6,8 @@ export interface EruditServerLanguage {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
export interface ServerLanguageModule {
|
|
9
|
-
|
|
10
|
-
[key: string]:
|
|
9
|
+
phrases: LanguagePhrases;
|
|
10
|
+
[key: string]: Function | LanguagePhrases;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export type ServerLanguageModules = Record<
|