@seafile/sdoc-editor 0.5.35 → 0.5.37

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.
Files changed (28) hide show
  1. package/dist/basic-sdk/comment/components/comment-editor.js +10 -2
  2. package/dist/basic-sdk/comment/components/comment-item-wrapper.js +1 -1
  3. package/dist/basic-sdk/comment/components/global-comment/index.css +1 -1
  4. package/dist/basic-sdk/constants/index.js +3 -1
  5. package/dist/basic-sdk/editor/comment-article.js +13 -2
  6. package/dist/basic-sdk/editor/editable-article.js +2 -1
  7. package/dist/basic-sdk/extension/plugins/list/plugin/shortcut.js +13 -1
  8. package/dist/basic-sdk/extension/plugins/paragraph/render-elem.js +3 -1
  9. package/dist/basic-sdk/extension/plugins/table/render/index.css +1 -0
  10. package/dist/basic-sdk/extension/plugins/table/render/table-header/columns-header/index.js +1 -1
  11. package/dist/basic-sdk/extension/plugins/table/render/table-header/rows-columns-header.js +1 -1
  12. package/dist/basic-sdk/extension/plugins/table/render/table-header/rows-header/index.js +1 -1
  13. package/dist/basic-sdk/extension/render/render-comment-editor-element.js +1 -1
  14. package/dist/basic-sdk/layout/editor-content.js +19 -0
  15. package/dist/basic-sdk/utils/event-handler.js +5 -0
  16. package/dist/basic-sdk/views/sdoc-viewer.js +2 -3
  17. package/dist/components/doc-operations/more-operations.js +26 -2
  18. package/dist/context.js +7 -0
  19. package/dist/layout/layout.css +5 -0
  20. package/package.json +2 -1
  21. package/public/locales/cs/sdoc-editor.json +2 -2
  22. package/public/locales/de/sdoc-editor.json +2 -2
  23. package/public/locales/en/sdoc-editor.json +4 -3
  24. package/public/locales/es/sdoc-editor.json +2 -2
  25. package/public/locales/fr/sdoc-editor.json +2 -2
  26. package/public/locales/it/sdoc-editor.json +2 -2
  27. package/public/locales/ru/sdoc-editor.json +2 -2
  28. package/public/locales/zh_CN/sdoc-editor.json +4 -3
@@ -11,8 +11,9 @@ import { generateEmptyElement } from '../../extension/core';
11
11
  import { PARAGRAPH } from '../../extension/constants';
12
12
  import slateToMdString from '../../../slate-convert/slate-to-md';
13
13
  import mdStringToSlate from '../../../slate-convert/md-to-slate';
14
- import { COMMENT_EDITOR, COMMENT_EDITOR_EDIT_AREA_WIDTH } from '../../constants';
14
+ import { COMMENT_EDITOR, COMMENT_EDITOR_EDIT_AREA_WIDTH, INTERNAL_EVENT } from '../../constants';
15
15
  import { KeyCodes } from '../../../constants';
16
+ import EventBus from '../../utils/event-bus';
16
17
  const getSubmitTip = (type, content) => {
17
18
  if (content) return 'Save';
18
19
  return type === 'comment' ? 'Comment' : 'Reply';
@@ -87,6 +88,13 @@ const CommentEditor = _ref => {
87
88
  })];
88
89
  Transforms.select(editor, Editor.start(editor, []));
89
90
  }, [editor, updateValue, addParticipants, userInfo.username, placeholder]);
91
+ useEffect(() => {
92
+ const eventBus = EventBus.getInstance();
93
+ const unsubscribePostComment = eventBus.subscribe(INTERNAL_EVENT.COMMENT_EDITOR_POST_COMMENT, onSubmit);
94
+ return () => {
95
+ unsubscribePostComment();
96
+ };
97
+ }, [onSubmit]);
90
98
  const onCancel = useCallback(event => {
91
99
  event.stopPropagation();
92
100
  const {
@@ -144,6 +152,6 @@ const CommentEditor = _ref => {
144
152
  }));
145
153
  };
146
154
  CommentEditor.defaultProps = {
147
- placeholder: 'Enter_a_comment'
155
+ placeholder: 'Enter_comment_Enter_for_new_line_shift_enter_to_send'
148
156
  };
