diff --git a/AvaloniaApplication1/AvaloniaApplication1.csproj b/AvaloniaApplication1/AvaloniaApplication1.csproj index 6820ad7..0ece434 100644 --- a/AvaloniaApplication1/AvaloniaApplication1.csproj +++ b/AvaloniaApplication1/AvaloniaApplication1.csproj @@ -9,8 +9,8 @@ OpusCatMtEngineCore OpusCatMtEngine AnyCPU - Debug;Release;DebugWsl;DebugMacos - 1.3.0.0 + Debug;Release;DebugWsl;DebugMacos;ReleaseLinux;ReleaseMacos + 1.0.0.0 4 @@ -22,11 +22,20 @@ anycpu $(DefineConstants);LINUX + + 4 + anycpu + $(DefineConstants);LINUX + $(DefineConstants);MACOS + + $(DefineConstants);MACOS + + @@ -2763,6 +2772,7 @@ + diff --git a/AvaloniaApplication1/AvaloniaApplication1.csproj.user b/AvaloniaApplication1/AvaloniaApplication1.csproj.user index 75a8667..4f1b814 100644 --- a/AvaloniaApplication1/AvaloniaApplication1.csproj.user +++ b/AvaloniaApplication1/AvaloniaApplication1.csproj.user @@ -6,6 +6,9 @@ ProjectDebugger + + ProjectDebugger + AvaloniaApplication1 diff --git a/AvaloniaApplication1/IsoLanguage.cs b/AvaloniaApplication1/IsoLanguage.cs index e0cbc74..01a4bba 100644 --- a/AvaloniaApplication1/IsoLanguage.cs +++ b/AvaloniaApplication1/IsoLanguage.cs @@ -2,6 +2,7 @@ using Serilog; using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -60,6 +61,27 @@ private static void ParseIso639_3() } } + private static void ParseIso639_3MacroMappings() + { + var embeddedProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly(), ""); + using (var isoTable = new StreamReader(embeddedProvider.GetFileInfo("OpusCatMtEngine.iso-639-3-macrolanguages.tab").CreateReadStream())) + { + + //Skip header + isoTable.ReadLine(); + + string line; + while ((line = isoTable.ReadLine()) != null) + { + var split = line.Split('\t'); + var iso639_3_macro = split[0]; + var iso639_3_micro = split[1]; + IsoLanguage.Iso639_3MacroMappings[iso639_3_micro] = iso639_3_macro; + + } + } + } + private static void ParseIso639_5() { var embeddedProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly(), ""); @@ -85,12 +107,14 @@ static IsoLanguage() { IsoLanguage.ParseIso639_3(); IsoLanguage.ParseIso639_5(); + IsoLanguage.ParseIso639_3MacroMappings(); } private static Dictionary Iso639_3To639_1 = new Dictionary(); private static Dictionary Iso639_1To639_3 = new Dictionary(); private static Dictionary Iso639_2BTo639_3 = new Dictionary(); private static Dictionary Iso639_3ToRefName = new Dictionary(); + private static Dictionary Iso639_3MacroMappings = new Dictionary(); private static Dictionary Iso639_5ToRefName = new Dictionary(); public string Iso639_5Code { get; set; } @@ -130,6 +154,33 @@ public string ShortestIsoCode public string Iso15924Script { get; set; } public string IsoRefName { get; } public string OriginalCode { get; } + public bool IsRightToLeft + { + get + { + List CultureInfos = CultureInfo + .GetCultures(CultureTypes.SpecificCultures) + .ToList(); + + foreach (CultureInfo cultureInfo in CultureInfos) + { + if (cultureInfo.TwoLetterISOLanguageName == this.Iso639_1Code || + cultureInfo.ThreeLetterISOLanguageName == this.Iso639_3Code) + { + return cultureInfo.TextInfo.IsRightToLeft; + } + else if (IsoLanguage.Iso639_3MacroMappings.ContainsKey(this.Iso639_3Code)) + { + if (cultureInfo.ThreeLetterISOLanguageName == IsoLanguage.Iso639_3MacroMappings[this.Iso639_3Code]) + { + return cultureInfo.TextInfo.IsRightToLeft; + } + } + } + + return false; + } + } //This constructor parses the code. //The language code may be from a MT model, Opus MT models generally have ISO-639-1 codes if possible, diff --git a/AvaloniaApplication1/MTModel.cs b/AvaloniaApplication1/MTModel.cs index 10eb3e7..39954f2 100644 --- a/AvaloniaApplication1/MTModel.cs +++ b/AvaloniaApplication1/MTModel.cs @@ -646,7 +646,8 @@ public List SourceLanguages get => sourceLanguages; set { - sourceLanguages = value; + var sortedLangs = value.OrderBy(x => x.IsoRefName); + sourceLanguages = sortedLangs.ToList(); NotifyPropertyChanged("SourceLanguageString"); } } @@ -656,7 +657,9 @@ public List TargetLanguages get => targetLanguages; set { - targetLanguages = value; + var sortedLangs = value.OrderBy(x => x.IsoRefName); + targetLanguages = sortedLangs.ToList(); + NotifyPropertyChanged("TargetLanguageString"); } } diff --git a/AvaloniaApplication1/Marian/MarianProcess.cs b/AvaloniaApplication1/Marian/MarianProcess.cs index c0f5042..92e267f 100644 --- a/AvaloniaApplication1/Marian/MarianProcess.cs +++ b/AvaloniaApplication1/Marian/MarianProcess.cs @@ -106,8 +106,8 @@ public MarianProcess( { this.preprocessor = new MosesBpePreprocessor( - $"{this.modelDir}\\source.tcmodel", - $"{this.modelDir}\\source.bpe", + Path.Combine(this.modelDir,"source.tcmodel"), + Path.Combine(this.modelDir,"source.bpe"), this.SourceCode, this.TargetCode); this.segmentation = SegmentationMethod.Bpe; diff --git a/AvaloniaApplication1/OWIN/OwinMtService.cs b/AvaloniaApplication1/OWIN/OwinMtService.cs index 35d5306..8406a49 100644 --- a/AvaloniaApplication1/OWIN/OwinMtService.cs +++ b/AvaloniaApplication1/OWIN/OwinMtService.cs @@ -12,6 +12,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.DependencyInjection; +using LiveChartsCore; namespace OpusCatMtEngine { @@ -24,26 +25,31 @@ public OwinMtService(ModelManager modelManager) if (OpusCatMtEngineSettings.Default.AllowRemoteUse) { baseAddress = $"http://+:{OpusCatMtEngineSettings.Default.HttpMtServicePort}"; + + //First try to open the external http listener, this requires admin (or a prior + //reservation of the port with netsh) + try + { + this.StartWebApp(baseAddress, modelManager); + Log.Information($"Started HTTP API at http://+:{OpusCatMtEngineSettings.Default.HttpMtServicePort}. This API can be accessed from remote computers, if the firewall has been configured to allow it."); + } + //If opening the external listener fails, open a localhost listener (works without admin). + catch (Exception ex) + { + this.StartWebApp($"http://localhost:{OpusCatMtEngineSettings.Default.HttpMtServicePort}", modelManager); + Log.Information($"Started HTTP API at http://localhost:{OpusCatMtEngineSettings.Default.HttpMtServicePort}. This API cannot be accessed from remote computers."); + } } else { baseAddress = $"http://localhost:{OpusCatMtEngineSettings.Default.HttpMtServicePort}"; - } - //First try to open the external http listener, this requires admin (or a prior - //reservation of the port with netsh) - try - { - this.StartWebApp($"http://+:{OpusCatMtEngineSettings.Default.HttpMtServicePort}", modelManager); - Log.Information($"Started HTTP API at http://+:{OpusCatMtEngineSettings.Default.HttpMtServicePort}. This API can be accessed from remote computers, if the firewall has been configured to allow it."); - } - //If opening the external listener fails, open a localhost listener (works without admin). - catch (Exception ex) - { this.StartWebApp($"http://localhost:{OpusCatMtEngineSettings.Default.HttpMtServicePort}", modelManager); Log.Information($"Started HTTP API at http://localhost:{OpusCatMtEngineSettings.Default.HttpMtServicePort}. This API cannot be accessed from remote computers."); } + + } private void StartWebApp(string baseAddress, ModelManager modelManager) @@ -52,12 +58,25 @@ private void StartWebApp(string baseAddress, ModelManager modelManager) builder.Services.AddControllers().AddJsonOptions( options => { options.JsonSerializerOptions.PropertyNamingPolicy = null; options.JsonSerializerOptions.PropertyNameCaseInsensitive = false; }); builder.Services.AddSingleton(modelManager); - var app = builder.Build(); + builder.Services.AddCors(options => + { + options.AddDefaultPolicy( + builder => + { + builder.AllowAnyOrigin(); + builder.AllowAnyHeader(); + builder.AllowAnyMethod(); + }); + }); +; + var app = builder.Build(); + app.UseCors(); app.UseRouting(); app.MapControllerRoute( name: "default", pattern: "{controller}/{action}"); + app.RunAsync(baseAddress); } diff --git a/AvaloniaApplication1/OpusCatMtEngine.sh b/AvaloniaApplication1/OpusCatMtEngine.sh new file mode 100644 index 0000000..10ab9b4 --- /dev/null +++ b/AvaloniaApplication1/OpusCatMtEngine.sh @@ -0,0 +1,2 @@ +#!/bin/bash +LD_LIBRARY_PATH=$LD_LIBRARY_PATH./python3-linux-3.8.13-x86_64/lib/ PYTHONHOME=./python3-linux-3.8.13-x86_64/ ./OpusCatMtEngineCore \ No newline at end of file diff --git a/AvaloniaApplication1/UI/OpusCatSettingsView.axaml.cs b/AvaloniaApplication1/UI/OpusCatSettingsView.axaml.cs index 94f1398..e6f1f37 100644 --- a/AvaloniaApplication1/UI/OpusCatSettingsView.axaml.cs +++ b/AvaloniaApplication1/UI/OpusCatSettingsView.axaml.cs @@ -4,6 +4,8 @@ using Avalonia.Markup.Xaml; using Avalonia.VisualTree; using Microsoft.AspNetCore.Mvc.ViewEngines; +using MsBox.Avalonia.Enums; +using MsBox.Avalonia; using OpusCatMtEngine; using OpusCatMtEngine.UI; using System; @@ -14,6 +16,7 @@ using System.Diagnostics; using System.Linq; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using static System.Runtime.InteropServices.JavaScript.JSType; @@ -59,10 +62,33 @@ private void SettingsControl_Loaded(object? sender, RoutedEventArgs e) NotifyPropertyChanged("SaveButtonEnabled"); } - public void OpenCustomSettingsInEditor_Click(object sender, RoutedEventArgs e) + public async void OpenCustomSettingsInEditor_Click(object sender, RoutedEventArgs e) { var customizeYml = HelperFunctions.GetOpusCatDataPath(OpusCatMtEngineSettings.Default.CustomizationBaseConfig); - Process.Start("notepad.exe", customizeYml); + try + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Process.Start(new ProcessStartInfo("cmd", $"/c start {customizeYml}")); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Process.Start("xdg-open", customizeYml); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + Process.Start("open", customizeYml); + } + } + catch (Exception ex) + { + string messageBoxText = "Could not open customize.yml in a text editor."; + var box = MessageBoxManager.GetMessageBoxStandard( + "Cannot open editor", + messageBoxText, + ButtonEnum.Ok); + var result = await box.ShowAsync(); + } } diff --git a/AvaloniaApplication1/UI/RightToLeftConverter.cs b/AvaloniaApplication1/UI/RightToLeftConverter.cs new file mode 100644 index 0000000..50b3a80 --- /dev/null +++ b/AvaloniaApplication1/UI/RightToLeftConverter.cs @@ -0,0 +1,42 @@ +using Avalonia.Data.Converters; +using Avalonia.Data; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Avalonia.Media; + +namespace OpusCatMtEngine +{ + public class RightToLeftConverter : IValueConverter + { + public static readonly RightToLeftConverter Instance = new(); + + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if (value is Boolean isRtl + && targetType.IsAssignableTo(typeof(FlowDirection))) + { + if (isRtl) + { + return FlowDirection.RightToLeft; + } + else + { + return FlowDirection.LeftToRight; + } + + } + + // converter used for the wrong type + return new BindingNotification(new InvalidCastException(), BindingErrorType.Error); + } + + public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + } +} diff --git a/AvaloniaApplication1/UI/TranslateView.axaml b/AvaloniaApplication1/UI/TranslateView.axaml index b82615e..a002161 100644 --- a/AvaloniaApplication1/UI/TranslateView.axaml +++ b/AvaloniaApplication1/UI/TranslateView.axaml @@ -8,6 +8,9 @@ xmlns:resx="clr-namespace:OpusCatMtEngine.Properties" x:Name="_this" x:CompileBindings="False"> + + + @@ -39,9 +42,9 @@ - + - + @@ -64,7 +67,7 @@ diff --git a/AvaloniaApplication1/UI/TranslateView.axaml.cs b/AvaloniaApplication1/UI/TranslateView.axaml.cs index fa34aac..e9ff906 100644 --- a/AvaloniaApplication1/UI/TranslateView.axaml.cs +++ b/AvaloniaApplication1/UI/TranslateView.axaml.cs @@ -66,8 +66,8 @@ public IsoLanguage SourceLanguage get => sourceLanguage; set { - NotifyPropertyChanged(); sourceLanguage = value; + NotifyPropertyChanged(); } } @@ -76,8 +76,8 @@ public IsoLanguage TargetLanguage get => targetLanguage; set { - NotifyPropertyChanged(); targetLanguage = value; + NotifyPropertyChanged(); } } diff --git a/AvaloniaApplication1/iso-639-3-macrolanguages.tab b/AvaloniaApplication1/iso-639-3-macrolanguages.tab new file mode 100644 index 0000000..dbf2285 --- /dev/null +++ b/AvaloniaApplication1/iso-639-3-macrolanguages.tab @@ -0,0 +1,457 @@ +M_Id I_Id I_Status +aka fat A +aka twi A +ara aao A +ara abh A +ara abv A +ara acm A +ara acq A +ara acw A +ara acx A +ara acy A +ara adf A +ara aeb A +ara aec A +ara afb A +ara ajp R +ara apc A +ara apd A +ara arb A +ara arq A +ara ars A +ara ary A +ara arz A +ara auz A +ara avl A +ara ayh A +ara ayl A +ara ayn A +ara ayp A +ara bbz R +ara pga A +ara shu A +ara ssh A +aym ayc A +aym ayr A +aze azb A +aze azj A +bal bcc A +bal bgn A +bal bgp A +bik bcl A +bik bhk R +bik bln A +bik bto A +bik cts A +bik fbl A +bik lbl A +bik rbl A +bik ubl A +bnc ebk A +bnc lbk A +bnc obk A +bnc rbk A +bnc vbk A +bua bxm A +bua bxr A +bua bxu A +chm mhr A +chm mrj A +cre crj A +cre crk A +cre crl A +cre crm A +cre csw A +cre cwd A +del umu A +del unm A +den scs A +den xsl A +din dib A +din dik A +din dip A +din diw A +din dks A +doi dgo A +doi xnr A +est ekk A +est vro A +fas pes A +fas prs A +ful ffm A +ful fub A +ful fuc A +ful fue A +ful fuf A +ful fuh A +ful fui A +ful fuq A +ful fuv A +gba bdt A +gba gbp A +gba gbq A +gba gmm A +gba gso A +gba gya A +gba mdo R +gon esg A +gon ggo R +gon gno A +gon wsg A +grb gbo A +grb gec A +grb grj A +grb grv A +grb gry A +grn gnw A +grn gug A +grn gui A +grn gun A +grn nhd A +hai hax A +hai hdn A +hbs bos A +hbs cnr A +hbs hrv A +hbs srp A +hmn blu R +hmn cqd A +hmn hea A +hmn hma A +hmn hmc A +hmn hmd A +hmn hme A +hmn hmg A +hmn hmh A +hmn hmi A +hmn hmj A +hmn hml A +hmn hmm A +hmn hmp A +hmn hmq A +hmn hms A +hmn hmw A +hmn hmy A +hmn hmz A +hmn hnj A +hmn hrm A +hmn huj A +hmn mmr A +hmn muq A +hmn mww A +hmn sfm A +iku ike A +iku ikt A +ipk esi A +ipk esk A +jrb ajt R +jrb aju A +jrb jye A +jrb yhd A +jrb yud A +kau kby A +kau knc A +kau krt A +kln enb A +kln eyo A +kln niq A +kln oki A +kln pko A +kln sgc A +kln spy A +kln tec A +kln tuy A +kok gom A +kok knn A +kom koi A +kom kpv A +kon kng A +kon kwy A +kon ldi A +kpe gkp A +kpe xpe A +kur ckb A +kur kmr A +kur sdh A +lah hnd A +lah hno A +lah jat A +lah phr A +lah pmu R +lah pnb A +lah skr A +lah xhe A +lav ltg A +lav lvs A +luy bxk A +luy ida A +luy lkb A +luy lko A +luy lks A +luy lri A +luy lrm A +luy lsm A +luy lto A +luy lts A +luy lwg A +luy nle A +luy nyd A +luy rag A +man emk A +man mku A +man mlq A +man mnk A +man msc A +man mwk A +man myq R +mlg bhr A +mlg bjq R +mlg bmm A +mlg bzc A +mlg msh A +mlg plt A +mlg skg A +mlg tdx A +mlg tkg A +mlg txy A +mlg xmv A +mlg xmw A +mon khk A +mon mvf A +msa bjn A +msa btj A +msa bve A +msa bvu A +msa coa A +msa dup A +msa hji A +msa ind A +msa jak A +msa jax A +msa kvb A +msa kvr A +msa kxd A +msa lce A +msa lcf A +msa liw A +msa max A +msa meo A +msa mfa A +msa mfb A +msa min A +msa mly R +msa mqg A +msa msi A +msa mui A +msa orn A +msa ors A +msa pel A +msa pse A +msa tmw A +msa urk A +msa vkk A +msa vkt A +msa xmm A +msa zlm A +msa zmi A +msa zsm A +mwr dhd A +mwr mtr A +mwr mve A +mwr rwr A +mwr swv A +mwr wry A +nep dty A +nep npi A +nor nno A +nor nob A +oji ciw A +oji ojb A +oji ojc A +oji ojg A +oji ojs A +oji ojw A +oji otw A +ori ory A +ori spv A +orm gax A +orm gaz A +orm hae A +orm orc A +pus pbt A +pus pbu A +pus pst A +que cqu R +que qub A +que qud A +que quf A +que qug A +que quh A +que quk A +que qul A +que qup A +que qur A +que qus A +que quw A +que qux A +que quy A +que quz A +que qva A +que qvc A +que qve A +que qvh A +que qvi A +que qvj A +que qvl A +que qvm A +que qvn A +que qvo A +que qvp A +que qvs A +que qvw A +que qvz A +que qwa A +que qwc A +que qwh A +que qws A +que qxa A +que qxc A +que qxh A +que qxl A +que qxn A +que qxo A +que qxp A +que qxr A +que qxt A +que qxu A +que qxw A +raj bgq A +raj gda A +raj gju A +raj hoj A +raj mup A +raj wbr A +rom rmc A +rom rmf A +rom rml A +rom rmn A +rom rmo A +rom rmw A +rom rmy A +san cls A +san vsn A +sqi aae A +sqi aat A +sqi aln A +sqi als A +srd sdc A +srd sdn A +srd src A +srd sro A +swa swc A +swa swh A +syr aii A +syr cld A +tmh taq A +tmh thv A +tmh thz A +tmh ttq A +uzb uzn A +uzb uzs A +yid ydd A +yid yih A +zap zaa A +zap zab A +zap zac A +zap zad A +zap zae A +zap zaf A +zap zai A +zap zam A +zap zao A +zap zaq A +zap zar A +zap zas A +zap zat A +zap zav A +zap zaw A +zap zax A +zap zca A +zap zcd A +zap zoo A +zap zpa A +zap zpb A +zap zpc A +zap zpd A +zap zpe A +zap zpf A +zap zpg A +zap zph A +zap zpi A +zap zpj A +zap zpk A +zap zpl A +zap zpm A +zap zpn A +zap zpo A +zap zpp A +zap zpq A +zap zpr A +zap zps A +zap zpt A +zap zpu A +zap zpv A +zap zpw A +zap zpx A +zap zpy A +zap zpz A +zap zsr A +zap ztc R +zap zte A +zap ztg A +zap ztl A +zap ztm A +zap ztn A +zap ztp A +zap ztq A +zap zts A +zap ztt A +zap ztu A +zap ztx A +zap zty A +zha ccx R +zha ccy R +zha zch A +zha zeh A +zha zgb A +zha zgm A +zha zgn A +zha zhd A +zha zhn A +zha zlj A +zha zln A +zha zlq A +zha zqe A +zha zyb A +zha zyg A +zha zyj A +zha zyn A +zha zzj A +zho cdo A +zho cjy A +zho cmn A +zho cnp A +zho cpx A +zho csp A +zho czh A +zho czo A +zho gan A +zho hak A +zho hsn A +zho lzh A +zho mnp A +zho nan A +zho wuu A +zho yue A +zza diq A +zza kiu A