Switched to using ASP.Net Core localization.

This commit is contained in:
Harrison Deng 2022-04-25 00:43:53 -05:00
parent 5f2f648eaa
commit 0488df2ed1
8 changed files with 62 additions and 125 deletions

View File

@ -1,7 +1,7 @@
@page @page
@using Props.Services.Content @using Microsoft.AspNetCore.Mvc.Localization
@model IndexModel @model IndexModel
@inject ITextualManager<IndexModel> ContentManager @inject IViewLocalizer Localizer
@{ @{
ViewData["Title"] = "Home page"; ViewData["Title"] = "Home page";
} }
@ -14,7 +14,7 @@
<div class="text-center px-3 my-2 concise"> <div class="text-center px-3 my-2 concise">
<h1 class="my-2 display-1">Props</h1> <h1 class="my-2 display-1">Props</h1>
<p> <p>
@ContentManager.Json.description @Localizer["description"]
</p> </p>
</div> </div>
</section> </section>
@ -22,7 +22,7 @@
<section class="jumbotron sub"> <section class="jumbotron sub">
<div class="container d-flex flex-column align-items-center py-2 concise"> <div class="container d-flex flex-column align-items-center py-2 concise">
<i class="bi bi-search" style="font-size: 5rem;"></i> <i class="bi bi-search" style="font-size: 5rem;"></i>
<h2 class="mb-3 mt-4">@ContentManager.Json.help.title</h2> <h2 class="mb-3 mt-4">@Localizer["help.title"]</h2>
<form class="concise my-4"> <form class="concise my-4">
<div class="input-group"> <div class="input-group">
<input type="text" class="form-control" placeholder="What are you looking for?" aria-label="Search" <input type="text" class="form-control" placeholder="What are you looking for?" aria-label="Search"
@ -31,10 +31,10 @@
</div> </div>
</form> </form>
<p class="text-center"> <p class="text-center">
@ContentManager.Json.help.searchIntroduction @Localizer["help.searchIntroduction"]
</p> </p>
<p class="text-center"> <p class="text-center">
@ContentManager.Json.help.additionalInfo @Localizer["help.additionalInfo"]
</p> </p>
</div> </div>
</section> </section>
@ -42,7 +42,7 @@
<section class="container d-flex flex-column align-items-center my-3 less-concise"> <section class="container d-flex flex-column align-items-center my-3 less-concise">
<h2 class="mb-3 mt-4">Our Mission</h2> <h2 class="mb-3 mt-4">Our Mission</h2>
<p class="text-center"> <p class="text-center">
@ContentManager.Json.mission @Localizer["mission"]
</p> </p>
</section> </section>
@ -52,25 +52,55 @@
<div class="less-concise d-flex flex-column align-items-center"> <div class="less-concise d-flex flex-column align-items-center">
<h2 class="mb-3 mt-4">Features</h2> <h2 class="mb-3 mt-4">Features</h2>
<p class="center"> <p class="center">
@ContentManager.Json.features.description @Localizer["features.description"]
</p> </p>
</div> </div>
<div style="width: 100%;" data-simplebar> <div style="width: 100%;" data-simplebar>
<div class="row px-2 py-3 flex-nowrap"> <div class="row px-2 py-3 flex-nowrap">
@foreach (dynamic feature in ContentManager.Json.features.list) <div class="card mx-2" style="width: 32rem;">
{ <div class="card-body">
<div class="card mx-2" style="width: 32rem;"> <h5 class="card-title">@Localizer["feature.shoppingList.title"]</h5>
<div class="card-body"> <h6 class="card-subtitle mb-3 text-muted">
<h5 class="card-title">@feature.title</h5> <slot name="subtitle">@Localizer["feature.shoppingList.subtitle"]</slot>
<h6 class="card-subtitle mb-3 text-muted"> </h6>
<slot name="subtitle">@feature.subtitle</slot> <p class="card-text">
</h6> @Localizer["feature.shoppingList.text"]
<p class="card-text"> </p>
@feature.text
</p>
</div>
</div> </div>
} </div>
<div class="card mx-2" style="width: 32rem;">
<div class="card-body">
<h5 class="card-title">@Localizer["feature.productComparison.title"]</h5>
<h6 class="card-subtitle mb-3 text-muted">
<slot name="subtitle">@Localizer["feature.productComparison.subtitle"]</slot>
</h6>
<p class="card-text">
@Localizer["feature.productComparison.text"]
</p>
</div>
</div>
<div class="card mx-2" style="width: 32rem;">
<div class="card-body">
<h5 class="card-title">@Localizer["feature.autoSearch.title"]</h5>
<h6 class="card-subtitle mb-3 text-muted">
<slot name="subtitle">@Localizer["feature.autoSearch.subtitle"]</slot>
</h6>
<p class="card-text">
@Localizer["feature.autoSearch.text"]
</p>
</div>
</div>
<div class="card mx-2" style="width: 32rem;">
<div class="card-body">
<h5 class="card-title">@Localizer["feature.sharing.title"]</h5>
<h6 class="card-subtitle mb-3 text-muted">
<slot name="subtitle">@Localizer["feature.sharing.subtitle"]</slot>
</h6>
<p class="card-text">
@Localizer["feature.sharing.text"]
</p>
</div>
</div>
</div> </div>
</div> </div>
</section> </section>

