mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 18:38:27 +03:00
i18n service
This commit is contained in:
parent
6a65b6d735
commit
6ee109dc80
11 changed files with 384 additions and 4 deletions
|
@ -80,6 +80,7 @@
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||||
<Compile Include="Services\DeviceActionService.cs" />
|
<Compile Include="Services\DeviceActionService.cs" />
|
||||||
|
<Compile Include="Services\LocalizeService.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AndroidAsset Include="Assets\FontAwesome.ttf" />
|
<AndroidAsset Include="Assets\FontAwesome.ttf" />
|
||||||
|
|
|
@ -41,7 +41,11 @@ namespace Bit.Droid
|
||||||
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
|
var documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
|
||||||
var liteDbStorage = new LiteDbStorageService(Path.Combine(documentsPath, "bitwarden.db"));
|
var liteDbStorage = new LiteDbStorageService(Path.Combine(documentsPath, "bitwarden.db"));
|
||||||
var deviceActionService = new DeviceActionService();
|
var deviceActionService = new DeviceActionService();
|
||||||
|
var localizeService = new LocalizeService();
|
||||||
|
|
||||||
|
ServiceContainer.Register<ILocalizeService>("localizeService", localizeService);
|
||||||
|
ServiceContainer.Register<II18nService>("i18nService",
|
||||||
|
new MobileI18nService(localizeService.GetCurrentCultureInfo()));
|
||||||
ServiceContainer.Register<ICryptoPrimitiveService>("cryptoPrimitiveService", new CryptoPrimitiveService());
|
ServiceContainer.Register<ICryptoPrimitiveService>("cryptoPrimitiveService", new CryptoPrimitiveService());
|
||||||
ServiceContainer.Register<IStorageService>("storageService",
|
ServiceContainer.Register<IStorageService>("storageService",
|
||||||
new MobileStorageService(preferencesStorage, liteDbStorage));
|
new MobileStorageService(preferencesStorage, liteDbStorage));
|
||||||
|
|
97
src/Android/Services/LocalizeService.cs
Normal file
97
src/Android/Services/LocalizeService.cs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
|
||||||
|
namespace Bit.Droid.Services
|
||||||
|
{
|
||||||
|
public class LocalizeService : ILocalizeService
|
||||||
|
{
|
||||||
|
public CultureInfo GetCurrentCultureInfo()
|
||||||
|
{
|
||||||
|
var netLanguage = "en";
|
||||||
|
var androidLocale = Java.Util.Locale.Default;
|
||||||
|
netLanguage = AndroidToDotnetLanguage(androidLocale.ToString().Replace("_", "-"));
|
||||||
|
// This gets called a lot - try/catch can be expensive so consider caching or something
|
||||||
|
CultureInfo ci = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ci = new CultureInfo(netLanguage);
|
||||||
|
}
|
||||||
|
catch(CultureNotFoundException e1)
|
||||||
|
{
|
||||||
|
// iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
|
||||||
|
// fallback to first characters, in this case "en"
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
|
||||||
|
Console.WriteLine(netLanguage + " failed, trying " + fallback + " (" + e1.Message + ")");
|
||||||
|
ci = new CultureInfo(fallback);
|
||||||
|
}
|
||||||
|
catch(CultureNotFoundException e2)
|
||||||
|
{
|
||||||
|
// iOS language not valid .NET culture, falling back to English
|
||||||
|
Console.WriteLine(netLanguage + " couldn't be set, using 'en' (" + e2.Message + ")");
|
||||||
|
ci = new CultureInfo("en");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ci;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string AndroidToDotnetLanguage(string androidLanguage)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Android Language:" + androidLanguage);
|
||||||
|
var netLanguage = androidLanguage;
|
||||||
|
if(androidLanguage.StartsWith("zh"))
|
||||||
|
{
|
||||||
|
if(androidLanguage.Contains("Hant") || androidLanguage.Contains("TW") ||
|
||||||
|
androidLanguage.Contains("HK") || androidLanguage.Contains("MO"))
|
||||||
|
{
|
||||||
|
netLanguage = "zh-Hant";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
netLanguage = "zh-Hans";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Certain languages need to be converted to CultureInfo equivalent
|
||||||
|
switch(androidLanguage)
|
||||||
|
{
|
||||||
|
case "ms-BN": // "Malaysian (Brunei)" not supported .NET culture
|
||||||
|
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
|
||||||
|
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
|
||||||
|
netLanguage = "ms"; // closest supported
|
||||||
|
break;
|
||||||
|
case "in-ID": // "Indonesian (Indonesia)" has different code in .NET
|
||||||
|
netLanguage = "id-ID"; // correct code for .NET
|
||||||
|
break;
|
||||||
|
case "gsw-CH": // "Schwiizertüütsch (Swiss German)" not supported .NET culture
|
||||||
|
netLanguage = "de-CH"; // closest supported
|
||||||
|
break;
|
||||||
|
// add more application-specific cases here (if required)
|
||||||
|
// ONLY use cultures that have been tested and known to work
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine(".NET Language/Locale:" + netLanguage);
|
||||||
|
return netLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ToDotnetFallbackLanguage(PlatformCulture platCulture)
|
||||||
|
{
|
||||||
|
Console.WriteLine(".NET Fallback Language:" + platCulture.LanguageCode);
|
||||||
|
var netLanguage = platCulture.LanguageCode; // use the first part of the identifier (two chars, usually);
|
||||||
|
switch(platCulture.LanguageCode)
|
||||||
|
{
|
||||||
|
case "gsw":
|
||||||
|
netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
|
||||||
|
break;
|
||||||
|
// add more application-specific cases here (if required)
|
||||||
|
// ONLY use cultures that have been tested and known to work
|
||||||
|
}
|
||||||
|
Console.WriteLine(".NET Fallback Language/Locale:" + netLanguage + " (application-specific)");
|
||||||
|
return netLanguage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
src/App/Abstractions/ILocalizeService.cs
Normal file
9
src/App/Abstractions/ILocalizeService.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Bit.App.Abstractions
|
||||||
|
{
|
||||||
|
public interface ILocalizeService
|
||||||
|
{
|
||||||
|
CultureInfo GetCurrentCultureInfo();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
using Bit.App.Models;
|
using Bit.App.Models;
|
||||||
using Bit.App.Pages;
|
using Bit.App.Pages;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.App.Services;
|
||||||
using Bit.App.Utilities;
|
using Bit.App.Utilities;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Xamarin.Forms.StyleSheets;
|
using Xamarin.Forms.StyleSheets;
|
||||||
using Xamarin.Forms.Xaml;
|
using Xamarin.Forms.Xaml;
|
||||||
|
@ -12,18 +15,23 @@ namespace Bit.App
|
||||||
{
|
{
|
||||||
public partial class App : Application
|
public partial class App : Application
|
||||||
{
|
{
|
||||||
|
private readonly MobileI18nService _i18nService;
|
||||||
|
|
||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService;
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
SetCulture();
|
||||||
ThemeManager.SetTheme("light");
|
ThemeManager.SetTheme("light");
|
||||||
MainPage = new TabsPage();
|
MainPage = new TabsPage();
|
||||||
|
|
||||||
|
ServiceContainer.Resolve<MobilePlatformUtilsService>("platformUtilsService").Init();
|
||||||
MessagingCenter.Subscribe<Application, DialogDetails>(Current, "ShowDialog", async (sender, details) =>
|
MessagingCenter.Subscribe<Application, DialogDetails>(Current, "ShowDialog", async (sender, details) =>
|
||||||
{
|
{
|
||||||
var confirmed = true;
|
var confirmed = true;
|
||||||
// TODO: ok text
|
var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ?
|
||||||
var confirmText = string.IsNullOrWhiteSpace(details.ConfirmText) ? "Ok" : details.ConfirmText;
|
AppResources.Ok : details.ConfirmText;
|
||||||
if(!string.IsNullOrWhiteSpace(details.CancelText))
|
if(!string.IsNullOrWhiteSpace(details.CancelText))
|
||||||
{
|
{
|
||||||
confirmed = await MainPage.DisplayAlert(details.Title, details.Text, confirmText,
|
confirmed = await MainPage.DisplayAlert(details.Title, details.Text, confirmText,
|
||||||
|
@ -51,5 +59,14 @@ namespace Bit.App
|
||||||
{
|
{
|
||||||
// Handle when your app resumes
|
// Handle when your app resumes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SetCulture()
|
||||||
|
{
|
||||||
|
_i18nService.Init();
|
||||||
|
// Calendars are removed by linker. ref https://bugzilla.xamarin.com/show_bug.cgi?id=59077
|
||||||
|
new System.Globalization.ThaiBuddhistCalendar();
|
||||||
|
new System.Globalization.HijriCalendar();
|
||||||
|
new System.Globalization.UmAlQuraCalendar();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
39
src/App/Models/PlatformCulture.cs
Normal file
39
src/App/Models/PlatformCulture.cs
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.App.Models
|
||||||
|
{
|
||||||
|
public class PlatformCulture
|
||||||
|
{
|
||||||
|
public PlatformCulture(string platformCultureString)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(platformCultureString))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Expected culture identifier.", nameof(platformCultureString));
|
||||||
|
}
|
||||||
|
|
||||||
|
// .NET expects dash, not underscore
|
||||||
|
PlatformString = platformCultureString.Replace("_", "-");
|
||||||
|
var dashIndex = PlatformString.IndexOf("-", StringComparison.Ordinal);
|
||||||
|
if(dashIndex > 0)
|
||||||
|
{
|
||||||
|
var parts = PlatformString.Split('-');
|
||||||
|
LanguageCode = parts[0];
|
||||||
|
LocaleCode = parts[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LanguageCode = PlatformString;
|
||||||
|
LocaleCode = string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PlatformString { get; private set; }
|
||||||
|
public string LanguageCode { get; private set; }
|
||||||
|
public string LocaleCode { get; private set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return PlatformString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
67
src/App/Services/MobileI18nService.cs
Normal file
67
src/App/Services/MobileI18nService.cs
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Bit.App.Services
|
||||||
|
{
|
||||||
|
public class MobileI18nService : II18nService
|
||||||
|
{
|
||||||
|
private const string ResourceId = "UsingResxLocalization.Resx.AppResources";
|
||||||
|
|
||||||
|
private static readonly Lazy<ResourceManager> _resourceManager = new Lazy<ResourceManager>(() =>
|
||||||
|
new ResourceManager(ResourceId, IntrospectionExtensions.GetTypeInfo(typeof(MobileI18nService)).Assembly));
|
||||||
|
|
||||||
|
private readonly CultureInfo _defaultCulture = new CultureInfo("en-US");
|
||||||
|
private bool _inited;
|
||||||
|
|
||||||
|
public MobileI18nService(CultureInfo systemCulture)
|
||||||
|
{
|
||||||
|
Culture = systemCulture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CultureInfo Culture { get; set; }
|
||||||
|
|
||||||
|
public void Init(CultureInfo culture = null)
|
||||||
|
{
|
||||||
|
if(_inited)
|
||||||
|
{
|
||||||
|
throw new Exception("I18n already inited.");
|
||||||
|
}
|
||||||
|
_inited = true;
|
||||||
|
if(culture != null)
|
||||||
|
{
|
||||||
|
Culture = culture;
|
||||||
|
}
|
||||||
|
AppResources.Culture = Culture;
|
||||||
|
Thread.CurrentThread.CurrentCulture = Culture;
|
||||||
|
Thread.CurrentThread.CurrentUICulture = Culture;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string T(string id, params string[] p)
|
||||||
|
{
|
||||||
|
return Translate(id, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Translate(string id, params string[] p)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(id))
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
var result = _resourceManager.Value.GetString(id, Culture);
|
||||||
|
if(result == null)
|
||||||
|
{
|
||||||
|
result = _resourceManager.Value.GetString(id, _defaultCulture);
|
||||||
|
if(result == null)
|
||||||
|
{
|
||||||
|
result = $"{{{id}}}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string.Format(result, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
src/App/Utilities/TranslateExtension.cs
Normal file
29
src/App/Utilities/TranslateExtension.cs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using System;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
using Xamarin.Forms.Xaml;
|
||||||
|
|
||||||
|
namespace Bit.App.Utilities
|
||||||
|
{
|
||||||
|
[ContentProperty("Text")]
|
||||||
|
public class TranslateExtension : IMarkupExtension
|
||||||
|
{
|
||||||
|
private II18nService _i18nService;
|
||||||
|
|
||||||
|
public TranslateExtension()
|
||||||
|
{
|
||||||
|
_i18nService = ServiceContainer.Resolve<II18nService>("i18nService");
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string P1 { get; set; }
|
||||||
|
public string P2 { get; set; }
|
||||||
|
public string P3 { get; set; }
|
||||||
|
|
||||||
|
public object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return _i18nService.T(Id, P1, P2, P3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
src/Core/Abstractions/II18nService.cs
Normal file
11
src/Core/Abstractions/II18nService.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace Bit.Core.Abstractions
|
||||||
|
{
|
||||||
|
public interface II18nService
|
||||||
|
{
|
||||||
|
CultureInfo Culture { get; set; }
|
||||||
|
string T(string id, params string[] p);
|
||||||
|
string Translate(string id, params string[] p);
|
||||||
|
}
|
||||||
|
}
|
101
src/iOS.Core/Services/LocalizeService.cs
Normal file
101
src/iOS.Core/Services/LocalizeService.cs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Models;
|
||||||
|
using Foundation;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Core.Services
|
||||||
|
{
|
||||||
|
public class LocalizeService : ILocalizeService
|
||||||
|
{
|
||||||
|
public CultureInfo GetCurrentCultureInfo()
|
||||||
|
{
|
||||||
|
var netLanguage = "en";
|
||||||
|
if(NSLocale.PreferredLanguages.Length > 0)
|
||||||
|
{
|
||||||
|
var pref = NSLocale.PreferredLanguages[0];
|
||||||
|
|
||||||
|
netLanguage = iOSToDotnetLanguage(pref);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gets called a lot - try/catch can be expensive so consider caching or something
|
||||||
|
CultureInfo ci = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ci = new CultureInfo(netLanguage);
|
||||||
|
}
|
||||||
|
catch(CultureNotFoundException e1)
|
||||||
|
{
|
||||||
|
// iOS locale not valid .NET culture (eg. "en-ES" : English in Spain)
|
||||||
|
// fallback to first characters, in this case "en"
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var fallback = ToDotnetFallbackLanguage(new PlatformCulture(netLanguage));
|
||||||
|
Console.WriteLine(netLanguage + " failed, trying " + fallback + " (" + e1.Message + ")");
|
||||||
|
ci = new CultureInfo(fallback);
|
||||||
|
}
|
||||||
|
catch(CultureNotFoundException e2)
|
||||||
|
{
|
||||||
|
// iOS language not valid .NET culture, falling back to English
|
||||||
|
Console.WriteLine(netLanguage + " couldn't be set, using 'en' (" + e2.Message + ")");
|
||||||
|
ci = new CultureInfo("en");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ci;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string iOSToDotnetLanguage(string iOSLanguage)
|
||||||
|
{
|
||||||
|
Console.WriteLine("iOS Language:" + iOSLanguage);
|
||||||
|
var netLanguage = iOSLanguage;
|
||||||
|
if(iOSLanguage.StartsWith("zh-Hant") || iOSLanguage.StartsWith("zh-HK"))
|
||||||
|
{
|
||||||
|
netLanguage = "zh-Hant";
|
||||||
|
}
|
||||||
|
else if(iOSLanguage.StartsWith("zh"))
|
||||||
|
{
|
||||||
|
netLanguage = "zh-Hans";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Certain languages need to be converted to CultureInfo equivalent
|
||||||
|
switch(iOSLanguage)
|
||||||
|
{
|
||||||
|
case "ms-MY": // "Malaysian (Malaysia)" not supported .NET culture
|
||||||
|
case "ms-SG": // "Malaysian (Singapore)" not supported .NET culture
|
||||||
|
netLanguage = "ms"; // closest supported
|
||||||
|
break;
|
||||||
|
case "gsw-CH": // "Schwiizertüütsch (Swiss German)" not supported .NET culture
|
||||||
|
netLanguage = "de-CH"; // closest supported
|
||||||
|
break;
|
||||||
|
// add more application-specific cases here (if required)
|
||||||
|
// ONLY use cultures that have been tested and known to work
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine(".NET Language/Locale:" + netLanguage);
|
||||||
|
return netLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ToDotnetFallbackLanguage(PlatformCulture platCulture)
|
||||||
|
{
|
||||||
|
Console.WriteLine(".NET Fallback Language:" + platCulture.LanguageCode);
|
||||||
|
// Use the first part of the identifier (two chars, usually);
|
||||||
|
var netLanguage = platCulture.LanguageCode;
|
||||||
|
switch(platCulture.LanguageCode)
|
||||||
|
{
|
||||||
|
case "pt":
|
||||||
|
netLanguage = "pt-PT"; // fallback to Portuguese (Portugal)
|
||||||
|
break;
|
||||||
|
case "gsw":
|
||||||
|
netLanguage = "de-CH"; // equivalent to German (Switzerland) for this app
|
||||||
|
break;
|
||||||
|
// add more application-specific cases here (if required)
|
||||||
|
// ONLY use cultures that have been tested and known to work
|
||||||
|
}
|
||||||
|
Console.WriteLine(".NET Fallback Language/Locale:" + netLanguage + " (application-specific)");
|
||||||
|
return netLanguage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,9 +49,14 @@
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||||
<Compile Include="Services\KeyChainStorageService.cs" />
|
<Compile Include="Services\KeyChainStorageService.cs" />
|
||||||
|
<Compile Include="Services\LocalizeService.cs" />
|
||||||
<Compile Include="Views\Toast.cs" />
|
<Compile Include="Views\Toast.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\App\App.csproj">
|
||||||
|
<Project>{ee44c6a1-2a85-45fe-8d9b-bf1d5f88809c}</Project>
|
||||||
|
<Name>App</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\Core\Core.csproj">
|
<ProjectReference Include="..\Core\Core.csproj">
|
||||||
<Project>{4b8a8c41-9820-4341-974c-41e65b7f4366}</Project>
|
<Project>{4b8a8c41-9820-4341-974c-41e65b7f4366}</Project>
|
||||||
<Name>Core</Name>
|
<Name>Core</Name>
|
||||||
|
|
Loading…
Reference in a new issue