149
157
  export default CommentEditor;
@@ -233,7 +233,7 @@ const CommentItemWrapper = _ref => {
233
233
  'sdoc-resolved': comment.resolved,
234
234
  'd-flex flex-column pt-0': element
235
235
  });
236
- const tip = comment.resolved ? 'Reopen_discussion' : 'Enter_a_reply';
236
+ const tip = comment.resolved ? 'Reopen_discussion' : 'Enter_reply_Enter_for_new_line_Shift_Enter_to_send';
237
237
  return /*#__PURE__*/React.createElement("div", {
238
238
  id: "comment-item-wrapper_".concat(comment.id),
239
239
  className: className,
@@ -152,7 +152,7 @@
152
152
 
153
153
  .sdoc-comment-drawer .sdoc-doc-comment-editor-container .comment-ui-container.active {
154
154
  margin-bottom: 0;
155
- padding: 16px;
155
+ padding: 16px 10px;
156
156
  left: 0;
157
157
  }
158
158
 
@@ -22,7 +22,9 @@ export const INTERNAL_EVENT = {
22
22
  UPDATE_MENTION_TEMP_CONTENT: 'update_mention_temp_content',
23
23
  TABLE_COLUMN_START_DRAG: 'table_column_start_drag',
24
24
  TABLE_SHOW_DRAG_HANDLER: 'table_show_drag_handler',
25
- TABLE_HIDE_DRAG_HANDLER: 'table_show_drag_handler'
25
+ TABLE_HIDE_DRAG_HANDLER: 'table_show_drag_handler',
26
+ ON_PRINT: 'on_print',
27
+ COMMENT_EDITOR_POST_COMMENT: 'comment_editor_post_comment'
26
28
  };
27
29
  export const REVISION_DIFF_KEY = 'diff';
28
30
  export const REVISION_DIFF_VALUE = '1';
@@ -2,15 +2,16 @@ import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
2
  import React, { useCallback, useMemo } from 'react';
3
3
  import { Editable, ReactEditor, Slate } from '@seafile/slate-react';
4
4
  import { Editor, Node, Range } from '@seafile/slate';
5
+ import isHotkey from 'is-hotkey';
5
6
  import scrollIntoView from 'scroll-into-view-if-needed';
6
7
  import { renderLeaf } from '../extension';
7
- import EventProxy from '../utils/event-handler';
8
8
  import { useCursors } from '../cursor/use-cursors';
9
9
  import { INTERNAL_EVENT } from '../constants';
10
10
  import { usePipDecorate } from '../decorates';
11
11
  import EventBus from '../utils/event-bus';
12
12
  import { IMAGE } from '../extension/constants';
13
13
  import RenderCommentEditorCustomRenderElement from '../extension/render/render-comment-editor-element';
14
+ import EventProxy from '../utils/event-handler';
14
15
  const CommentArticle = _ref => {
15
16
  let {
16
17
  editor,
@@ -57,6 +58,15 @@ const CommentArticle = _ref => {
57
58
  //
58
59
  }
59
60
  }, []);
61
+ const onKeyDown = useCallback(event => {
62
+ if (isHotkey('shift+enter', event)) {
63
+ event.preventDefault();
64
+ const eventBus = EventBus.getInstance();
65
+ eventBus.dispatch(INTERNAL_EVENT.COMMENT_EDITOR_POST_COMMENT, event);
66
+ return;
67
+ }
68
+ eventProxy.onKeyDown(event);
69
+ }, [eventProxy]);
60
70
  return /*#__PURE__*/React.createElement(Slate, {
61
71
  editor: editor,
62
72
  value: slateValue,
@@ -74,7 +84,8 @@ const CommentArticle = _ref => {
74
84
  onCopy: eventProxy.onCopy,
75
85
  onCompositionStart: eventProxy.onCompositionStart,
76
86
  onCompositionUpdate: eventProxy.onCompositionUpdate,
77
- onCompositionEnd: eventProxy.onCompositionEnd
87
+ onCompositionEnd: eventProxy.onCompositionEnd,
88
+ onKeyDown: onKeyDown
78
89
  }));
79
90
  };
80
91
  export default CommentArticle;
@@ -177,7 +177,8 @@ const EditableArticle = _ref => {
177
177
  onMouseDown: onMouseDown,
178
178
  decorate: decorate,
179
179
  onCut: eventProxy.onCut,
180
- onCopy: eventProxy.onCopy
180
+ onCopy: eventProxy.onCopy,
181
+ id: "sdoc-editor"
181
182
  })), /*#__PURE__*/React.createElement(SideToolbar, null), isShowComment && /*#__PURE__*/React.createElement(CommentWrapper, {
182
183
  editor: editor,
183
184
  type: "editor"
@@ -1,8 +1,9 @@
1
1
  import { Editor, Path, Range, Transforms } from '@seafile/slate';
2
- import { ORDERED_LIST, PARAGRAPH } from '../../../constants';
2
+ import { INSERT_POSITION, ORDERED_LIST, PARAGRAPH } from '../../../constants';
3
3
  import { getBeforeText, setListType } from '../helpers';
4
4
  import { focusEditor, getLastChild, getPreviousPath } from '../../../core';
5
5
  import { generateEmptyListItem } from '../model';
6
+ import { toggleList } from '../transforms';
6
7
 
7
8
  /**
8
9
  * @param {Editor} editor
@@ -29,6 +30,17 @@ export const handleShortcut = (editor, text) => {
29
30
  // If the match fails or the match is not at the beginning of the line, it is not a shortcut
30
31
  if (!matchResult || matchResult.index !== 0) return false;
31
32
  const previousNodePath = getPreviousPath(aboveNodePath);
33
+
34
+ // No previous node means that the current paragraph is the first paragraph in the container
35
+ if (!previousNodePath) {
36
+ if (matchedText !== '1.') return false;
37
+ // Delete shortcut key text
38
+ Transforms.delete(editor, {
39
+ at: range
40
+ });
41
+ toggleList(editor, ORDERED_LIST);
42
+ return true;
43
+ }
32
44
  const [previousNode, previousPath] = Editor.node(editor, previousNodePath);
33
45
  // If the previous node is not an ordered list and is not start with `1.`,it is not a shortcut
34
46
  if (previousNode.type !== ORDERED_LIST && matchedText !== '1.') return false;
@@ -33,9 +33,11 @@ const Paragraph = _ref => {
33
33
  }
34
34
  const style = {
35
35
  textAlign: element.align,
36
+ paddingTop: '5px',
37
+ paddingBottom: '5px',
36
38
  paddingLeft: indent ? '28px' : ''
37
39
  };
38
- return /*#__PURE__*/React.createElement("p", Object.assign({
40
+ return /*#__PURE__*/React.createElement("div", Object.assign({
39
41
  "data-id": element.id
40
42
  }, attributes, {
41
43
  style: _objectSpread({
@@ -1,6 +1,7 @@
1
1
  .sdoc-table-wrapper {
2
2
  width: 100%;
3
3
  margin: 16px 0;
4
+ page-break-inside:avoid;
4
5
  }
5
6
 
6
7
  .sdoc-table-wrapper+.sdoc-table-wrapper {
@@ -41,7 +41,7 @@ const ColumnsHeader = _ref => {
41
41
  // eslint-disable-next-line react-hooks/exhaustive-deps
42
42
  }, [table, columns, tableSize]);
43
43
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
44
- className: "sdoc-table-columns-header position-absolute",
44
+ className: "sdoc-table-columns-header position-absolute d-print-none",
45
45
  contentEditable: false
46
46
  }, /*#__PURE__*/React.createElement("div", {
47
47
  className: "sdoc-table-columns-header-container h-100 d-flex position-absolute",
@@ -15,7 +15,7 @@ const RowsColumnsHeader = _ref => {
15
15
  maxColIndex: tableSize[1] - 1
16
16
  });
17
17
  return /*#__PURE__*/React.createElement("div", {
18
- className: classnames('sdoc-table-rows-columns-header', {
18
+ className: classnames('sdoc-table-rows-columns-header d-print-none', {
19
19
  'range-selected': isSelectedAllTableCells
20
20
  }),
21
21
  contentEditable: false,
@@ -45,7 +45,7 @@ const RowsHeader = _ref => {
45
45
  // eslint-disable-next-line react-hooks/exhaustive-deps
46
46
  }, [tableSize, table]);
47
47
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
48
- className: "sdoc-table-rows-header h-100 position-absolute d-flex flex-column",
48
+ className: "sdoc-table-rows-header h-100 position-absolute d-flex flex-column d-print-none",
49
49
  contentEditable: false
50
50
  }, children.map((row, index) => {
51
51
  return /*#__PURE__*/React.createElement(RowHeader, {
@@ -21,7 +21,7 @@ const RenderCommentEditorCustomRenderElement = props => {
21
21
  const [renderParagraph] = ParagraphPlugin.renderElements;
22
22
  return renderParagraph(_props);
23
23
  }
24
- const placeholder = commentType === 'comment' ? 'Enter_a_comment' : 'Enter_a_reply';
24
+ const placeholder = commentType === 'comment' ? 'Enter_comment_Enter_for_new_line_shift_enter_to_send' : 'Enter_reply_Enter_for_new_line_Shift_Enter_to_send';
25
25
  const [renderParagraph] = ParagraphPlugin.renderElements;
26
26
  return renderParagraph(_objectSpread(_objectSpread({}, _props), {}, {
27
27
  placeholder
@@ -25,6 +25,25 @@ const EditorContent = _ref => {
25
25
  'readonly': readonly,
26
26
  'no-outline': !showOutline
27
27
  });
28
+ if (readonly) {
29
+ return /*#__PURE__*/React.createElement("div", {
30
+ className: "sdoc-content-wrapper"
31
+ }, /*#__PURE__*/React.createElement("div", {
32
+ ref: scrollRef,
33
+ className: "sdoc-scroll-container",
34
+ onScroll: onWrapperScroll,
35
+ id: "sdoc-scroll-container"
36
+ }, /*#__PURE__*/React.createElement(ScrollContext.Provider, {
37
+ value: {
38
+ scrollRef
39
+ }
40
+ }, /*#__PURE__*/React.createElement("div", {
41
+ className: className
42
+ }, showOutline && /*#__PURE__*/React.createElement(SDocOutline, {
43
+ scrollLeft: scrollLeft,
44
+ doc: docValue
45
+ }), children))));
46
+ }
28
47
  return /*#__PURE__*/React.createElement("div", {
29
48
  className: "sdoc-content-wrapper"
30
49
  }, /*#__PURE__*/React.createElement(CommentProvider, {
@@ -67,6 +67,11 @@ class EventProxy {
67
67
  if (isHotkey('tab', event) || isHotkey('shift+tab', event)) {
68
68
  editor.handleTab && editor.handleTab(event);
69
69
  }
70
+ if (isHotkey('mod+p', event)) {
71
+ event.preventDefault();
72
+ const eventBus = EventBus.getInstance();
73
+ eventBus.dispatch(INTERNAL_EVENT.ON_PRINT);
74
+ }
70
75
  const node = getSelectedNodeByType(editor, ELEMENT_TYPE.TABLE);
71
76
  if (node) {
72
77
  this.editor.tableOnKeyDown(event);
@@ -5,7 +5,6 @@ import { generateDefaultDocContent } from '../../utils';
5
5
  import { EditorContainer, EditorContent } from '../layout';
6
6
  import ReadOnlyArticle from './readonly-article';
7
7
  import { ColorProvider } from '../hooks/use-color-context';
8
- import { CollaboratorsProvider } from '../../hooks';
9
8
  import '../assets/css/simple-viewer.css';
10
9
  const SDocViewer = _ref => {
11
10
  let {
@@ -19,7 +18,7 @@ const SDocViewer = _ref => {
19
18
  return /*#__PURE__*/React.createElement(EditorContainer, {
20
19
  editor: validEditor,
21
20
  readonly: true
22
- }, /*#__PURE__*/React.createElement(CollaboratorsProvider, null, /*#__PURE__*/React.createElement(ColorProvider, null, showToolbar && /*#__PURE__*/React.createElement(HeaderToolbar, {
21
+ }, /*#__PURE__*/React.createElement(ColorProvider, null, showToolbar && /*#__PURE__*/React.createElement(HeaderToolbar, {
23
22
  editor: validEditor,
24
23
  readonly: true
25
24
  }), /*#__PURE__*/React.createElement(EditorContent, {
@@ -30,7 +29,7 @@ const SDocViewer = _ref => {
30
29
  }, /*#__PURE__*/React.createElement(ReadOnlyArticle, {
31
30
  editor: validEditor,
32
31
  slateValue: slateValue
33
- })))));
32
+ }))));
34
33
  };
35
34
  SDocViewer.defaultProps = {
36
35
  showToolbar: false,
@@ -1,9 +1,11 @@
1
- import React, { useCallback, useState } from 'react';
1
+ import React, { useCallback, useEffect, useState } from 'react';
2
2
  import { withTranslation } from 'react-i18next';
3
3
  import { Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
4
+ import printJS from '@seafile/print-js';
4
5
  import { EventBus } from '../../basic-sdk';
5
6
  import { EXTERNAL_EVENT } from '../../constants';
6
7
  import context from '../../context';
8
+ import { INTERNAL_EVENT } from '../../basic-sdk/constants';
7
9
  const MoreOperations = _ref => {
8
10
  let {
9
11
  t
@@ -15,9 +17,28 @@ const MoreOperations = _ref => {
15
17
  const docPerm = context.getSetting('docPerm');
16
18
  const historyURL = context.getSetting('historyURL');
17
19
  const isSdocRevision = context.getSetting('isSdocRevision');
20
+ const cssUrls = context.getPrintCss();
21
+ useEffect(() => {
22
+ const eventBus = EventBus.getInstance();
23
+ const unSubscribe = eventBus.subscribe(INTERNAL_EVENT.ON_PRINT, handlePrint);
24
+ return () => {
25
+ unSubscribe();
26
+ };
27
+ // eslint-disable-next-line react-hooks/exhaustive-deps
28
+ }, []);
18
29
  const toggleDropdown = useCallback(isDropdownOpen => {
19
30
  setIsDropdownOpen(!isDropdownOpen);
20
31
  }, []);
32
+ const handlePrint = useCallback(() => {
33
+ printJS({
34
+ printable: 'sdoc-editor',
35
+ type: 'html',
36
+ scanStyles: true,
37
+ targetStyles: ['*'],
38
+ style: '@page { size: auto A4 landscape;margin:20px auto; padding: 0;} .d-print-none{display:none !important;}',
39
+ css: cssUrls
40
+ });
41
+ }, [cssUrls]);
21
42
  const onFreezeDocument = useCallback(() => {
22
43
  const eventBus = EventBus.getInstance();
23
44
  eventBus.dispatch(EXTERNAL_EVENT.FREEZE_DOCUMENT);
@@ -51,7 +72,10 @@ const MoreOperations = _ref => {
51
72
  }, t('Open_parent_folder')), isPro && isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
52
73
  className: "sdoc-dropdown-menu-item",
53
74
  onClick: unFreeze
54
- }, t('Unfreeze')), isPro && !isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
75
+ }, t('Unfreeze')), /*#__PURE__*/React.createElement(DropdownItem, {
76
+ className: "sdoc-dropdown-menu-item",
77
+ onClick: handlePrint
78
+ }, t('Print')), isPro && !isFreezed && /*#__PURE__*/React.createElement(DropdownItem, {
55
79
  className: "sdoc-dropdown-menu-item",
56
80
  onClick: onFreezeDocument
57
81
  }, t('Freeze_document')), /*#__PURE__*/React.createElement(DropdownItem, {
package/dist/context.js CHANGED
@@ -57,6 +57,13 @@ class Context {
57
57
  if (this.settings[key] === false) return this.settings[key];
58
58
  return this.settings[key] || '';
59
59
  }
60
+ getPrintCss() {
61
+ const server = this.getSetting('serviceUrl');
62
+ const mediaUrl = this.getSetting('mediaUrl');
63
+ const commonCss = "".concat(server).concat(mediaUrl, "css/seafile-ui.css");
64
+ const fontCss = "".concat(server).concat(mediaUrl, "/sdoc-editor/sdoc-editor-font.css");
65
+ return [commonCss, fontCss];
66
+ }
60
67
  updateSettings(update) {
61
68
  for (let key in update) {
62
69
  this.settings[key] = update[key];
@@ -1,3 +1,8 @@
1
+ body {
2
+ -webkit-print-color-adjust: exact;
3
+ color-adjust: exact;
4
+ }
5
+
1
6
  #root, #wrapper {
2
7
  height: 100%;
3
8
  width: 100%;
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@seafile/sdoc-editor",
3
- "version": "0.5.35",
3
+ "version": "0.5.37",
4
4
  "private": false,
5
5
  "description": "This is a sdoc editor",
6
6
  "main": "dist/index.js",
7
7
  "dependencies": {
8
+ "@seafile/print-js": "^1.6.2",
8
9
  "@seafile/react-image-lightbox": "2.0.4",
9
10
  "@seafile/slate": "0.91.8",
10
11
  "@seafile/slate-history": "0.86.2",
@@ -274,8 +274,8 @@
274
274
  "Delete_reply": "Delete reply",
275
275
  "Are_you_sure_to_delete_this_comment": "Are you sure to delete this comment?",
276
276
  "Are_you_sure_to_delete_this_reply": "Are you sure to delete this reply?",
277
- "Enter_a_comment": "Enter a comment",
278
- "Enter_a_reply": "Enter a reply",
277
+ "Enter_comment_Enter_for_new_line_shift_enter_to_send": "Enter a comment",
278
+ "Enter_reply_Enter_for_new_line_Shift_Enter_to_send": "Enter a reply",
279
279
  "Reopen_discussion": "Adding a reply will reopen this discussion",
280
280
  "Confirm": "Potvrdit",
281
281
  "View_changes": "View changes",
@@ -274,8 +274,8 @@
274
274
  "Delete_reply": "Delete reply",
275
275
  "Are_you_sure_to_delete_this_comment": "Are you sure to delete this comment?",
276
276
  "Are_you_sure_to_delete_this_reply": "Are you sure to delete this reply?",
277
- "Enter_a_comment": "Enter a comment",
278
- "Enter_a_reply": "Enter a reply",
277
+ "Enter_comment_Enter_for_new_line_shift_enter_to_send": "Enter a comment",
278
+ "Enter_reply_Enter_for_new_line_Shift_Enter_to_send": "Enter a reply",
279
279
  "Reopen_discussion": "Adding a reply will reopen this discussion",
280
280
  "Confirm": "Bestätigen",
281
281
  "View_changes": "View changes",
@@ -274,8 +274,8 @@
274
274
  "Delete_reply": "Delete reply",
275
275
  "Are_you_sure_to_delete_this_comment": "Are you sure to delete this comment?",
276
276
  "Are_you_sure_to_delete_this_reply": "Are you sure to delete this reply?",
277
- "Enter_a_comment": "Enter a comment",
278
- "Enter_a_reply": "Enter a reply",
277
+ "Enter_comment_Enter_for_new_line_shift_enter_to_send": "Enter comment, Enter for new line, Shift + Enter to send",
278
+ "Enter_reply_Enter_for_new_line_Shift_Enter_to_send": "Enter reply, Enter for new line, Shift + Enter to send",
279
279
  "Reopen_discussion": "Adding a reply will reopen this discussion",
280
280
  "Confirm": "Confirm",
281
281
  "View_changes": "View changes",
@@ -452,5 +452,6 @@
452
452
  "Move_column_count": "Moving {{count}} column(s)",
453
453
  "Move_row_count": "Moving {{count}} row(s)",
454
454
  "Mark_all_as_read": "Mark all as read",
455
- "Alignment_type": "Alignment"
455
+ "Alignment_type": "Alignment",
456
+ "Print": "Print"
456
457
  }
@@ -274,8 +274,8 @@
274
274
  "Delete_reply": "Delete reply",
275
275
  "Are_you_sure_to_delete_this_comment": "Are you sure to delete this comment?",
276
276
  "Are_you_sure_to_delete_this_reply": "Are you sure to delete this reply?",
277
- "Enter_a_comment": "Enter a comment",
278
- "Enter_a_reply": "Enter a reply",
277
+ "Enter_comment_Enter_for_new_line_shift_enter_to_send": "Enter a comment",
278
+ "Enter_reply_Enter_for_new_line_Shift_Enter_to_send": "Enter a reply",
279
279
  "Reopen_discussion": "Adding a reply will reopen this discussion",
280
280
  "Confirm": "Confirmar",
281
281
  "View_changes": "View changes",
@@ -274,8 +274,8 @@
274
274
  "Delete_reply": "Supprimer la réponse",
275
275
  "Are_you_sure_to_delete_this_comment": "Êtes-vous sûr de vouloir supprimer ce commentaire ?",
276
276
  "Are_you_sure_to_delete_this_reply": "Êtes-vous sûr de vouloir supprimer cette réponse ?",
277
- "Enter_a_comment": "Saisir un commentaire",
278
- "Enter_a_reply": "Saisir une réponse",
277
+ "Enter_comment_Enter_for_new_line_shift_enter_to_send": "Saisir un commentaire",
278
+ "Enter_reply_Enter_for_new_line_Shift_Enter_to_send": "Saisir une réponse",
279
279
  "Reopen_discussion": "L'ajout d'une réponse rouvrira la discussion.",
280
280
  "Confirm": "Confirmer",
281
281
  "View_changes": "Afficher les modifications",
@@ -274,8 +274,8 @@
274
274
  "Delete_reply": "Delete reply",
275
275
  "Are_you_sure_to_delete_this_comment": "Are you sure to delete this comment?",
276
276
  "Are_you_sure_to_delete_this_reply": "Are you sure to delete this reply?",
277
- "Enter_a_comment": "Enter a comment",
278
- "Enter_a_reply": "Enter a reply",
277
+ "Enter_comment_Enter_for_new_line_shift_enter_to_send": "Enter a comment",
278
+ "Enter_reply_Enter_for_new_line_Shift_Enter_to_send": "Enter a reply",
279
279
  "Reopen_discussion": "Adding a reply will reopen this discussion",
280
280
  "Confirm": "Confirm",
281
281
  "View_changes": "View changes",
@@ -274,8 +274,8 @@
274
274
  "Delete_reply": "Удалить ответ",
275
275
  "Are_you_sure_to_delete_this_comment": "Вы уверены, что удалите этот комментарий?",
276
276
  "Are_you_sure_to_delete_this_reply": "Вы уверены, что удалите этот ответ?",
277
- "Enter_a_comment": "Введите комментарий",
278
- "Enter_a_reply": "Введите ответ",
277
+ "Enter_comment_Enter_for_new_line_shift_enter_to_send": "Введите комментарий",
278
+ "Enter_reply_Enter_for_new_line_Shift_Enter_to_send": "Введите ответ",
279
279
  "Reopen_discussion": "Добавление ответа приведёт к возобновлению обсуждения.",
280
280
  "Confirm": "Подтвердить",
281
281
  "View_changes": "Просмотр изменений",
@@ -274,8 +274,8 @@
274
274
  "Delete_reply": "删除回复",
275
275
  "Are_you_sure_to_delete_this_comment": "你确定要删除这个评论吗?",
276
276
  "Are_you_sure_to_delete_this_reply": "你确定要删除这个回复吗?",
277
- "Enter_a_comment": "输入评论",
278
- "Enter_a_reply": "输入回复",
277
+ "Enter_comment_Enter_for_new_line_shift_enter_to_send": "输入评论,Enter 换行,Shift + Enter 发送",
278
+ "Enter_reply_Enter_for_new_line_Shift_Enter_to_send": "输入回复,Enter 换行,Shift + Enter 发送",
279
279
  "Reopen_discussion": "添加回复会重新提出该讨论",
280
280
  "Confirm": "确认",
281
281
  "View_changes": "查看改动",
@@ -452,5 +452,6 @@
452
452
  "Move_column_count": "移动{{count}}列",
453
453
  "Move_row_count": "移动{{count}}行",
454
454
  "Mark_all_as_read": "全部标记为已读",
455
- "Alignment_type": "对齐方式"
455
+ "Alignment_type": "对齐方式",
456
+ "Print": "打印"
456
457
  }