-
Notifications
You must be signed in to change notification settings - Fork 10
t/33: Enabled configuration and localisation of headings #57
Conversation
tests/heading.js
Outdated
beforeEach( () => { | ||
const editorElement = document.createElement( 'div' ); | ||
|
||
const spy = testUtils.sinon.stub( Locale.prototype, '_t' ).returns( 'foo' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since items are localized in the heading plugin before stubbed editor.t
would work, this is the only way I see to test it. TBH, I don't like it and I wish we had some easier way to assert localization because it will repeat in many places.
…`t( String )` definitions.
…tial config.heading.formats value.
src/heading.js
Outdated
withText: true, | ||
items: collection | ||
} ); | ||
|
||
// Bind dropdown model to command. | ||
dropdownModel.bind( 'isEnabled' ).to( command, 'isEnabled' ); | ||
dropdownModel.bind( 'label' ).to( command, 'value', format => format.label ); | ||
dropdownModel.bind( 'label' ).to( command, 'value', ( { label } ) => label ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The previous version was much easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a matter of preference, I suppose. It's easier for me to read the second one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As with every preference, I can't say that your's weird, but... it is :D.
My way of thinking is – format => format.label
tells you that a format is turned into just its label. With the deconstruction pattern there you lose the context (the format). It's burried deep in the binding that you did, so the callback may be far from intiuitive at first.
src/heading.js
Outdated
@@ -40,23 +40,22 @@ export default class Heading extends Plugin { | |||
const collection = new Collection(); | |||
|
|||
// Add formats to collection. | |||
for ( let format of formats ) { | |||
for ( let { id, label } of formats ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you really need to change this code (in this PR), then be comprehensive – this can be a const
.
src/headingengine.js
Outdated
* @protected | ||
* @type {Array.<module:heading/headingcommand~HeadingFormat>} | ||
*/ | ||
get _formats() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/ckeditor/ckeditor5-design/wiki/Code-Style#order-within-class-definition – getters and setters go before methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OTOH, this more deserves to be a method – _getLocalizedFormats()
. Plus, even the API doc is misleading now because it doesn't explain why this getter exists in the first place.
src/headingengine.js
Outdated
editor.config.define( 'heading', { | ||
formats: [ | ||
{ id: 'paragraph', element: 'p', label: labels.Paragraph }, | ||
{ id: 'heading1', element: 'h2', label: labels[ 'Heading 1' ] }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the _formats
getter localizes these labels, why are you using localized versions here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that two things must be localized:
- Default config, which is
editor.config.define( 'heading', { formats: [ ... ] } )
. - User config, which is
editor.config.get( 'heading.formats' )
.
src/headingengine.js
Outdated
* @protected | ||
* @member {Object} #_localizedFormatLabels | ||
*/ | ||
const labels = this._localizedFormatLabels = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Must this be a property? It'd be a good private variable of this module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rationale – don't bloat the class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because of the above #57 (comment). Both default config and user config must be localized. The first is localized in constructor()
, the second in init()
. I cannot share these labels in any other way because they require editor.t()
to be created.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
User config can be localised together with the default config when they are processed by the _getLocalizedOptions()
method (currently _options
property, but I commented that it shouldn't be a property). The default config doesn't have to be localized beforehand.
You're right about the other thing, though. The localized labels cannot be defined in the module scope, because they require the t()
function. I missed that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw, this property also shouldn't use the word "format".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm thinking about the localization of user config and I'm afraid about one thing. Perhaps it's an edge case, but still...
Let's say you want editor in language X. So the _localizedOptionLabels
contains e.g. map like:
Paragraph: 'X Paragraph',
'Heading 1': 'X Heading 1',
...
Now, someone also specifies config.heading.options
, but want to use English strings there because for a weird case it make sense to keep them in English. But this turns to be impossible because they are automatically localized using _localizedOptionLabels
mapping.
I hope that this case is really that edgy as it sounds now and can be ignored.
PS. This applies to the current implementation and the one proposed by me above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If they want to use English strings so badly, they can write them with a ZWSP at the end, so _localizedOptionLabels
does not translate them to current editor language and just passes them thru =)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's an edge case, really. When someone translates the entire app but some labels.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know :D I thought about the same "solution".
So I guess it's all fine. But this can still be improved in the code:
User config can be localised together with the default config when they are processed by the _getLocalizedOptions() method (currently _options property, but I commented that it shouldn't be a property). The default config doesn't have to be localized beforehand.
src/headingengine.js
Outdated
|
||
if ( enterCommand ) { | ||
this.listenTo( enterCommand, 'afterExecute', ( evt, data ) => { | ||
const positionParent = editor.document.selection.getFirstPosition().parent; | ||
const batch = data.batch; | ||
const isHeading = formats.some( ( format ) => format.id == positionParent.name ); | ||
const isHeading = formats.some( ( { id } ) => id == positionParent.name ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert this. The previous version was more readable.
Please consider https://github.com/ckeditor/ckeditor5-heading/issues/52. You added What I don't know is how could the option be named ;> |
Last but not least – do we need to explicitly define the paragraph option? I wanted to ask the question because you may have a more concrete opinion about that, but personally I think that removing it from the config may only make things more complicated. |
OK, that wasn't all yet :D.
We don't need this option yet. And I don't think that anyone will ever need it. Even if your editor implements some oddest editing use case, the |
+1 Wanted to say exactly the same :) |
src/headingengine.js
Outdated
{ id: 'heading2', element: 'h3', label: labels[ 'Heading 2' ] }, | ||
{ id: 'heading3', element: 'h4', label: labels[ 'Heading 3' ] } | ||
], | ||
defaultOptionId: 'paragraph' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still to be removed.
src/headingengine.js
Outdated
* @protected | ||
* @type {Array.<module:heading/headingcommand~HeadingOption>} | ||
*/ | ||
get _options() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still to not be a getter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Take it easy ;-) It's a step–by–step refac.
src/headingengine.js
Outdated
* @readonly | ||
* @member {Array.<module:heading/headingcommand~HeadingOption>} #_cachedLocalizedOptions | ||
*/ | ||
return ( this._cachedLocalizedOptions = editor.config.get( 'heading.options' ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Srsly, a multiline assignment combined with a return statement? Please, de-obfuscate this :P
I changed the message to:
|
Suggested merge commit message (convention)
Feature: Enabled configuration and localization of headings. Closes ckeditor/ckeditor5#2418.
NOTE: Added
config.heading.formats
andconfig.heading.defaultFormatId
config options.