feat(developer): check for duplicated language codes in package editor and compiler

Fixes #8119.
This commit is contained in:
Marc Durdin 2023-02-02 15:06:15 +07:00
parent a040a2bb6b
commit 8ee8325c74
3 changed files with 95 additions and 44 deletions

View file

@ -337,6 +337,8 @@ type
procedure SaveJSON(ARoot: TJSONObject); virtual;
procedure LoadXML(ARoot: IXMLNode); virtual;
procedure SaveXML(ARoot: IXMLNode); virtual;
function ContainsID(const id: string): Boolean;
function IndexOfID(const id: string): Integer;
end;
TPackageLexicalModel = class(TPackageBaseObject)
@ -2262,6 +2264,21 @@ end;
{ TPackageKeyboardLanguageList }
function TPackageKeyboardLanguageList.ContainsID(const id: string): Boolean;
begin
Result := IndexOfID(id) >= 0;
end;
function TPackageKeyboardLanguageList.IndexOfID(const id: string): Integer;
var
i: Integer;
begin
for i := 0 to Count - 1 do
if SameText(Items[i].ID, id) then
Exit(i);
Result := -1;
end;
procedure TPackageKeyboardLanguageList.LoadJSON(ARoot: TJSONObject);
var
j: Integer;

View file

@ -27,7 +27,9 @@ unit CompilePackage;
interface
uses
kpsfile, kmpinffile, PackageInfo,
kpsfile,
kmpinffile,
PackageInfo,
Keyman.Developer.System.Project.ProjectLog;
function DoCompilePackage(pack: TKPSFile; AMessageEvent: TCompilePackageMessageEvent; ASilent, ACheckFilenameConventions: Boolean; const AOutputFileName: string): Boolean; // I4688
@ -37,6 +39,7 @@ implementation
uses
Winapi.Windows,
System.Classes,
System.Generics.Collections,
System.SysUtils,
System.IniFiles,
System.Zip,
@ -85,6 +88,7 @@ type
procedure CheckKeyboardLanguages;
procedure CheckFilenameConventions;
function CheckLexicalModels: Boolean;
procedure CheckForDuplicatedLanguages(const resourceType, id: string; languages: TPackageKeyboardLanguageList);
end;
function DoCompilePackage(pack: TKPSFile; AMessageEvent: TCompilePackageMessageEvent; ASilent, ACheckFilenameConventions: Boolean; const AOutputFileName: string): Boolean; // I4688
@ -141,6 +145,8 @@ begin
end;
function TCompilePackage.CheckLexicalModels: Boolean;
var
model: TPackageLexicalModel;
begin
if pack.LexicalModels.Count > 0 then
begin
@ -151,6 +157,12 @@ begin
end;
end;
for model in pack.LexicalModels do
begin
CheckForDuplicatedLanguages('model', model.id, model.Languages);
end;
Exit(True);
end;
@ -487,6 +499,7 @@ end;
const
SKKeyboardPackageLanguageNonCanonical = 'The keyboard %0:s has a non-canonical language tag "%1:s" (%2:s), should be "%3:s".';
SKKeyboardShouldHaveAtLeastOneLanguage = 'The keyboard %0:s has no language tags. It should have at least one language tag.';
SKPackageShouldNotRepeatLanguages = 'The %0:s %1:s has a repeated language "%2:s".';
procedure TCompilePackage.CheckKeyboardLanguages;
var
@ -496,6 +509,30 @@ begin
begin
if k.Languages.Count = 0 then
WriteMessage(plsWarning, Format(SKKeyboardShouldHaveAtLeastOneLanguage, [k.ID]));
CheckForDuplicatedLanguages('keyboard', k.ID, k.Languages);
end;
end;
procedure TCompilePackage.CheckForDuplicatedLanguages(const resourceType, id: string; languages: TPackageKeyboardLanguageList);
var
tags: TDictionary<string,Integer>;
lang: TPackageKeyboardLanguage;
begin
tags := TDictionary<string,Integer>.Create;
try
for lang in languages do
begin
if tags.ContainsKey(lang.ID.ToLower) then
begin
WriteMessage(plsWarning, Format(SKPackageShouldNotRepeatLanguages, [resourceType, id, lang.ID]));
end
else
begin
tags.Add(lang.ID.ToLower, 0);
end;
end;
finally
tags.Free;
end;
end;

View file

