Skip to content

Commit

Permalink
Merge pull request stakira#1107 from maiko3tattun/0421_TranslateError…
Browse files Browse the repository at this point in the history
…message

Improved translation of error messages for more flexibility
  • Loading branch information
stakira authored Apr 20, 2024
2 parents 2dabd4a + 89c1494 commit e3915b5
Show file tree
Hide file tree
Showing 17 changed files with 199 additions and 87 deletions.
3 changes: 2 additions & 1 deletion OpenUtau.Core/Classic/Frq.cs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ public bool Load(string wavPath) {
}
return true;
} catch (Exception e) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.load", ": frq file", e));
var customEx = new MessageCustomizableException("Failed to load frq file", "<translate:errors.failed.load>: frq file", e);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
return false;
}
}
Expand Down
24 changes: 10 additions & 14 deletions OpenUtau.Core/Commands/Notifications.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,17 @@ public ErrorMessageNotification(string message, Exception e) {
this.message = message;
this.e = e;
}
public override string ToString() => $"Error message: {message} {e}";
}

public class ErrorMessageNotificationWithTranslation : ErrorMessageNotification {
public readonly string stringKey = string.Empty;
public ErrorMessageNotificationWithTranslation(string stringKey) : base(string.Empty) {
this.stringKey = stringKey;
}
public ErrorMessageNotificationWithTranslation(string stringKey, Exception e) : base(e) {
this.stringKey = stringKey;
}
public ErrorMessageNotificationWithTranslation(string stringKey, string additionalMessage, Exception e) : base(additionalMessage, e) {
this.stringKey = stringKey;
public override string ToString() {
if (e is MessageCustomizableException mce) {
if (string.IsNullOrWhiteSpace(mce.Message)) {
return $"Error message: {mce.SubstanceException.Message} {mce.SubstanceException}";
} else {
return $"Error message: {mce.Message} {mce.SubstanceException}";
}
} else {
return $"Error message: {message} {e}";
}
}
public override string ToString() => $"Error message: {stringKey}{message} {e}";
}

public class LoadingNotification : UNotification {
Expand Down
2 changes: 1 addition & 1 deletion OpenUtau.Core/DiffSinger/DiffSingerVocoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public DsVocoder(string name) {
model = File.ReadAllBytes(Path.Combine(Location, config.model));
}
catch (Exception ex) {
throw new Exception($"Error loading vocoder {name}. Please download vocoder from https://github.com/xunmengshe/OpenUtau/wiki/Vocoders");
throw new MessageCustomizableException($"Error loading vocoder {name}", $"<translate:errors.diffsinger.downloadvocoder1>{name}<translate:errors.diffsinger.downloadvocoder2>https://github.com/xunmengshe/OpenUtau/wiki/Vocoders", new Exception($"Error loading vocoder {name}"));
}
session = Onnx.getInferenceSession(model);
}
Expand Down
15 changes: 10 additions & 5 deletions OpenUtau.Core/PlaybackManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ private void Render(UProject project, int tick, int endTick, int trackNo) {
} catch (Exception e) {
Log.Error(e, "Failed to render.");
StopPlayback();
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.render", e));
var customEx = new MessageCustomizableException("Failed to render.", "<translate:errors.failed.render>", e);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
}
});
}
Expand Down Expand Up @@ -161,10 +162,12 @@ await Task.Run(() => {
WaveFileWriter.CreateWaveFile16(exportPath, new ExportAdapter(projectMix).ToMono(1, 0));
DocManager.Inst.ExecuteCmd(new ProgressBarNotification(0, $"Exported to {exportPath}."));
} catch (IOException ioe) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.export", $": {exportPath}", ioe));
var customEx = new MessageCustomizableException($"Failed to export {exportPath}.", $"<translate:errors.failed.export>: {exportPath}", ioe);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
DocManager.Inst.ExecuteCmd(new ProgressBarNotification(0, $"Failed to export {exportPath}."));
} catch (Exception e) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.render", e));
var customEx = new MessageCustomizableException("Failed to render.", $"<translate:errors.failed.render>: {exportPath}", e);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
DocManager.Inst.ExecuteCmd(new ProgressBarNotification(0, $"Failed to render."));
}
});
Expand All @@ -189,10 +192,12 @@ await Task.Run(() => {
DocManager.Inst.ExecuteCmd(new ProgressBarNotification(0, $"Exported to {file}."));
}
} catch (IOException ioe) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.export", $": {file}", ioe));
var customEx = new MessageCustomizableException($"Failed to export {file}.", $"<translate:errors.failed.export>: {file}", ioe);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
DocManager.Inst.ExecuteCmd(new ProgressBarNotification(0, $"Failed to export {file}."));
} catch (Exception e) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.render", e));
var customEx = new MessageCustomizableException("Failed to render.", "<translate:errors.failed.render>", e);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
DocManager.Inst.ExecuteCmd(new ProgressBarNotification(0, $"Failed to render."));
}
});
Expand Down
3 changes: 2 additions & 1 deletion OpenUtau.Core/Render/RenderEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ public Tuple<WaveMix, List<Fader>> RenderMixdown(TaskScheduler uiScheduler, ref
if (task.IsFaulted && !wait) {
Log.Error(task.Exception.Flatten(), "Failed to render.");
PlaybackManager.Inst.StopPlayback();
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.render", task.Exception));
var customEx = new MessageCustomizableException("Failed to render.", "<translate:errors.failed.render>", task.Exception);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
}
}, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, uiScheduler);
if (wait) {
Expand Down
41 changes: 41 additions & 0 deletions OpenUtau.Core/Util/MessageCustomizableException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System;

namespace OpenUtau.Core {
public class MessageCustomizableException : Exception {

public override string Message { get; } = string.Empty;
public string TranslatableMessage { get; set; } = string.Empty;
public Exception SubstanceException { get; }
public bool ShowStackTrace { get; } = true;

/// <summary>
/// This allows the use of translatable messages and the hiding of stack traces in the message box.
/// <summary>
/// <paramref name="message">untranslated message</paramref>
/// <paramref name="translatableMessage">By enclosing the resource key with a tag like "<translate:key>", only that part will be translated.</paramref>
/// <paramref name="e">underlying exception</paramref>
public MessageCustomizableException(string message, string translatableMessage, Exception e) {
Message = message;
TranslatableMessage = translatableMessage;
SubstanceException = e;
}

/// <summary>
/// This allows the use of translatable messages and the hiding of stack traces in the message box.
/// <summary>
/// <paramref name="message">untranslated message</paramref>
/// <paramref name="translatableMessage">By enclosing the resource key with a tag like "<translate:key>", only that part will be translated.</paramref>
/// <paramref name="e">underlying exception</paramref>
/// <paramref name="showStackTrace">Can be omitted. Default is true.</paramref>
public MessageCustomizableException(string message, string translatableMessage, Exception e, bool showStackTrace) {
Message = message;
TranslatableMessage = translatableMessage;
SubstanceException = e;
ShowStackTrace = showStackTrace;
}

public override string ToString() {
return SubstanceException.ToString();
}
}
}
22 changes: 18 additions & 4 deletions OpenUtau/Strings/Strings.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,27 @@

<system:String x:Key="errors.caption">Error</system:String>
<system:String x:Key="errors.details">Error Details</system:String>
<system:String x:Key="errors.diffsinger.downloadvocoder1">Error loading vocoder </system:String>
<system:String x:Key="errors.diffsinger.downloadvocoder2">. Please download vocoder from </system:String>
<system:String x:Key="errors.expression.abbrlong">Abbreviation must be between 1 and 4 characters long</system:String>
<system:String x:Key="errors.expression.abbrset">Abbreviation must be set</system:String>
<system:String x:Key="errors.expression.abbrunique">Abbreviations must be unique</system:String>
<system:String x:Key="errors.expression.default">Default value must be between min and max</system:String>
<system:String x:Key="errors.expression.flagunique">Flags must be unique</system:String>
<system:String x:Key="errors.expression.min">Min must be smaller than max</system:String>
<system:String x:Key="errors.expression.name">Name must be set</system:String>
<system:String x:Key="errors.failed.export">Failed to export</system:String>
<system:String x:Key="errors.failed.importfiles">Failed to import files</system:String>
<system:String x:Key="errors.failed.importaudio">Failed to import audio</system:String>
<system:String x:Key="errors.failed.importmidi">Failed to import midi</system:String>
<system:String x:Key="errors.failed.load">Failed to load</system:String>
<system:String x:Key="errors.failed.open">Failed to open</system:String>
<system:String x:Key="errors.failed.render">Failed to render.</system:String>
<system:String x:Key="errors.failed.runeditingmacro">Failed to run editing macro.</system:String>
<system:String x:Key="errors.failed.loadprefs">Failed to load prefs. Initialize it.</system:String>
<system:String x:Key="errors.failed.openfile">Failed to open</system:String>
<system:String x:Key="errors.failed.openlocation">Failed to open location</system:String>
<system:String x:Key="errors.failed.render">Failed to render</system:String>
<system:String x:Key="errors.failed.runeditingmacro">Failed to run editing macro</system:String>
<system:String x:Key="errors.failed.save">Failed to save</system:String>
<system:String x:Key="errors.failed.savesingerconfig">Failed to save singer config file.</system:String>
<system:String x:Key="errors.failed.savesingerconfig">Failed to save singer config file</system:String>

<system:String x:Key="exps.abbr">Abbreviation</system:String>
<system:String x:Key="exps.apply">Apply</system:String>
Expand Down
22 changes: 18 additions & 4 deletions OpenUtau/Strings/Strings.ja-JP.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,27 @@

<system:String x:Key="errors.caption">エラー</system:String>
<system:String x:Key="errors.details">エラーの詳細</system:String>
<system:String x:Key="errors.diffsinger.downloadvocoder1">ボコーダー </system:String>
<system:String x:Key="errors.diffsinger.downloadvocoder2"> のロードに失敗しました。未インストールの場合、以下のURLからダウンロードしてください: </system:String>
<system:String x:Key="errors.expression.abbrlong">パラメータの略称は1~4文字で入力してください</system:String>
<system:String x:Key="errors.expression.abbrset">パラメータの略称を入力してください</system:String>
<system:String x:Key="errors.expression.abbrunique">パラメータの略称が重複しています</system:String>
<system:String x:Key="errors.expression.default">デフォルト値は最小値以上、最大値以下にしてください</system:String>
<system:String x:Key="errors.expression.flagunique">フラグが重複しています</system:String>
<system:String x:Key="errors.expression.min">最小値は最大値より小さくしてください</system:String>
<system:String x:Key="errors.expression.name">表情名を入力してください</system:String>
<system:String x:Key="errors.failed.export">エクスポートに失敗しました</system:String>
<system:String x:Key="errors.failed.importfiles">ファイルのインポートに失敗しました</system:String>
<system:String x:Key="errors.failed.importaudio">オーディオのインポートに失敗しました</system:String>
<system:String x:Key="errors.failed.importmidi">MIDIのインポートに失敗しました</system:String>
<system:String x:Key="errors.failed.load">読み込みに失敗しました</system:String>
<system:String x:Key="errors.failed.open">読み込みに失敗しました</system:String>
<system:String x:Key="errors.failed.render">レンダリングに失敗しました。</system:String>
<system:String x:Key="errors.failed.runeditingmacro">一括処理に失敗しました。</system:String>
<system:String x:Key="errors.failed.loadprefs">環境設定の読み込みに失敗しました。設定を初期化します。</system:String>
<system:String x:Key="errors.failed.openfile">読み込みに失敗しました</system:String>
<system:String x:Key="errors.failed.openlocation">フォルダを開けませんでした</system:String>
<system:String x:Key="errors.failed.render">レンダリングに失敗しました</system:String>
<system:String x:Key="errors.failed.runeditingmacro">一括処理に失敗しました</system:String>
<system:String x:Key="errors.failed.save">保存に失敗しました</system:String>
<system:String x:Key="errors.failed.savesingerconfig">シンガー設定の保存に失敗しました</system:String>
<system:String x:Key="errors.failed.savesingerconfig">シンガー設定の保存に失敗しました</system:String>

<system:String x:Key="exps.abbr">パラメータの略称</system:String>
<system:String x:Key="exps.apply">適用</system:String>
Expand Down
6 changes: 4 additions & 2 deletions OpenUtau/ViewModels/EditSubbanksViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ public void LoadSubbanks() {
}
SelectedColor = Colors[0];
} catch (Exception e) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.load", ": subbanks", e));
var customEx = new MessageCustomizableException("Failed to load subbanks", "<translate:errors.failed.load>: subbanks", e);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
}
}

