fix #2464 - translation install/upgrade experience
This commit is contained in:
parent
82c074ce2e
commit
368b900a6e
|
@ -9,7 +9,7 @@
|
|||
@inject IStringLocalizer<Add> Localizer
|
||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||
|
||||
@if (_supportedCultures == null)
|
||||
@if (_cultures == null)
|
||||
{
|
||||
<p><em>@SharedLocalizer["Loading"]</em></p>
|
||||
}
|
||||
|
@ -17,104 +17,42 @@ else
|
|||
{
|
||||
<TabStrip>
|
||||
<TabPanel Name="Manage" ResourceKey="Manage">
|
||||
@if (_availableCultures.Count() == 0)
|
||||
{
|
||||
<ModuleMessage Type="MessageType.Info" Message="@_message"></ModuleMessage>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
}
|
||||
else
|
||||
{
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="name" HelpText="Name Of The Language" ResourceKey="Name">Name:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="_code" class="form-select" @bind="@_code" required>
|
||||
@foreach (var culture in _availableCultures)
|
||||
{
|
||||
<option value="@culture.Name">@(culture.DisplayName + " (" + culture.Name + ")")</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="default" HelpText="Indicates Whether Or Not This Language Is The Default For The Site" ResourceKey="IsDefault">Default?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="default" class="form-select" @bind="@_isDefault" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
<form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
|
||||
<div class="container">
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="translated" HelpText="Specify If You Wish To Select Languages That Have Translations Installed" ResourceKey="Translated">Translated?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="translated" class="form-select" value="@_translated" @onchange="(e => TranslatedChanged(e))" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="name" HelpText="Name Of The Language" ResourceKey="Name">Name:</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="_code" class="form-select" @bind="@_code" required>
|
||||
<option value="-"><@SharedLocalizer["Not Specified"]></option>
|
||||
@foreach (var culture in _cultures)
|
||||
{
|
||||
<option value="@culture.Name">@(culture.DisplayName + " (" + culture.Name + ")")</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success" @onclick="SaveLanguage">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</form>
|
||||
}
|
||||
</TabPanel>
|
||||
<TabPanel Name="Translations" Heading="Translations" ResourceKey="Download" Security="SecurityAccessLevel.Host">
|
||||
<div class="row justify-content-center mb-3">
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<select id="price" class="form-select custom-select" @onchange="(e => PriceChanged(e))">
|
||||
<option value="free">@SharedLocalizer["Free"]</option>
|
||||
<option value="paid">@SharedLocalizer["Paid"]</option>
|
||||
</select>
|
||||
<input id="search" class="form-control" placeholder="@SharedLocalizer["Search.Hint"]" @bind="@_search" />
|
||||
<button type="button" class="btn btn-primary" @onclick="Search">@SharedLocalizer["Search"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="Reset">@SharedLocalizer["Reset"]</button>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="default" HelpText="Indicates Whether Or Not This Language Is The Default For The Site" ResourceKey="IsDefault">Default?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="default" class="form-select" @bind="@_default" required>
|
||||
<option value="True">@SharedLocalizer["Yes"]</option>
|
||||
<option value="False">@SharedLocalizer["No"]</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (_packages != null)
|
||||
{
|
||||
@if (_packages.Count > 0)
|
||||
{
|
||||
<Pager Items="@_packages">
|
||||
<Row>
|
||||
<td>
|
||||
<h3 style="display: inline;"><a href="@context.ProductUrl" target="_new">@context.Name</a></h3> by: <strong><a href="@context.OwnerUrl" target="new">@context.Owner</a></strong><br />
|
||||
@(context.Description.Length > 400 ? (context.Description.Substring(0, 400) + "...") : context.Description)<br />
|
||||
<strong>@(String.Format("{0:n0}", context.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||
@SharedLocalizer["Search.Released"]: <strong>@context.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||
@SharedLocalizer["Search.Version"]: <strong>@context.Version</strong>
|
||||
@((MarkupString)(!string.IsNullOrEmpty(context.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(context.PackageUrl).Host + "</strong>" : ""))
|
||||
@((MarkupString)(context.TrialPeriod > 0 ? " | <strong>" + context.TrialPeriod + " " + @SharedLocalizer["Trial"] + "</strong>" : ""))
|
||||
</td>
|
||||
<td style="width: 1px; vertical-align: middle;">
|
||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PackageUrl))
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
</td>
|
||||
<td style="width: 1px; vertical-align: middle;">
|
||||
@if (context.Price != null && !string.IsNullOrEmpty(context.PaymentUrl))
|
||||
{
|
||||
<a class="btn btn-primary" style="text-decoration: none !important" href="@context.PaymentUrl" target="_new">@context.Price.Value.ToString("$#,##0.00")</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(context.PackageId, context.Version))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
}
|
||||
else
|
||||
{
|
||||
<br />
|
||||
<div class="mx-auto text-center">
|
||||
@Localizer["Search.NoResults"]
|
||||
</div>
|
||||
}
|
||||
<button type="button" class="btn btn-success" @onclick="InstallLanguages">@SharedLocalizer["Install"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
|
||||
<br />
|
||||
<br />
|
||||
<ModuleMessage Type="MessageType.Info" Message="@SharedLocalizer["Oqtane.Marketplace"]" />
|
||||
}
|
||||
<button type="button" class="btn btn-success" @onclick="SaveLanguage">@SharedLocalizer["Save"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</form>
|
||||
</TabPanel>
|
||||
<TabPanel Name="Upload" ResourceKey="Upload" Security="SecurityAccessLevel.Host">
|
||||
<div class="container">
|
||||
|
@ -125,216 +63,86 @@ else
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-success" @onclick="InstallLanguages">@SharedLocalizer["Install"]</button>
|
||||
<button type="button" class="btn btn-success" @onclick="InstallTranslations">@SharedLocalizer["Install"]</button>
|
||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||
</TabPanel>
|
||||
</TabStrip>
|
||||
}
|
||||
|
||||
@if (_productname != "")
|
||||
{
|
||||
<div class="app-actiondialog">
|
||||
<div class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p style="height: 200px; overflow-y: scroll;">
|
||||
<h3>@_productname</h3>
|
||||
@if (!string.IsNullOrEmpty(_license))
|
||||
{
|
||||
@((MarkupString)_license)
|
||||
}
|
||||
else
|
||||
{
|
||||
@SharedLocalizer["License Not Specified"]
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private ElementReference form;
|
||||
private bool validated = false;
|
||||
|
||||
private string _code = string.Empty;
|
||||
private string _isDefault = "False";
|
||||
private string _message;
|
||||
private IEnumerable<Culture> _supportedCultures;
|
||||
private IEnumerable<Culture> _availableCultures;
|
||||
private List<Package> _packages;
|
||||
private string _price = "free";
|
||||
private string _search = "";
|
||||
private string _productname = "";
|
||||
private string _license = "";
|
||||
private string _packageid = "";
|
||||
private string _version = "";
|
||||
private string _translated = "True";
|
||||
private string _code = "-";
|
||||
private string _default = "False";
|
||||
private List<string> _languages;
|
||||
private IEnumerable<Culture> _cultures;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
var languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId);
|
||||
var languagesCodes = languages.Select(l => l.Code).ToList();
|
||||
_languages = languages.Select(l => l.Code).ToList();
|
||||
|
||||
_supportedCultures = await LocalizationService.GetCulturesAsync();
|
||||
_availableCultures = _supportedCultures.Where(c => !c.Name.Equals(Constants.DefaultCulture) && !languagesCodes.Contains(c.Name));
|
||||
await LoadTranslations();
|
||||
await LoadCultures();
|
||||
}
|
||||
|
||||
if (_supportedCultures.Count() == 1)
|
||||
{
|
||||
_message = Localizer["OnlyEnglish"];
|
||||
}
|
||||
else if (_availableCultures.Count() == 0)
|
||||
{
|
||||
_message = Localizer["AllLanguages"];
|
||||
}
|
||||
}
|
||||
private async Task LoadCultures()
|
||||
{
|
||||
_cultures = await LocalizationService.GetCulturesAsync(bool.Parse(_translated));
|
||||
_cultures = _cultures.Where(c => !c.Name.Equals(Constants.DefaultCulture) && !_languages.Contains(c.Name));
|
||||
_code = "-";
|
||||
}
|
||||
|
||||
private async Task LoadTranslations()
|
||||
{
|
||||
_packages = await PackageService.GetPackagesAsync("translation", _search, _price, "");
|
||||
}
|
||||
private async void TranslatedChanged(ChangeEventArgs e)
|
||||
{
|
||||
_translated = (string)e.Value;
|
||||
await LoadCultures();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async void PriceChanged(ChangeEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
_price = (string)e.Value;
|
||||
_search = "";
|
||||
await LoadTranslations();
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On PriceChanged");
|
||||
}
|
||||
}
|
||||
private async Task SaveLanguage()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form) && _code != "-")
|
||||
{
|
||||
var language = new Language
|
||||
{
|
||||
SiteId = PageState.Page.SiteId,
|
||||
Name = CultureInfo.GetCultureInfo(_code).DisplayName,
|
||||
Code = _code,
|
||||
IsDefault = (_default == null ? false : Boolean.Parse(_default))
|
||||
};
|
||||
|
||||
private async Task Search()
|
||||
{
|
||||
try
|
||||
{
|
||||
await LoadTranslations();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On Search");
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
language = await LanguageService.AddLanguageAsync(language);
|
||||
|
||||
private async Task Reset()
|
||||
{
|
||||
try
|
||||
{
|
||||
_search = "";
|
||||
await LoadTranslations();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error On Reset");
|
||||
}
|
||||
}
|
||||
if (language.IsDefault)
|
||||
{
|
||||
await SetCultureAsync(language.Code);
|
||||
}
|
||||
|
||||
private async Task SaveLanguage()
|
||||
{
|
||||
validated = true;
|
||||
var interop = new Interop(JSRuntime);
|
||||
if (await interop.FormValid(form))
|
||||
{
|
||||
var language = new Language
|
||||
{
|
||||
SiteId = PageState.Page.SiteId,
|
||||
Name = CultureInfo.GetCultureInfo(_code).DisplayName,
|
||||
Code = _code,
|
||||
IsDefault = (_isDefault == null ? false : Boolean.Parse(_isDefault))
|
||||
};
|
||||
await logger.LogInformation("Language Added {Language}", language);
|
||||
|
||||
try
|
||||
{
|
||||
language = await LanguageService.AddLanguageAsync(language);
|
||||
|
||||
if (language.IsDefault)
|
||||
{
|
||||
await SetCultureAsync(language.Code);
|
||||
}
|
||||
|
||||
await logger.LogInformation("Language Added {Language}", language);
|
||||
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Adding Language {Language} {Error}", language, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Language.Add"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
NavigationManager.NavigateTo(NavigateUrl());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Adding Language {Language} {Error}", language, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Language.Add"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void HideModal()
|
||||
{
|
||||
_productname = "";
|
||||
_license = "";
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task GetPackage(string packageid, string version)
|
||||
{
|
||||
try
|
||||
{
|
||||
var package = await PackageService.GetPackageAsync(packageid, version);
|
||||
if (package != null)
|
||||
{
|
||||
_productname = package.Name;
|
||||
if (!string.IsNullOrEmpty(package.License))
|
||||
{
|
||||
_license = package.License.Replace("\n", "<br />");
|
||||
}
|
||||
_packageid = package.PackageId;
|
||||
_version = package.Version;
|
||||
}
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", packageid, version);
|
||||
AddModuleMessage(Localizer["Error.Module.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DownloadPackage()
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_packageid, _version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Language Package {Name} {Version} Downloaded Successfully", _packageid, _version);
|
||||
AddModuleMessage(Localizer["Success.Language.Download"], MessageType.Success);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Downloading Translation {Name} {Version}", _packageid, _version);
|
||||
AddModuleMessage(Localizer["Error.Language.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InstallLanguages()
|
||||
private async Task InstallTranslations()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -19,29 +19,86 @@ else
|
|||
<th style="width: 1px;"> </th>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@Localizer["Code"]</th>
|
||||
<th>@Localizer["Translation"]</th>
|
||||
<th>@Localizer["Default"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<th style="width: 1px;">@Localizer["Translation"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
}
|
||||
</Header>
|
||||
<Row>
|
||||
<td><ActionDialog Header="Delete Language" Message="@string.Format(Localizer["Confirm.Language.Delete"], context.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteLanguage(context))" Disabled="@((context.IsDefault && _languages.Count > 2) || context.Code == Constants.DefaultCulture)" ResourceKey="DeleteLanguage" /></td>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Code</td>
|
||||
<td>@context.Version</td>
|
||||
<td><TriStateCheckBox Value="@(context.IsDefault)" Disabled="true"></TriStateCheckBox></td>
|
||||
<td>
|
||||
@if (UpgradeAvailable(context.Code, context.Version))
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadLanguage(context.Code))>@SharedLocalizer["Upgrade"]</button>
|
||||
}
|
||||
</td>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
|
||||
<td>
|
||||
@switch (TranslationAvailable(context.Code, context.Version))
|
||||
{
|
||||
case "install":
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(context.Code))>@SharedLocalizer["Download"]</button>
|
||||
break;
|
||||
case "upgrade":
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(context.Code))>@SharedLocalizer["Upgrade"]</button>
|
||||
break;
|
||||
}
|
||||
</td>
|
||||
}
|
||||
</Row>
|
||||
</Pager>
|
||||
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host) && _install)
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick="InstallTranslations">@SharedLocalizer["Install"]</button>
|
||||
}
|
||||
}
|
||||
|
||||
@if (_package != null)
|
||||
{
|
||||
<div class="app-actiondialog">
|
||||
<div class="modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">@SharedLocalizer["Review License Terms"]</h5>
|
||||
<button type="button" class="btn-close" aria-label="Close" @onclick="HideModal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p style="height: 200px; overflow-y: scroll;">
|
||||
<h4 style="display: inline;"><a href="@_package.ProductUrl" target="_new">@_package.Name</a></h4><br />
|
||||
@SharedLocalizer["Search.By"]: <strong><a href="@_package.OwnerUrl" target="new">@_package.Owner</a></strong><br />
|
||||
@(_package.Description.Length > 400 ? (_package.Description.Substring(0, 400) + "...") : _package.Description)<br />
|
||||
<strong>@(String.Format("{0:n0}", _package.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||
@SharedLocalizer["Search.Released"]: <strong>@_package.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||
@SharedLocalizer["Search.Version"]: <strong>@_package.Version</strong>
|
||||
@((MarkupString)(!string.IsNullOrEmpty(_package.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(_package.PackageUrl).Host + "</strong>" : ""))
|
||||
<br /><br />
|
||||
@if (!string.IsNullOrEmpty(_package.License))
|
||||
{
|
||||
@((MarkupString)_package.License.Replace("\n", "<br />"))
|
||||
}
|
||||
else
|
||||
{
|
||||
@SharedLocalizer["License Not Specified"]
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code {
|
||||
private List<Language> _languages;
|
||||
private List<Package> _packages;
|
||||
private Package _package;
|
||||
private bool _install = false;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
|
@ -49,64 +106,109 @@ else
|
|||
{
|
||||
_languages = await LanguageService.GetLanguagesAsync(PageState.Site.SiteId, Constants.ClientId);
|
||||
|
||||
var cultures = await LocalizationService.GetCulturesAsync();
|
||||
var culture = cultures.First(c => c.Name.Equals(Constants.DefaultCulture));
|
||||
var cultures = await LocalizationService.GetCulturesAsync(false);
|
||||
var culture = cultures.First(c => c.Name.Equals(Constants.DefaultCulture));
|
||||
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_packages = await PackageService.GetPackagesAsync("translation");
|
||||
}
|
||||
}
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
_packages = await PackageService.GetPackagesAsync("translation");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteLanguage(Language language)
|
||||
{
|
||||
try
|
||||
{
|
||||
await LanguageService.DeleteLanguageAsync(language.LanguageId);
|
||||
await logger.LogInformation("Language Deleted {Language}", language);
|
||||
private async Task DeleteLanguage(Language language)
|
||||
{
|
||||
try
|
||||
{
|
||||
await LanguageService.DeleteLanguageAsync(language.LanguageId);
|
||||
await logger.LogInformation("Language Deleted {Language}", language);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Language {Language} {Error}", language, ex.Message);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Deleting Language {Language} {Error}", language, ex.Message);
|
||||
|
||||
AddModuleMessage(Localizer["Error.Language.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
AddModuleMessage(Localizer["Error.Language.Delete"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private bool UpgradeAvailable(string code, string version)
|
||||
{
|
||||
var upgradeavailable = false;
|
||||
if (_packages != null && version != null)
|
||||
{
|
||||
private string TranslationAvailable(string code, string version)
|
||||
{
|
||||
if (_packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == (Constants.PackageId + "." + code)).FirstOrDefault();
|
||||
if (package != null)
|
||||
{
|
||||
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) == 0) &&
|
||||
(Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
|
||||
}
|
||||
{
|
||||
// package version needs to match current framework version
|
||||
if (Version.Parse(package.Version).CompareTo(Version.Parse(Constants.Version)) == 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(version))
|
||||
{
|
||||
return "install";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||
{
|
||||
return "upgrade";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
return upgradeavailable;
|
||||
}
|
||||
private async Task GetPackage(string code)
|
||||
{
|
||||
try
|
||||
{
|
||||
_package = await PackageService.GetPackageAsync(Constants.PackageId + "." + code, Constants.Version);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Getting Package {PackageId} {Version}", Constants.PackageId + "." + code, Constants.Version);
|
||||
AddModuleMessage(Localizer["Error.Translation.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DownloadLanguage(string code)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(Constants.PackageId + "." + code, Constants.Version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Translation Downloaded {Code} {Version}", code, Constants.Version);
|
||||
await PackageService.InstallPackagesAsync();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Language.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Downloading Translation {Code} {Version} {Error}", code, Constants.Version, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Language.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
private async Task DownloadPackage()
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Language Package {Name} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||
AddModuleMessage(Localizer["Success.Language.Download"], MessageType.Success);
|
||||
_package = null;
|
||||
_install = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Downloading Translation {Name} {Version}", _package.PackageId, _package.Version);
|
||||
AddModuleMessage(Localizer["Error.Language.Download"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
private void HideModal()
|
||||
{
|
||||
_package = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private async Task InstallTranslations()
|
||||
{
|
||||
try
|
||||
{
|
||||
await PackageService.InstallPackagesAsync();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Translation.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
_install = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Installing Translations");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,29 +108,30 @@
|
|||
<Header>
|
||||
<th>@SharedLocalizer["Name"]</th>
|
||||
<th>@Localizer["Code"]</th>
|
||||
<th>@Localizer["Version"]</th>
|
||||
<th style="width: 1px;">@Localizer["Version"]</th>
|
||||
<th style="width: 1px;"> </th>
|
||||
</Header>
|
||||
<Row>
|
||||
<td>@context.Name</td>
|
||||
<td>@context.Code</td>
|
||||
<td>@context.Version</td>
|
||||
<td>@((string.IsNullOrEmpty(context.Version)) ? "---" : context.Version)</td>
|
||||
<td>
|
||||
@if (context.IsDefault)
|
||||
@switch (TranslationAvailable(_packagename + "." + context.Code, context.Version))
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Download"]</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UpgradeAvailable(_packagename + "." + context.Code, context.Version))
|
||||
{
|
||||
<button type="button" class="btn btn-primary" @onclick=@(async () => await DownloadPackage(_packagename + "." + context.Code))>@SharedLocalizer["Upgrade"]</button>
|
||||
}
|
||||
case "install":
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Download"]</button>
|
||||
break;
|
||||
case "upgrade":
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await GetPackage(_packagename + "." + context.Code))>@SharedLocalizer["Upgrade"]</button>
|
||||
break;
|
||||
}
|
||||
</td>
|
||||
</Row>
|
||||
</Pager>
|
||||
<button type="button" class="btn btn-success" @onclick="InstallTranslations">@SharedLocalizer["Install"]</button>
|
||||
@if (_install)
|
||||
{
|
||||
<button type="button" class="btn btn-success" @onclick="InstallTranslations">@SharedLocalizer["Install"]</button>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -143,7 +144,7 @@
|
|||
</TabPanel>
|
||||
</TabStrip>
|
||||
|
||||
@if (_productname != "")
|
||||
@if (_package != null)
|
||||
{
|
||||
<div class="app-actiondialog">
|
||||
<div class="modal" tabindex="-1" role="dialog">
|
||||
|
@ -155,10 +156,17 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<p style="height: 200px; overflow-y: scroll;">
|
||||
<h3>@_productname</h3>
|
||||
@if (!string.IsNullOrEmpty(_packagelicense))
|
||||
<h4 style="display: inline;"><a href="@_package.ProductUrl" target="_new">@_package.Name</a></h4><br />
|
||||
@SharedLocalizer["Search.By"]: <strong><a href="@_package.OwnerUrl" target="new">@_package.Owner</a></strong><br />
|
||||
@(_package.Description.Length > 400 ? (_package.Description.Substring(0, 400) + "...") : _package.Description)<br />
|
||||
<strong>@(String.Format("{0:n0}", _package.Downloads))</strong> @SharedLocalizer["Search.Downloads"] |
|
||||
@SharedLocalizer["Search.Released"]: <strong>@_package.ReleaseDate.ToString("MMM dd, yyyy")</strong> |
|
||||
@SharedLocalizer["Search.Version"]: <strong>@_package.Version</strong>
|
||||
@((MarkupString)(!string.IsNullOrEmpty(_package.PackageUrl) ? " | " + SharedLocalizer["Search.Source"] + ": <strong>" + new Uri(_package.PackageUrl).Host + "</strong>" : ""))
|
||||
<br /><br />
|
||||
@if (!string.IsNullOrEmpty(_package.License))
|
||||
{
|
||||
@((MarkupString)_packagelicense)
|
||||
@((MarkupString)_package.License.Replace("\n", "<br />"))
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -167,7 +175,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadPackage(_packageid))>@SharedLocalizer["Accept"]</button>
|
||||
<button type="button" class="btn btn-success" @onclick="DownloadPackage">@SharedLocalizer["Accept"]</button>
|
||||
<button type="button" class="btn btn-secondary" @onclick="HideModal">@SharedLocalizer["Cancel"]</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -203,9 +211,8 @@
|
|||
|
||||
private List<Package> _packages;
|
||||
private List<Language> _languages;
|
||||
private string _productname = "";
|
||||
private string _packagelicense = "";
|
||||
private string _packageid = "";
|
||||
private Package _package;
|
||||
private bool _install = false;
|
||||
|
||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
|
||||
|
||||
|
@ -297,24 +304,31 @@
|
|||
|
||||
private void HideModal()
|
||||
{
|
||||
_productname = "";
|
||||
_packagelicense = "";
|
||||
_package = null;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private bool UpgradeAvailable(string packagename, string version)
|
||||
private string TranslationAvailable(string packagename, string version)
|
||||
{
|
||||
var upgradeavailable = false;
|
||||
if (_packages != null)
|
||||
{
|
||||
var package = _packages.Where(item => item.PackageId == packagename).FirstOrDefault();
|
||||
if (package != null)
|
||||
{
|
||||
upgradeavailable = (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0);
|
||||
if (string.IsNullOrEmpty(version))
|
||||
{
|
||||
return "install";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Version.Parse(package.Version).CompareTo(Version.Parse(version)) > 0)
|
||||
{
|
||||
return "upgrade";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return upgradeavailable;
|
||||
return "";
|
||||
}
|
||||
|
||||
private async Task GetPackage(string packagename)
|
||||
|
@ -322,16 +336,7 @@
|
|||
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
||||
try
|
||||
{
|
||||
var package = await PackageService.GetPackageAsync(packagename, version);
|
||||
if (package != null)
|
||||
{
|
||||
_productname = package.Name;
|
||||
if (!string.IsNullOrEmpty(package.License))
|
||||
{
|
||||
_packagelicense = package.License.Replace("\n", "<br />");
|
||||
}
|
||||
_packageid = package.PackageId;
|
||||
}
|
||||
_package = await PackageService.GetPackageAsync(packagename, version);
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -341,16 +346,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
private async Task DownloadPackage(string packagename)
|
||||
private async Task DownloadPackage()
|
||||
{
|
||||
try
|
||||
{
|
||||
var version = _packages.Where(item => item.PackageId == packagename).FirstOrDefault().Version;
|
||||
await PackageService.DownloadPackageAsync(packagename, version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", packagename, version);
|
||||
await PackageService.DownloadPackageAsync(_package.PackageId, _package.Version, Constants.PackagesFolder);
|
||||
await logger.LogInformation("Package {PackageId} {Version} Downloaded Successfully", _package.PackageId, _package.Version);
|
||||
AddModuleMessage(Localizer["Success.Translation.Download"], MessageType.Success);
|
||||
_productname = "";
|
||||
_packagelicense = "";
|
||||
_package = null;
|
||||
_install = true;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -366,6 +370,8 @@
|
|||
{
|
||||
await PackageService.InstallPackagesAsync();
|
||||
AddModuleMessage(string.Format(Localizer["Success.Translation.Install"], NavigateUrl("admin/system")), MessageType.Success);
|
||||
_install = false;
|
||||
StateHasChanged();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
|
@ -444,7 +444,7 @@
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
|
||||
AddModuleMessage(Localizer["Error.Theme.LoadPane"], MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ using Microsoft.JSInterop;
|
|||
using Oqtane.Documentation;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.UI;
|
||||
|
||||
namespace Oqtane.Client
|
||||
|
@ -56,7 +57,11 @@ namespace Oqtane.Client
|
|||
RegisterClientStartups(assembly, builder.Services);
|
||||
}
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
var host = builder.Build();
|
||||
|
||||
await SetCultureFromLocalizationCookie(host.Services);
|
||||
|
||||
await host.RunAsync();
|
||||
}
|
||||
|
||||
private static async Task LoadClientAssemblies(HttpClient http, IServiceProvider serviceProvider)
|
||||
|
@ -220,7 +225,7 @@ namespace Oqtane.Client
|
|||
var localizationCookie = await interop.GetCookie(CookieRequestCultureProvider.DefaultCookieName);
|
||||
var culture = CookieRequestCultureProvider.ParseCookieValue(localizationCookie)?.UICultures?[0].Value;
|
||||
var localizationService = serviceProvider.GetRequiredService<ILocalizationService>();
|
||||
var cultures = await localizationService.GetCulturesAsync();
|
||||
var cultures = await localizationService.GetCulturesAsync(false);
|
||||
|
||||
if (culture == null || !cultures.Any(c => c.Name.Equals(culture, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
|
|
|
@ -117,45 +117,30 @@
|
|||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="The Only Supported Culture That Has Been Defined Is English" xml:space="preserve">
|
||||
<value>The Only Supported Culture That Has Been Defined Is English</value>
|
||||
</data>
|
||||
<data name="Error.Language.Add" xml:space="preserve">
|
||||
<value>Error Adding Language</value>
|
||||
</data>
|
||||
<data name="Translated.HelpText" xml:space="preserve">
|
||||
<value>Specify If You Wish To Select Languages That Have Translations Installed</value>
|
||||
</data>
|
||||
<data name="Name.HelpText" xml:space="preserve">
|
||||
<value>Name Of The Langauage</value>
|
||||
</data>
|
||||
<data name="IsDefault.HelpText" xml:space="preserve">
|
||||
<value>Indicates Whether Or Not This Language Is The Default For The Site</value>
|
||||
</data>
|
||||
<data name="Translated.Text" xml:space="preserve">
|
||||
<value>Translated?</value>
|
||||
</data>
|
||||
<data name="Name.Text" xml:space="preserve">
|
||||
<value>Name:</value>
|
||||
</data>
|
||||
<data name="IsDefault.Text" xml:space="preserve">
|
||||
<value>Default?</value>
|
||||
</data>
|
||||
<data name="AllLanguages" xml:space="preserve">
|
||||
<value>All The Installed Languages Have Been Added.</value>
|
||||
</data>
|
||||
<data name="Error.Language.Download" xml:space="preserve">
|
||||
<value>Error Downloading Translation</value>
|
||||
</data>
|
||||
<data name="OnlyEnglish" xml:space="preserve">
|
||||
<value>The Only Installed Language Is English</value>
|
||||
</data>
|
||||
<data name="Success.Language.Download" xml:space="preserve">
|
||||
<value>Translation Downloaded Successfully. Click Install To Complete Installation.</value>
|
||||
</data>
|
||||
<data name="Success.Language.Install" xml:space="preserve">
|
||||
<value>Translations Installed Successfully. You Must <a href={0}>Restart</a> Your Application To Apply These Changes.</value>
|
||||
</data>
|
||||
<data name="Search.NoResults" xml:space="preserve">
|
||||
<value>No Translations Match The Criteria Provided Or Package Service Is Disabled</value>
|
||||
</data>
|
||||
<data name="Download.Heading" xml:space="preserve">
|
||||
<value>Translations</value>
|
||||
</data>
|
||||
<data name="LanguageUpload.HelpText" xml:space="preserve">
|
||||
<value>Upload one or more translation packages. Once they are uploaded click Install to complete the installation.</value>
|
||||
</data>
|
||||
|
|
|
@ -13,6 +13,6 @@ namespace Oqtane.Services
|
|||
/// Returns a collection of supported cultures
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<IEnumerable<Culture>> GetCulturesAsync();
|
||||
Task<IEnumerable<Culture>> GetCulturesAsync(bool installed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,6 @@ namespace Oqtane.Services
|
|||
|
||||
private string Apiurl => CreateApiUrl("Localization");
|
||||
|
||||
public async Task<IEnumerable<Culture>> GetCulturesAsync() => await GetJsonAsync<IEnumerable<Culture>>(Apiurl);
|
||||
public async Task<IEnumerable<Culture>> GetCulturesAsync(bool installed) => await GetJsonAsync<IEnumerable<Culture>>($"{Apiurl}?installed={installed}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace Oqtane.Controllers
|
|||
var code = Path.GetFileName(Path.GetDirectoryName(file));
|
||||
if (!languages.Any(item => item.Code == code))
|
||||
{
|
||||
languages.Add(new Language { Code = code, Name = CultureInfo.GetCultureInfo(code).DisplayName, Version = FileVersionInfo.GetVersionInfo(file).FileVersion, IsDefault = false });
|
||||
languages.Add(new Language { Code = code, Name = CultureInfo.GetCultureInfo(code).DisplayName, Version = FileVersionInfo.GetVersionInfo(file).ProductVersion, IsDefault = false });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ namespace Oqtane.Controllers
|
|||
var code = Path.GetFileName(Path.GetDirectoryName(file));
|
||||
if (languages.Any(item => item.Code == code))
|
||||
{
|
||||
languages.Single(item => item.Code == code).Version = FileVersionInfo.GetVersionInfo(file).FileVersion;
|
||||
languages.Single(item => item.Code == code).Version = FileVersionInfo.GetVersionInfo(file).ProductVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,18 @@ namespace Oqtane.Controllers
|
|||
|
||||
// GET: api/localization
|
||||
[HttpGet()]
|
||||
public IEnumerable<Culture> Get()
|
||||
public IEnumerable<Culture> Get(bool installed)
|
||||
{
|
||||
var cultures = _localizationManager.GetSupportedCultures().Select(c => new Culture
|
||||
string[] culturecodes;
|
||||
if (installed)
|
||||
{
|
||||
culturecodes = _localizationManager.GetInstalledCultures();
|
||||
}
|
||||
else
|
||||
{
|
||||
culturecodes = _localizationManager.GetSupportedCultures();
|
||||
}
|
||||
var cultures = culturecodes.Select(c => new Culture
|
||||
{
|
||||
Name = CultureInfo.GetCultureInfo(c).Name,
|
||||
DisplayName = CultureInfo.GetCultureInfo(c).DisplayName,
|
||||
|
|
Loading…
Reference in New Issue
Block a user