From 947728f99eef051f7bfce5a64fa110eb72cae887 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sat, 17 Sep 2022 12:29:18 +0200 Subject: [PATCH 1/4] Upgraded dependencies --- I18N Commander/DataModel/DataModel.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/I18N Commander/DataModel/DataModel.csproj b/I18N Commander/DataModel/DataModel.csproj index 07d4dfb..2b1e1d6 100644 --- a/I18N Commander/DataModel/DataModel.csproj +++ b/I18N Commander/DataModel/DataModel.csproj @@ -8,12 +8,12 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 4173cdc761c9331d3b5c5e152834a394be2b526a Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sat, 17 Sep 2022 12:30:02 +0200 Subject: [PATCH 2/4] Added a DeepL facade --- I18N Commander/Processor/DeepL.cs | 66 +++++++++++++++++++++++ I18N Commander/Processor/Processor.csproj | 4 ++ 2 files changed, 70 insertions(+) create mode 100644 I18N Commander/Processor/DeepL.cs diff --git a/I18N Commander/Processor/DeepL.cs b/I18N Commander/Processor/DeepL.cs new file mode 100644 index 0000000..bbfe58e --- /dev/null +++ b/I18N Commander/Processor/DeepL.cs @@ -0,0 +1,66 @@ +using DataModel.Database; +using DeepL; + +namespace Processor; + +public static class DeepL +{ + private static bool DEEPL_NOT_AVAILABLE = false; + + public readonly record struct DeepLUsage(bool Enabled, long CharacterCount, long CharacterLimit, bool AuthIssue = false); + + public static async Task GetUsage() + { + if(DEEPL_NOT_AVAILABLE) + return new DeepLUsage(false, 0, 1); + + if (await AppSettings.GetDeepLMode() == SettingDeepLMode.DISABLED) + return new DeepLUsage(false, 0, 1); + + var deepLAPIKey = await AppSettings.GetDeepLAPIKey(); + if(string.IsNullOrWhiteSpace(deepLAPIKey)) + return new DeepLUsage(false, 0, 1); + + try + { + using var deepl = new Translator(deepLAPIKey); + var usage = await deepl.GetUsageAsync(); + + return new DeepLUsage(true, usage.Character!.Count, usage.Character.Limit); + } + catch (AuthorizationException e) + { + DEEPL_NOT_AVAILABLE = true; + return new DeepLUsage(false, 0, 1, true); + } + } + + public static async Task Translate(string text, string targetCulture) + { + if (DEEPL_NOT_AVAILABLE) + return string.Empty; + + if (await AppSettings.GetDeepLMode() == SettingDeepLMode.DISABLED) + return string.Empty; + + var deepLAPIKey = await AppSettings.GetDeepLAPIKey(); + if(string.IsNullOrWhiteSpace(deepLAPIKey)) + return string.Empty; + + try + { + var sourceCultureIndex = await AppSettings.GetDeepLSourceCultureIndex(); + var sourceCulture = await AppSettings.GetCultureCode(sourceCultureIndex); + + using var deepl = new Translator(deepLAPIKey); + var translation = await deepl.TranslateTextAsync(text, sourceCulture, targetCulture); + + return translation.Text; + } + catch (AuthorizationException e) + { + DEEPL_NOT_AVAILABLE = true; + return string.Empty; + } + } +} \ No newline at end of file diff --git a/I18N Commander/Processor/Processor.csproj b/I18N Commander/Processor/Processor.csproj index 94a5986..7b794fd 100644 --- a/I18N Commander/Processor/Processor.csproj +++ b/I18N Commander/Processor/Processor.csproj @@ -11,4 +11,8 @@ + + + + From 86b1f8348e28e566fc43f03abe9fc4e2db4f12de Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Sat, 17 Sep 2022 12:30:47 +0200 Subject: [PATCH 3/4] Added new icons --- .../UI WinForms/Resources/Icons.Designer.cs | 30 ++++++++++++++++++ .../UI WinForms/Resources/Icons.resx | 9 ++++++ .../Resources/icons8-increase-512.png | Bin 0 -> 2804 bytes .../Resources/icons8-refresh-512.png | Bin 0 -> 2669 bytes .../Resources/icons8-reload-512.png | Bin 0 -> 3129 bytes 5 files changed, 39 insertions(+) create mode 100644 I18N Commander/UI WinForms/Resources/icons8-increase-512.png create mode 100644 I18N Commander/UI WinForms/Resources/icons8-refresh-512.png create mode 100644 I18N Commander/UI WinForms/Resources/icons8-reload-512.png diff --git a/I18N Commander/UI WinForms/Resources/Icons.Designer.cs b/I18N Commander/UI WinForms/Resources/Icons.Designer.cs index ab02ede..eec4a58 100644 --- a/I18N Commander/UI WinForms/Resources/Icons.Designer.cs +++ b/I18N Commander/UI WinForms/Resources/Icons.Designer.cs @@ -170,6 +170,16 @@ namespace UI_WinForms.Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap icons8_increase_512 { + get { + object obj = ResourceManager.GetObject("icons8_increase_512", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -230,6 +240,26 @@ namespace UI_WinForms.Resources { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap icons8_refresh_512 { + get { + object obj = ResourceManager.GetObject("icons8_refresh_512", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap icons8_reload_512 { + get { + object obj = ResourceManager.GetObject("icons8_reload_512", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/I18N Commander/UI WinForms/Resources/Icons.resx b/I18N Commander/UI WinForms/Resources/Icons.resx index f4a76ae..ccb480d 100644 --- a/I18N Commander/UI WinForms/Resources/Icons.resx +++ b/I18N Commander/UI WinForms/Resources/Icons.resx @@ -151,6 +151,9 @@ icons8-document-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + icons8-increase-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + icons8-key-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -169,6 +172,12 @@ icons8-play-512 (2).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + icons8-refresh-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + icons8-reload-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + icons8-remove-tag-512.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff --git a/I18N Commander/UI WinForms/Resources/icons8-increase-512.png b/I18N Commander/UI WinForms/Resources/icons8-increase-512.png new file mode 100644 index 0000000000000000000000000000000000000000..e8cccca78a78fec43943e0c1296ad3043a65b300 GIT binary patch literal 2804 zcmai0dpwkR7at>RGigOgD$~PKX>P8~tWh#{x7|aMz zf(ix0I6M;Y@@yM`;;=}-R%p|#K)w564PHBh-t9`5bF(!`B5S!=oAg| zB*w~2DDpyd<1)fP3djqSgp&X(>wf@SIjn!KD}*AW6qWGhaiFa&=3V^fF%n>FfyK{5 z0bhg^sU~`Iq+p~!nZpHnVn}r^ig_^LE1)Akk}vXs+8QJQvwO|efvCi&d=>;*D#MtE z+#DS}MSM0V62ipZE}KzqPL4Ksf{hK@0y8TE6^#h_a@etCh6G|+;Go{b5zu&B8XiZ) z zt?ryhOgIRsef@0MkC9;&H}0>{?698&Z>J>u?TSKvvun`Rhh_+NZiqm}+!z9R(CiUG zLuRzh6JxVThrN#$?2NK7bZJj#39xf)0d(SYm+1V(>!$ms4CZk;z8o!Q|y7JrcUmZtx&h;eXY%$gbtt2qG$sX4wI z;7^U|tnN3>s>`JM33ZiGW4mHj_F%dLBQ<(#3tu^G)ofTp=vtY+pf!Kf#r0O(9q+}L zhi!bf;(?=tdj1(Adb-fPXQ%#o6;0=`b64}atDx7#LV;_57zRV?C>|A9?$Kq?>xJ${ zcA)vEyg2+Wg6;&>!?e8I^B~RKk78V`{$7X2D)Itqnl=vW8XY^e#_G+5(3H$SOaWJi zx7}(H-1c=&`$7{WcWT%9mesFht;x_TA1o~Eb2SPT=7l#7u--GCwA9(gZ0FSa4P)2u z>^)-nG;w;25Vq>ZCRI(VU)wJDey~x&YIVz8lAr(U@O8LRMEQB7F8US9Z*gG7QT?>r z?Z3AVEjwr+H=A7k(uGVPNlURn1T!Q^waKZUrbGoIXU5Ddn*{_r@Axw zeK6{+G4q#pJ-KX0e1A&4ep*oS8Ch_ME^bt<=yGNQEH7C<*)MEJvNp-xV+h$vlvCwA zmjv_bUL+YVMGUId6CM_*Iv$1}O;yX9g5P|kRy0b-YMIOK;Fe^DYE~N!s#FRlU1SdE zetU{AxGD0M%?EXv*-m&(<-U6_+EogBy~1RcnXUUq8&4)P(ES7$y5FV!A{jXUqw6&D zkDisWgTp#$vB+%wG~L5RI+;WbJIzUQTIvSGWJI|sy*TIDH@GLya!-QK)QXD5h20uc z@H?oIE_~kk=z@=U;IyGsqv`gML>1}c!Q;im2ZS5enQt_PR(4zrtf&*d%(s(P zxSj@`C~)H(L0WXk)>T7s@EXf+ZB?p#j$ZU>_miX1zD?2<@OYFe1!h=J6W-kK)O9ZP zml1o)q~9T29^9l_Hj0_hFzxuhftJ+udR)DvfmXUL0eD=c#%mm1fy;6$Nz%OB?K~8n z=0I5-v%!&>6JBtrN-dg+FemE`s_(nBME!<$LeOY`&EO2Z?j;>& zG8cT;_;D&lVbKoC4cBsIhp z6}QxDZSD_Q#W{<->poF3V^SU9{)*Wb>~5{ONVR~mhi9cd;^aa<(aQw%M&0F!=>8gS zk4Oh@ha~;Gy@Iq@!l~l7P=h#!EcI!246Jx*PC)#0pL~t4c3Svvw#C)St|mfy_5;nx zQcqhK$ehY`3yN22qO>zQkbZE4NH xFmdw+@O|Vl!Njs2L$&&Z{D#)$;f2d*G_3+CBdtm9dlY|G-JCqgr#FZE@F!I9PqhF5 literal 0 HcmV?d00001 diff --git a/I18N Commander/UI WinForms/Resources/icons8-refresh-512.png b/I18N Commander/UI WinForms/Resources/icons8-refresh-512.png new file mode 100644 index 0000000000000000000000000000000000000000..c496baeda2b57b771c8e629dda0a0e15c1a19492 GIT binary patch literal 2669 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 Date: Sat, 17 Sep 2022 12:31:12 +0200 Subject: [PATCH 4/4] Show the DeepL usage as part of the settings view --- .../UI WinForms/Components/Setting.cs | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/I18N Commander/UI WinForms/Components/Setting.cs b/I18N Commander/UI WinForms/Components/Setting.cs index 639487b..f9d7e2a 100644 --- a/I18N Commander/UI WinForms/Components/Setting.cs +++ b/I18N Commander/UI WinForms/Components/Setting.cs @@ -6,6 +6,8 @@ namespace UI_WinForms.Components; public sealed partial class Setting : UserControl { + private SettingUIData data; + public Setting() { this.InitializeComponent(); @@ -15,6 +17,7 @@ public sealed partial class Setting : UserControl { this.InitializeComponent(); this.Dock = DockStyle.Top; + this.data = settingMetaData; this.labelIcon.Image = settingMetaData.Icon; this.labelSettingName.Text = settingMetaData.SettingName(); this.labelExplanation.Text = settingMetaData.SettingExplanation(); @@ -38,6 +41,8 @@ public sealed partial class Setting : UserControl dataControl.Margin = new Padding(0, (int) margin, 0, (int)margin); }; } + + private void UpdateExplanation() => this.labelExplanation.Text = this.data.SettingExplanation(); private readonly record struct SettingUIData( Bitmap Icon, @@ -109,6 +114,85 @@ public sealed partial class Setting : UserControl return new Setting(settingData); } + private static async Task ShowDeepLUsageSettingAsync() + { + var currentUsage = await Processor.DeepL.GetUsage(); + var percent = currentUsage.Enabled ? currentUsage.CharacterCount / (float)currentUsage.CharacterLimit : 0; + + // Local function to show & update the explanation text: + string GetUsageText() => currentUsage.Enabled ? + $"You used {currentUsage.CharacterCount:###,###,###,##0} characters out of {currentUsage.CharacterLimit:###,###,###,##0} ({percent:P2})." : currentUsage.AuthIssue ? + "Was not able to authorize with DeepL. Please check your API key." : + "DeepL is disabled or the API key is not set."; + + var settingData = new SettingUIData( + Icon: Icons.icons8_increase_512, + SettingName: () => "DeepL Usage", + SettingExplanation: GetUsageText, + SetupDataControl: () => + { + var progressbar = new ProgressBar(); + progressbar.Maximum = 100; + progressbar.Margin = new Padding(0, 16, 0, 16); + progressbar.Dock = DockStyle.Fill; + progressbar.Style = ProgressBarStyle.Continuous; + progressbar.Value = percent switch + { + < 0 => 0, + > 1 => 100, + + _ => (int)(percent * 100) + }; + + var reloadButton = new Button(); + reloadButton.Text = string.Empty; + reloadButton.Image = Icons.icons8_reload_512; + reloadButton.FlatStyle = FlatStyle.Flat; + reloadButton.FlatAppearance.BorderSize = 0; + reloadButton.BackColor = Color.Empty; + reloadButton.UseVisualStyleBackColor = true; + reloadButton.Size = new Size(60, 60); + reloadButton.Click += async (sender, args) => + { + var usage = await Processor.DeepL.GetUsage(); + + // Update the outer variables: + percent = usage.Enabled ? usage.CharacterCount / (float)usage.CharacterLimit : 0; + currentUsage = usage; + + // Update the progress bar: + progressbar.Value = percent switch + { + < 0 => 0, + > 1 => 100, + + _ => (int)(percent * 100) + }; + + // Update the explanation text. Therefore, we need to get the setting object through the chain of parents: + var setting = (Setting) ((Control) sender).Parent.Parent.Parent; + setting.UpdateExplanation(); + }; + + // Setup the layout: + var layout = new TableLayoutPanel(); + layout.ColumnCount = 2; + layout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100)); + layout.ColumnStyles.Add(new ColumnStyle(SizeType.Absolute, 66)); + layout.RowCount = 1; + layout.RowStyles.Add(new RowStyle(SizeType.Percent, 100)); + layout.Controls.Add(progressbar, 0, 0); + layout.Controls.Add(reloadButton, 1, 0); + layout.Dock = DockStyle.Fill; + + return layout; + } + ); + + var setting = new Setting(settingData); + return setting; + } + private static async Task ShowDeepLActionSettingAsync() { var currentSetting = await AppSettings.GetDeepLAction(); @@ -264,7 +348,8 @@ public sealed partial class Setting : UserControl { yield return setting; } - + + yield return ShowDeepLUsageSettingAsync(); yield return ShowDeepLActionSettingAsync(); yield return ShowDeepLAPIKeySettingAsync(); yield return ShowDeepLModeSettingAsync();