Merge pull request #14658 from keymanapp/fix/developer/new-ldml-keyboard-project-validation-message

fix(developer): add clear messages about validation failures to New LDML Project Parameters form
This commit is contained in:
Marc Durdin 2025-09-02 11:29:39 +02:00 committed by GitHub
commit c263a2bd2a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 516 additions and 265 deletions

View file

@ -2,9 +2,12 @@
title: New LDML Keyboard Project Parameters Dialog
---
Allows you to quickly fill in common parameters for a new LDML keyboard project, adding keyboard, package, documentation and metadata files, following the [file layout](/developer/keyboards/) used in the [Keyman keyboards repository](https://github.com/keymanapp/keyboards).
Allows you to quickly fill in common parameters for a new LDML keyboard project,
adding keyboard, package, documentation and metadata files, following the [file
layout](/developer/keyboards/) used in the [Keyman keyboards
repository](https://github.com/keymanapp/keyboards).
Projects can also be created from the command line with [KMConvert](kmconvert).
Projects can also be created from the command line with [kmc generate](kmc).
![Keyboard Editor - New file, Details tab](../images/ui/frmNewLDMLProjectParameters.png)
@ -12,25 +15,54 @@ Projects can also be created from the command line with [KMConvert](kmconvert).
Keyboard Name
: **Required.** The descriptive name of the keyboard. This will be set in the
`<info name` attribute value in the keyboard, in the
package name, and where appropriate in documentation and metadata.
: **Required.** The name of the keyboard presented to end users. This will be
set in the `<info name` attribute value in the keyboard, in the package name,
and where appropriate in documentation and metadata.
Description
: **Required.** A short description of the purpose of the keyboard. This will
show up in a keyboard search on keyman.com and supports basic Markdown (no
embedded HTML). This is stored in the package metadata.
: **Required.** This field should describe your keyboard to people who find it
online. It should explain the purpose of the keyboard in a friendly,
descriptive way. The description could include details that will help users to
decide if this keyboard is the appropriate choice for their needs.
: The first paragraph of the description will appear in the keyboard search
result on keyman.com; the full description will be shown in the keyboard
details page on keyman.com. Use
[Markdown](https://www.markdownguide.org/basic-syntax) to include basic
formatting, but not embedded HTML is not allowed.
: To add images to the description, you will need to reference an image on a
server accessible online. For example, to use images from the Keyman
keyboard repository where this keyboard can be uploaded, you can use the
GitHub source. The URL starts with
https://raw.githubusercontent.com/keymanapp/keyboards/master/ + the path to
the image within the repository. For example:
```md
![GFF Mesobe Fidelat keyboard](https://raw.githubusercontent.com/keymanapp/keyboards/master/release/gff/gff_mesobe_fidelat/source/help/images/gff_mesobe_fidelat-default-1.jpeg)
```
> [!IMPORTANT]
> Images should not be included in the first paragraph.
* Learn more about the [keyboard repository](https://help.keyman.com/developer/keyboards/)
* The description can be edited later in the [Package Editor](package-editor).
Author
: Optional. The name of the developer of the keyboard. This will be set in
the package metadata, and where appropriate in documentation and metadata.
Copyright, Full Copyright
Copyright
: Optional. A copyright string for the keyboard. This will be set in the
package metadata, and where appropriate in documentation and metadata.
: Optional. A copyright string for the keyboard, excluding copyright year(s).
This will be set in the package metadata, and where appropriate in
documentation and metadata.
Full Copyright
: The same copyright string for the keyboard, including copyright year.
Version

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 171 KiB

View file

@ -1,222 +1,338 @@
inherited frmNewLDMLKeyboardProjectParameters: TfrmNewLDMLKeyboardProjectParameters
BorderIcons = [biSystemMenu]
BorderStyle = bsDialog
Caption = 'New LDML Keyboard Project'
ClientHeight = 465
ClientWidth = 625
Position = poScreenCenter
ExplicitWidth = 631
ExplicitHeight = 494
PixelsPerInch = 96
TextHeight = 13
object lblFileName: TLabel
Left = 12
Top = 406
Width = 64
Height = 13
Caption = '&Keyboard ID:'
FocusControl = editKeyboardID
end
object lblPath: TLabel
Left = 12
Top = 379
Width = 26
Height = 13
Caption = '&Path:'
FocusControl = editPath
end
object lblKeyboardName: TLabel
Left = 12
Top = 11
Width = 80
Height = 13
Caption = 'Keyboard &Name:'
FocusControl = editKeyboardName
end
object lblCoypright: TLabel
Left = 12
Top = 180
Width = 51
Height = 13
Caption = '&Copyright:'
FocusControl = editCopyright
end
object lblVersion: TLabel
Left = 12
Top = 233
Width = 39
Height = 13
Caption = '&Version:'
FocusControl = editVersion
end
object lblAuthor: TLabel
Left = 12
Top = 153
Width = 37
Height = 13
Caption = 'A&uthor:'
FocusControl = editAuthor
end
object lblKeyboardLanguages: TLabel
Left = 419
Top = 260
Width = 145
Height = 26
Caption = '(one BCP 47 tag per line, first tag is primary)'
WordWrap = True
end
object lblProjectFilename: TLabel
Left = 12
Top = 433
Width = 77
Height = 13
Caption = 'Project &filename'
FocusControl = editProjectFilename
end
object Label1: TLabel
Left = 12
Top = 206
Width = 68
Height = 13
Caption = 'Fu&ll copyright:'
FocusControl = editFullCopyright
end
object Label2: TLabel
Left = 12
Top = 38
Width = 53
Height = 13
Caption = '&Description'
FocusControl = memoDescription
end
object Label3: TLabel
Left = 12
Top = 260
Width = 102
Height = 13
Caption = '&Supported languages'
FocusControl = memoLanguages
end
object Label4: TLabel
Left = 331
Top = 233
Width = 232
Height = 13
Caption = 'Semantic version: major.minor.patch, e.g. 1.0.1'
end
object editKeyboardID: TEdit
Left = 120
Top = 403
Width = 205
Height = 21
TabOrder = 9
OnChange = editKeyboardIDChange
end
object cmdBrowse: TButton
Left = 340
Top = 376
Width = 73
Height = 21
Caption = '&Browse...'
TabOrder = 8
OnClick = cmdBrowseClick
end
object editPath: TEdit
Left = 120
Top = 376
Width = 205
Height = 21
TabOrder = 7
OnChange = editPathChange
end
object editKeyboardName: TEdit
Left = 120
Top = 8
Width = 205
Height = 21
TabOrder = 0
OnChange = editKeyboardNameChange
end
object editCopyright: TEdit
Left = 120
Top = 176
Width = 205
Height = 21
TabOrder = 3
Text = 'Copyright '#169
OnChange = editCopyrightChange
end
object editVersion: TEdit
Left = 120
Top = 230
Width = 205
Height = 21
TabOrder = 5
Text = '1.0.0'
OnChange = editVersionChange
end
object editAuthor: TEdit
Left = 120
Top = 150
Width = 205
Height = 21
TabOrder = 2
OnChange = editAuthorChange
end
object cmdOK: TButton
Left = 463
Top = 428
Width = 73
Height = 25
Caption = 'OK'
Default = True
TabOrder = 11
OnClick = cmdOKClick
end
object cmdCancel: TButton
Left = 542
Top = 428
Width = 73
Height = 25
Cancel = True
Caption = 'Cancel'
ModalResult = 2
TabOrder = 12
end
object editProjectFilename: TEdit
Left = 120
Top = 430
Width = 293
Height = 21
TabStop = False
ParentColor = True
ReadOnly = True
TabOrder = 10
OnChange = editKeyboardIDChange
end
object editFullCopyright: TEdit
Left = 120
Top = 203
Width = 205
Height = 21
TabOrder = 4
Text = 'Copyright '#169' YYYY'
OnChange = editFullCopyrightChange
end
object memoDescription: TMemo
Left = 120
Top = 35
Width = 497
Height = 109
TabOrder = 1
OnChange = memoDescriptionChange
end
object memoLanguages: TMemo
Left = 120
Top = 257
Width = 293
Height = 113
TabOrder = 6
OnChange = memoLanguagesChange
end
end
inherited frmNewLDMLKeyboardProjectParameters: TfrmNewLDMLKeyboardProjectParameters
BorderIcons = [biSystemMenu]
BorderStyle = bsDialog
Caption = 'New LDML Keyboard Project'
ClientHeight = 520
ClientWidth = 721
Position = poScreenCenter
OnDestroy = FormDestroy
ExplicitWidth = 727
ExplicitHeight = 549
PixelsPerInch = 96
TextHeight = 13
object lblKeyboardID: TLabel
Left = 12
Top = 430
Width = 64
Height = 13
Caption = '&Keyboard ID:'
FocusControl = editKeyboardID
end
object lblPath: TLabel
Left = 12
Top = 403
Width = 26
Height = 13
Caption = '&Path:'
FocusControl = editPath
end
object lblKeyboardName: TLabel
Left = 12
Top = 11
Width = 80
Height = 13
Caption = 'Keyboard &Name:'
FocusControl = editKeyboardName
end
object lblCoypright: TLabel
Left = 12
Top = 180
Width = 51
Height = 13
Caption = '&Copyright:'
FocusControl = editCopyright
end
object lblVersion: TLabel
Left = 12
Top = 233
Width = 39
Height = 13
Caption = '&Version:'
FocusControl = editVersion
end
object lblAuthor: TLabel
Left = 12
Top = 153
Width = 37
Height = 13
Caption = 'A&uthor:'
FocusControl = editAuthor
end
object lblKeyboardLanguages: TLabel
Left = 120
Top = 381
Width = 265
Height = 26
Caption = '(one BCP 47 tag per line, first tag is primary)'
WordWrap = True
end
object lblProjectFilename: TLabel
Left = 12
Top = 457
Width = 77
Height = 13
Caption = 'Project &filename'
FocusControl = editProjectFilename
end
object lblFullCopyright: TLabel
Left = 12
Top = 206
Width = 68
Height = 13
Caption = 'Fu&ll copyright:'
FocusControl = editFullCopyright
end
object lblDescription: TLabel
Left = 12
Top = 38
Width = 53
Height = 13
Caption = '&Description'
FocusControl = memoDescription
end
object lblLanguages: TLabel
Left = 12
Top = 284
Width = 102
Height = 13
Caption = '&Supported languages'
FocusControl = memoLanguages
end
object Label4: TLabel
Left = 120
Top = 256
Width = 232
Height = 13
Caption = 'Semantic version: major.minor.patch, e.g. 1.0.1'
end
object lblKeyboardNameValidation: TLabel
Left = 424
Top = 11
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = editKeyboardName
WordWrap = True
end
object lblDescriptionValidation: TLabel
Left = 424
Top = 38
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = memoDescription
WordWrap = True
end
object lblCopyrightValidation: TLabel
Left = 424
Top = 180
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = editCopyright
WordWrap = True
end
object lblVersionValidation: TLabel
Left = 424
Top = 233
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = editVersion
WordWrap = True
end
object lblAuthorValidation: TLabel
Left = 424
Top = 153
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = editAuthor
WordWrap = True
end
object lblFullCopyrightValidation: TLabel
Left = 424
Top = 206
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = editFullCopyright
WordWrap = True
end
object lblLanguagesValidation: TLabel
Left = 424
Top = 284
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
WordWrap = True
end
object lblPathValidation: TLabel
Left = 424
Top = 403
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = editPath
WordWrap = True
end
object lblKeyboardIDValidation: TLabel
Left = 424
Top = 430
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = editKeyboardID
WordWrap = True
end
object lblProjectFilenameValidation: TLabel
Left = 424
Top = 457
Width = 250
Height = 26
AutoSize = False
Caption = '(validation)'
FocusControl = editProjectFilename
WordWrap = True
end
object lblDescriptionMarkdown: TLabel
Left = 120
Top = 123
Width = 197
Height = 13
Caption = 'Markdown accepted, no embedded HTML'
Transparent = True
end
object editKeyboardID: TEdit
Left = 120
Top = 427
Width = 293
Height = 21
TabOrder = 9
OnChange = editKeyboardIDChange
OnExit = ControlExit
end
object cmdBrowse: TButton
Left = 340
Top = 400
Width = 73
Height = 21
Caption = '&Browse...'
TabOrder = 8
OnClick = cmdBrowseClick
end
object editPath: TEdit
Left = 120
Top = 400
Width = 205
Height = 21
TabOrder = 7
OnChange = editPathChange
OnExit = ControlExit
end
object editKeyboardName: TEdit
Left = 120
Top = 8
Width = 293
Height = 21
TabOrder = 0
OnChange = editKeyboardNameChange
OnExit = ControlExit
end
object editCopyright: TEdit
Left = 120
Top = 176
Width = 293
Height = 21
TabOrder = 3
Text = 'Copyright '#169
OnChange = editCopyrightChange
OnExit = ControlExit
end
object editVersion: TEdit
Left = 120
Top = 230
Width = 293
Height = 21
TabOrder = 5
Text = '1.0.0'
OnChange = editVersionChange
OnExit = ControlExit
end
object editAuthor: TEdit
Left = 120
Top = 150
Width = 293
Height = 21
TabOrder = 2
OnChange = editAuthorChange
OnExit = ControlExit
end
object cmdOK: TButton
Left = 120
Top = 487
Width = 73
Height = 25
Caption = 'OK'
Default = True
TabOrder = 11
OnClick = cmdOKClick
end
object cmdCancel: TButton
Left = 199
Top = 487
Width = 73
Height = 25
Cancel = True
Caption = 'Cancel'
ModalResult = 2
TabOrder = 12
end
object editProjectFilename: TEdit
Left = 120
Top = 454
Width = 293
Height = 21
TabStop = False
ParentColor = True
ReadOnly = True
TabOrder = 10
end
object editFullCopyright: TEdit
Left = 120
Top = 203
Width = 293
Height = 21
TabOrder = 4
Text = 'Copyright '#169' YYYY'
OnChange = editFullCopyrightChange
OnExit = ControlExit
end
object memoDescription: TMemo
Left = 120
Top = 35
Width = 293
Height = 82
TabOrder = 1
OnChange = memoDescriptionChange
OnExit = ControlExit
end
object memoLanguages: TMemo
Left = 120
Top = 279
Width = 293
Height = 96
TabOrder = 6
OnChange = memoLanguagesChange
OnExit = ControlExit
end
end

View file

@ -19,12 +19,13 @@ uses
Browse4Folder,
Keyman.Developer.UI.FormValidation,
UfrmTike,
utilfiletypes;
type
TfrmNewLDMLKeyboardProjectParameters = class(TTikeForm)
lblFileName: TLabel;
lblKeyboardID: TLabel;
lblPath: TLabel;
editKeyboardID: TEdit;
cmdBrowse: TButton;
@ -42,13 +43,24 @@ type
lblKeyboardLanguages: TLabel;
lblProjectFilename: TLabel;
editProjectFilename: TEdit;
Label1: TLabel;
lblFullCopyright: TLabel;
editFullCopyright: TEdit;
Label2: TLabel;
lblDescription: TLabel;
memoDescription: TMemo;
memoLanguages: TMemo;
Label3: TLabel;
lblLanguages: TLabel;
Label4: TLabel;
lblKeyboardNameValidation: TLabel;
lblDescriptionValidation: TLabel;
lblCopyrightValidation: TLabel;
lblVersionValidation: TLabel;
lblAuthorValidation: TLabel;
lblFullCopyrightValidation: TLabel;
lblLanguagesValidation: TLabel;
lblPathValidation: TLabel;
lblKeyboardIDValidation: TLabel;
lblProjectFilenameValidation: TLabel;
lblDescriptionMarkdown: TLabel;
procedure cmdOKClick(Sender: TObject);
procedure editKeyboardNameChange(Sender: TObject);
procedure FormCreate(Sender: TObject);
@ -61,7 +73,10 @@ type
procedure editFullCopyrightChange(Sender: TObject);
procedure memoDescriptionChange(Sender: TObject);
procedure memoLanguagesChange(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure ControlExit(Sender: TObject);
private
FormValidation: TFormValidation;
dlgBrowse: TBrowse4Folder;
function GetAuthor: string;
function GetBasePath: string;
@ -71,13 +86,14 @@ type
function GetBCP47Tags: string;
function GetVersion: string;
function Validate: Boolean;
procedure EnableControls;
procedure EnableControls(ChangingControl: TControl);
procedure SetBCP47Tags(const Value: string);
procedure SetKeyboardID(const Value: string);
procedure SetKeyboardName(const Value: string);
procedure UpdateProjectFilename;
function GetFullCopyright: string;
function GetDescription: string;
procedure SetupValidation;
protected
function GetHelpTopic: string; override;
public
@ -182,6 +198,9 @@ end;
procedure TfrmNewLDMLKeyboardProjectParameters.FormCreate(Sender: TObject);
begin
inherited;
SetupValidation;
editPath.Text := FKeymanDeveloperOptions.DefaultProjectPath;
editFullCopyright.Text := 'Copyright '+Char($00A9 {copyright})+' '+FormatDateTime('yyyy', Now)+' ';
@ -191,9 +210,15 @@ begin
dlgBrowse.Root := Desktop;
dlgBrowse.Title := 'Select folder to save project to';
EnableControls;
EnableControls(nil);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.FormDestroy(Sender: TObject);
begin
inherited;
FreeAndNil(FormValidation);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.cmdBrowseClick(Sender: TObject);
begin
dlgBrowse.InitialDir := editPath.Text;
@ -204,51 +229,66 @@ end;
procedure TfrmNewLDMLKeyboardProjectParameters.cmdOKClick(Sender: TObject);
begin
FormValidation.TouchAllFields;
if Validate then
ModalResult := mrOk;
end;
procedure TfrmNewLDMLKeyboardProjectParameters.editAuthorChange(Sender: TObject);
begin
EnableControls;
if not editCopyright.Modified then
begin
editCopyright.Text := 'Copyright '+Char($00A9 {copyright})+' '+Author;
FormValidation.TouchField(editCopyright);
end;
if not editFullCopyright.Modified then
begin
editFullCopyright.Text := 'Copyright '+Char($00A9 {copyright})+' '+FormatDateTime('yyyy', Now)+' '+Author;
FormValidation.TouchField(editFullCopyright);
end;
EnableControls(editAuthor);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.editCopyrightChange(Sender: TObject);
begin
EnableControls;
EnableControls(editCopyright);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.editFullCopyrightChange(Sender: TObject);
begin
EnableControls;
EnableControls(editFullCopyright);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.editKeyboardIDChange(Sender: TObject);
begin
UpdateProjectFilename;
EnableControls;
EnableControls(editKeyboardID);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.editKeyboardNameChange(Sender: TObject);
begin
if not editKeyboardID.Modified then
begin
editKeyboardID.Text := TKeyboardUtils.CleanKeyboardID(Trim(editKeyboardName.Text));
EnableControls;
FormValidation.TouchField(editKeyboardID);
end;
EnableControls(editKeyboardName);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.ControlExit(Sender: TObject);
begin
EnableControls(Sender as TControl);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.editPathChange(Sender: TObject);
begin
UpdateProjectFilename;
EnableControls;
EnableControls(editPath);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.editVersionChange(Sender: TObject);
begin
EnableControls;
EnableControls(editVersion);
end;
function IsValidSemanticVersion(const s: string): Boolean;
@ -257,20 +297,6 @@ begin
Result := TRegEx.Create('^\d+\.\d+\.\d+$').IsMatch(s);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.EnableControls;
var
e: Boolean;
begin
e := (Trim(editKeyboardName.Text) <> '') and
(Trim(editPath.Text) <> '') and
TKeyboardUtils.IsValidKeyboardID(Trim(editKeyboardID.Text), True) and
IsValidSemanticVersion(Trim(editVersion.Text)) and
(Trim(memoDescription.Text) <> '') and
(Trim(memoLanguages.Text) <> '');
cmdOK.Enabled := e;
end;
function TfrmNewLDMLKeyboardProjectParameters.GetAuthor: string;
begin
Result := Trim(editAuthor.Text);
@ -327,6 +353,12 @@ function TfrmNewLDMLKeyboardProjectParameters.Validate: Boolean;
var
ProjectFolder: string;
begin
if not FormValidation.Update then
begin
ShowMessage('One or more fields are missing or invalid. Please correct these fields and try again.');
Exit(False);
end;
Result := TKeyboardUtils.IsValidKeyboardID(Trim(editKeyboardID.Text), True);
if Result then
@ -352,30 +384,30 @@ end;
procedure TfrmNewLDMLKeyboardProjectParameters.SetBCP47Tags(const Value: string);
begin
memoLanguages.Text := Value.Replace(' ', #13#10);
EnableControls;
EnableControls(nil);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.SetKeyboardID(const Value: string);
begin
editKeyboardID.Text := Value;
EnableControls;
EnableControls(nil);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.SetKeyboardName(const Value: string);
begin
editKeyboardName.Text := Value;
EnableControls;
EnableControls(nil);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.memoDescriptionChange(Sender: TObject);
begin
EnableControls;
EnableControls(memoDescription);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.memoLanguagesChange(
Sender: TObject);
begin
EnableControls;
EnableControls(memoLanguages);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.UpdateProjectFilename;
@ -389,4 +421,75 @@ begin
editProjectFilename.Perform(EM_SCROLLCARET, 0, 0);
end;
////
//// Validation
////
procedure TfrmNewLDMLKeyboardProjectParameters.SetupValidation;
begin
FormValidation := TFormValidation.Create;
FormValidation.Add(lblKeyboardName, lblKeyboardNameValidation, editKeyboardName);
FormValidation.Add(lblDescription, lblDescriptionValidation, memoDescription);
FormValidation.Add(lblAuthor, lblAuthorValidation, editAuthor);
FormValidation.Add(lblCoypright, lblCopyrightValidation, editCopyright);
FormValidation.Add(lblFullCopyright, lblFullCopyrightValidation, editFullCopyright);
FormValidation.Add(lblVersion, lblVersionValidation, editVersion);
FormValidation.Add(lblKeyboardLanguages, lblLanguagesValidation, memoLanguages);
FormValidation.Add(lblPath, lblPathValidation, editPath);
FormValidation.Add(lblKeyboardID, lblKeyboardIDValidation, editKeyboardID);
FormValidation.Add(lblProjectFilename, lblProjectFilenameValidation, editProjectFilename);
FormValidation.AddMethod(
editKeyboardName,
function: Boolean begin Result := Trim(editKeyboardName.Text) <> '' end,
'Keyboard name cannot be empty'
);
FormValidation.AddMethod(
editPath,
function: Boolean begin Result := (Trim(editPath.Text) <> '') end,
'Keyboard path cannot be empty'
);
FormValidation.AddMethod(
editKeyboardID,
function: Boolean begin Result := Trim(editKeyboardID.Text) <> '' end,
'Keyboard ID cannot be empty'
);
FormValidation.AddMethod(
editKeyboardID,
function: Boolean begin Result := TKeyboardUtils.IsValidKeyboardID(Trim(editKeyboardID.Text), True) end,
'Keyboard ID can include only a-z, 0-9, and _, and must not start with a digit'
);
FormValidation.AddMethod(
memoDescription,
function: Boolean begin Result := Trim(memoDescription.Text) <> '' end,
'Description cannot be empty'
);
FormValidation.AddMethod(
editVersion,
function: Boolean begin Result := IsValidSemanticVersion(Trim(editVersion.Text)) end,
'Version must follow a "1.2.3" semantic version format'
);
FormValidation.AddMethod(
memoLanguages,
function: Boolean begin Result := Trim(memoLanguages.Text) <> '' end,
'Languages list cannot be empty'
);
end;
procedure TfrmNewLDMLKeyboardProjectParameters.EnableControls(ChangingControl: TControl);
begin
if Assigned(ChangingControl) then
begin
FormValidation.TouchField(ChangingControl);
end;
FormValidation.Update;
end;
end.