View File

@ -1,7 +1,7 @@
@page @page
@using Props.Services.Content @using Microsoft.AspNetCore.Mvc.Localization
@model SearchModel @model SearchModel
@inject ITextualManager<SearchModel> ContentManager @inject IViewLocalizer Localizer
@{ @{
ViewData["Title"] = "Search"; ViewData["Title"] = "Search";
@ -236,10 +236,10 @@
<div class="multipage-title"> <div class="multipage-title">
<h1 class="display-2"><i class="bi bi-stopwatch"></i> Quick Picks</h1> <h1 class="display-2"><i class="bi bi-stopwatch"></i> Quick Picks</h1>
<template x-if="hasResults()"> <template x-if="hasResults()">
<p>@ContentManager.Json.quickPicks.searched</p> <p>@Localizer["quickPicks.searched"]</p>
</template> </template>
<template x-if="!hasResults()"> <template x-if="!hasResults()">
<p>@ContentManager.Json.quickPicks.prompt</p> <p>@Localizer["quickPicks.prompt"]</p>
</template> </template>
<hr class="less-concise"> <hr class="less-concise">
</div> </div>
@ -257,7 +257,7 @@
<template x-if="!hasResults()"> <template x-if="!hasResults()">
<div <div
class="text-center less-concise text-muted flex-grow-1 justify-content-center d-flex flex-column"> class="text-center less-concise text-muted flex-grow-1 justify-content-center d-flex flex-column">
<h2>@ContentManager.Json.notSearched</h2> <h2>@Localizer["notSearched"]</h2>
</div> </div>
</template> </template>
</div> </div>
@ -266,10 +266,10 @@
<div class="multipage-title"> <div class="multipage-title">
<h2><i class="bi bi-view-list"></i> Results</h2> <h2><i class="bi bi-view-list"></i> Results</h2>
<template x-if="hasResults()"> <template x-if="hasResults()">
<p>@ContentManager.Json.results.searched</p> <p>@Localizer["results.searched"]</p>
</template> </template>
<template x-if="!hasResults()"> <template x-if="!hasResults()">
<p>@ContentManager.Json.results.prompt</p> <p>@Localizer["results.prompt"]</p>
</template> </template>
<hr class="less-concise"> <hr class="less-concise">
</div> </div>
@ -280,7 +280,7 @@
<template x-if="!hasResults()"> <template x-if="!hasResults()">
<div <div
class="text-center less-concise text-muted flex-grow-1 justify-content-center d-flex flex-column"> class="text-center less-concise text-muted flex-grow-1 justify-content-center d-flex flex-column">
<h2>@ContentManager.Json.notSearched</h2> <h2>@Localizer["notSearched"]</h2>
</div> </div>
</template> </template>
</div> </div>
@ -290,10 +290,9 @@
<div class="less-concise text-muted flex-grow-1 justify-content-center d-flex flex-column"> <div class="less-concise text-muted flex-grow-1 justify-content-center d-flex flex-column">
<h1 class="display-3"><i class="bi bi-info-circle"></i> Get Started!</h1> <h1 class="display-3"><i class="bi bi-info-circle"></i> Get Started!</h1>
<ol> <ol>
@foreach (string instruction in ContentManager.Json.instructions) <li>@Localizer["instructions.type"]</li>
{ <li>@Localizer["instructions.configure"]</li>
<li>@instruction</li> <li>@Localizer["instructions.search"]</li>
}
</ol> </ol>
</div> </div>
</div> </div>

View File

@ -1,29 +0,0 @@
using System.IO;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
using Props.Options;
namespace Props.Services.Content
{
public class CachedTextualManager<TPage> : ITextualManager<TPage>
{
private dynamic data;
private readonly TextualOptions options;
private readonly string fileName;
dynamic ITextualManager<TPage>.Json
{
get
{
if (data == null) data = JValue.Parse(File.ReadAllText(Path.Combine(options.Dir, fileName)));
return data;
}
}
public CachedTextualManager(IConfiguration configuration)
{
this.options = configuration.GetSection(TextualOptions.Textual).Get<TextualOptions>();
this.fileName = typeof(TPage).Name.Replace("Model", "") + ".json";
}
}
}

View File

@ -1,8 +0,0 @@
namespace Props.Services.Content
{
public interface ITextualManager<out TModel>
{
// TODO: Replace this system with globalization and localization. See: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-6.0
dynamic Json { get; }
}
}

View File

@ -6,7 +6,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Props.Data; using Props.Data;
using Props.Models.User; using Props.Models.User;
using Props.Services.Content;
using Props.Services.Modules; using Props.Services.Modules;
using System; using System;
@ -47,7 +46,6 @@ namespace Props
.AddEntityFrameworkStores<ApplicationDbContext>(); .AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages(); services.AddRazorPages();
services.AddSingleton(typeof(ITextualManager<>), typeof(CachedTextualManager<>));
services.AddSingleton<IShopManager, ModularShopManager>(); services.AddSingleton<IShopManager, ModularShopManager>();
services.AddScoped<IMetricsManager, LiveMetricsManager>(); services.AddScoped<IMetricsManager, LiveMetricsManager>();
services.AddScoped<ISearchManager, LiveSearchManager>(); services.AddScoped<ISearchManager, LiveSearchManager>();

View File

@ -18,9 +18,6 @@
"Search": { "Search": {
"MaxResults": 100 "MaxResults": 100
}, },
"Textual": {
"Dir": "./textual"
},
"Metrics": { "Metrics": {
"MaxQueryWords": 4096, "MaxQueryWords": 4096,
"MaxProductListings": 1024 "MaxProductListings": 1024

View File

@ -1,34 +0,0 @@
{
"description": "Props is a community driven website meant to help with organizing your online component shopping experience. Create project component lists, search across multiple commonly used online retail stores and share your projects with rest of the community!",
"help": {
"title": "Getting Started",
"searchIntroduction": "Props is a site designed to help with the online project component shopping experience. Create project component lists and search across multiple commonly used online retail stores to find the ideal purchase.",
"additionalInfo": "Take advantage of our project component manager, where you can add detailed descriptions of what things are for, as well as overall project summaries."
},
"mission": "Our mission is to bring become digital project workshop for anyone who likes Do It Yourself (DIY), Internet Of Things (IOT), or really any project that needs a home for all the materials, ideas, and thoughts. We also strive to build a community of builders, crafters and creators in hopes that we can all learn from each other's projects.",
"features": {
"description": "Props strives to be a platform where people can find and organize the material they need to complete their projects. Our features are therefore tailored to the community helping each other, as well as smart tools to quickly compare different products from different stores.",
"list": [
{
"title": "Shopping List",
"subtitle": "We'll do it so you don't need to.",
"text": "We'll help you track the components you need. You can add descriptions, and mark things as purchased, or shipped at your convenience. You can even add components from stores that Props doesn't know about yet!"
},
{
"title": "Product Comparison",
"subtitle": "So many shops to look through...",
"text": "There's so many online retailers nowadays that it's becoming more and more work to check all of them for what you need. With us, we'll do the searching for you. All you need to do is decide if the shipping time, cost, ratings and reviews are suitable!"
},
{
"title": "Auto Listing Search",
"subtitle": "Need a starting point?",
"text": "Some project parts commonly used. We'll try and find these parts for you automatically. This means you can create a shopping list, and we'll try and the best fitting products for you based on your shopping list entries."
},
{
"title": "Share It!",
"subtitle": "Show off your work!",
"text": "Have a project that you're excited about? Want to tell all your friends? We'll help. Each of your projects has a privacy setting. You can have it publically listed, unlisted, or completely private. Short link included."
}
]
}
}

View File

@ -1,16 +0,0 @@
{
"instructions": [
"Type in the electronic component your looking for in the search bar above.",
"Optionally, hit the configure button to modify your search criteria. With an account, you can even create and save multiple search profiles known as \"search outlines\".",
"That's it! Hit search and we'll look far and wide for what you need!"
],
"quickPicks": {
"searched": "The cream of the crop!",
"prompt": "This is where we'll show you top listings so you can get back to working on your project!"
},
"results": {
"searched": "We searched far and wide. Here's what we found!",
"prompt": "This is were we'll display all the results we went through to show you the top. This is a good place to check if none of our quick picks cater to your needs."
},
"notSearched": "Nothing to show yet!"
}