@ -314,8 +314,7 @@ type
procedure EnableLexicalModelTabControls;
procedure ShowEditLanguageForm(grid: TStringGrid;
langs: TPackageKeyboardLanguageList; lang: TPackageKeyboardLanguage);
function ShowAddLanguageForm(grid: TStringGrid;
langs: TPackageKeyboardLanguageList): Boolean;
procedure ShowAddLanguageForm(grid: TStringGrid; langs: TPackageKeyboardLanguageList);
procedure RefreshLexicalModelList;
procedure UpdateQRCode;
@ -1624,6 +1623,8 @@ procedure TfrmPackageEditor.EnableControls;
begin
EnableStartMenuControls;
EnableDetailsTabControls;
EnableKeyboardTabControls;
EnableLexicalModelTabControls;
EnableCompileTabControls;
end;
@ -1686,35 +1687,16 @@ end;
procedure TfrmPackageEditor.cmdKeyboardAddLanguageClick(Sender: TObject);
var
k: TPackageKeyboard;
lang: TPackageKeyboardLanguage;
frm: TfrmSelectBCP47Language;
begin
k := SelectedKeyboard;
Assert(Assigned(k));
frm := TfrmSelectBCP47Language.Create(Application.MainForm);
try
if frm.ShowModal = mrOk then
begin
lang := TPackageKeyboardLanguage.Create(pack);
lang.ID := frm.LanguageID;
lang.Name := frm.LanguageName;
k.Languages.Add(lang);
RefreshKeyboardLanguageList(k);
gridKeyboardLanguages.Row := gridKeyboardLanguages.RowCount - 1;
gridKeyboardLanguagesClick(gridKeyboardLanguages);
Modified := True;
end;
finally
frm.Free;
end;
ShowAddLanguageForm(gridKeyboardLanguages, k.Languages);
end;
procedure TfrmPackageEditor.cmdKeyboardEditLanguageClick(Sender: TObject);
var
k: TPackageKeyboard;
lang: TPackageKeyboardLanguage;
frm: TfrmSelectBCP47Language;
begin
k := SelectedKeyboard;
Assert(Assigned(k));
@ -1722,20 +1704,7 @@ begin
lang := SelectedKeyboardLanguage;
Assert(Assigned(lang));
frm := TfrmSelectBCP47Language.Create(Application.MainForm);
try
frm.LanguageID := lang.ID;
frm.LanguageName := lang.Name;
if frm.ShowModal = mrOk then
begin
lang.ID := frm.LanguageID;
lang.Name := frm.LanguageName;
RefreshKeyboardLanguageList(k);
Modified := True;
end;
finally
frm.Free;
end;
ShowEditLanguageForm(gridKeyboardLanguages, k.Languages, lang);
end;
procedure TfrmPackageEditor.cmdKeyboardRemoveLanguageClick(Sender: TObject);
@ -1819,16 +1788,25 @@ begin
end;
end;
function TfrmPackageEditor.ShowAddLanguageForm(grid: TStringGrid; langs: TPackageKeyboardLanguageList): Boolean;
procedure TfrmPackageEditor.ShowAddLanguageForm(grid: TStringGrid; langs: TPackageKeyboardLanguageList);
var
lang: TPackageKeyboardLanguage;
frm: TfrmSelectBCP47Language;
n: Integer;
begin
Result := False;
frm := TfrmSelectBCP47Language.Create(Application.MainForm);
try
if frm.ShowModal = mrOk then
begin
n := langs.IndexOfID(frm.LanguageID);
if n >= 0 then
begin
// Duplicate - we won't re-add the item, just select the existing item
grid.Row := n + 1;
EnableControls;
Exit;
end;
lang := TPackageKeyboardLanguage.Create(pack);
lang.ID := frm.LanguageID;
lang.Name := frm.LanguageName;
@ -1836,7 +1814,7 @@ begin
RefreshLanguageList(grid, langs);
grid.Row := grid.RowCount - 1;
Modified := True;
Result := True;
EnableControls;
end;
finally
frm.Free;
@ -1846,6 +1824,7 @@ end;
procedure TfrmPackageEditor.ShowEditLanguageForm(grid: TStringGrid; langs: TPackageKeyboardLanguageList; lang: TPackageKeyboardLanguage);
var
frm: TfrmSelectBCP47Language;
n: Integer;
begin
frm := TfrmSelectBCP47Language.Create(Application.MainForm);
try
@ -1853,9 +1832,30 @@ begin
frm.LanguageName := lang.Name;
if frm.ShowModal = mrOk then
begin
if not SameText(frm.LanguageID, lang.ID) then
begin
// If the id has changed, check for duplicates
n := langs.IndexOfID(frm.LanguageID);
if n >= 0 then
begin
// Duplicate - we will delete the edited one and select the existing
// one
langs.Remove(lang);
RefreshLanguageList(grid, langs);
// The index may have changed, search again
n := langs.IndexOfID(frm.LanguageID);
grid.Row := n + 1;
EnableControls;
Modified := True;
Exit;
end;
end;
lang.ID := frm.LanguageID;
lang.Name := frm.LanguageName;
RefreshLanguageList(grid, langs);
EnableControls;
Modified := True;
end;
finally
@ -2005,10 +2005,7 @@ var
begin
lm := SelectedLexicalModel;
Assert(Assigned(lm));
if ShowAddLanguageForm(gridLexicalModelLanguages, lm.Languages) then
gridLexicalModelLanguagesClick(gridLexicalModelLanguages);
EnableLexicalModelTabControls;
ShowAddLanguageForm(gridLexicalModelLanguages, lm.Languages);
end;
procedure TfrmPackageEditor.cmdLexicalModelLanguageEditClick(Sender: TObject);