Expand Down Expand Up @@ -184,7 +185,8 @@ public void SaveSubbanks() {
bankConfig.Save(stream);
}
} catch (Exception e) {
DocManager.Inst.ExecuteCmd(new ErrorMessageNotificationWithTranslation("errors.failed.save", ": subbanks", e));
var customEx = new MessageCustomizableException("Failed to save subbanks", "<translate:errors.failed.save>: subbanks", e);
DocManager.Inst.ExecuteCmd(new ErrorMessageNotification(customEx));
}
LoadSubbanks();
}
Expand Down
27 changes: 14 additions & 13 deletions OpenUtau/ViewModels/ExpressionsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,22 @@ public ExpressionBuilder(string name, string abbr, float min, float max, bool is
.ToProperty(this, x => x.SelectedType, out selectedType);
}

public string? Validate() {
public string[]? Validate() {
if (string.IsNullOrWhiteSpace(Name)) {
return "Name must be set.";
return new string[] { "Name must be set.", "<translate:errors.expression.name>" };
}
if (string.IsNullOrWhiteSpace(Abbr)) {
return "Abbreviation must be set.";
return new string[] { "Abbreviation must be set.", "<translate:errors.expression.abbrset>" };
}
if (ExpressionType == UExpressionType.Numerical) {
if (Abbr.Trim().Length < 1 || Abbr.Trim().Length > 4) {
return "Abbreviation must be between 1 and 4 characters long.";
return new string[] { "Abbreviation must be between 1 and 4 characters long.", "<translate:errors.expression.abbrlong>" };
}
if (Min >= Max) {
return "Min must be smaller than max.";
return new string[] { "Min must be smaller than max.", "<translate:errors.expression.min>" };
}
if (DefaultValue < Min || DefaultValue > Max) {
return "Default value must be between min and max.";
return new string[] { "Default value must be between min and max.", "<translate:errors.expression.default>" };
}
}
return null;
Expand Down Expand Up @@ -137,15 +137,16 @@ public void Apply() {
if (!Expressions.All(builder => builder.Validate() == null)) {
var invalid = Expressions.First(builder => builder.Validate() != null);
Expression = invalid;
throw new ArgumentException(invalid.Validate());
string[] validate = invalid.Validate()!;
throw new MessageCustomizableException(validate[0], validate[1], new ArgumentException(validate[0]), false);
}
var abbrs = Expressions.Select(builder => builder.Abbr);
if (abbrs.Count() != abbrs.Distinct().Count()) {
throw new ArgumentException("Abbreviations must be unique.");
var abbrs = Expressions.GroupBy(builder => builder.Abbr).Where(g => g.Count() > 1).Select(g => g.Key);
if (abbrs.Count() > 0) {
throw new MessageCustomizableException("", $"<translate:errors.expression.abbrunique>: {string.Join(", ", abbrs)}", new ArgumentException($"Abbreviations must be unique: {string.Join(", ", abbrs)}"), false);
}
var flags = Expressions.Where(builder => !string.IsNullOrEmpty(builder.Flag)).Select(builder => builder.Flag);
if (flags.Count() != flags.Distinct().Count()) {
throw new ArgumentException("Flags must be unique.");
var flags = Expressions.Where(builder => !string.IsNullOrEmpty(builder.Flag)).GroupBy(builder => builder.Flag).Where(g => g.Count() > 1).Select(g => g.Key);
if (flags.Count() > 0) {
throw new MessageCustomizableException("", $"<translate:errors.expression.flagunique>: {string.Join(", ", flags)}", new ArgumentException($"Flags must be unique: {string.Join(", ", flags)}"), false);
}
DocManager.Inst.StartUndoGroup();
DocManager.Inst.ExecuteCmd(new ConfigureExpressionsCommand(DocManager.Inst.Project, Expressions.Select(builder => builder.Build()).ToArray()));
Expand Down
Loading

0 comments on commit e3915b5

Please sign in to comment.