Instantiate just one I18n instance to pass to all controllers

This commit is contained in:
Robbie Antenesse 2019-09-16 12:32:53 -06:00
parent eda8e83d07
commit c4f657b7b4
11 changed files with 62 additions and 64 deletions

View File

@ -1,10 +1,9 @@
import { I18n } from '../i18n';
export class ViewController {
constructor(state, viewName, defaultState = {}) {
constructor(state, i18n, viewName, defaultState = {}) {
// Store the global app state so it's accessible but out of the way.
this.appState = state;
this.i18n = new I18n(this.appState);
this.i18n = i18n;
this.i18n.__ = this.i18n.__.bind(i18n); // Allow pulling out just the `__` function for shortened translation declaration.
// Give this view its own state within the appState.
if (!this.appState.viewStates.hasOwnProperty(viewName)) {

View File

@ -1,10 +1,10 @@
import { ViewController } from '../controller';
export class HomeController extends ViewController {
constructor(state) {
constructor(state, i18n) {
// Super passes state, view name, and default state to ViewController,
// which stores state in this.appState and the view controller's state to this.state
super(state, 'home', {
super(state, i18n, 'home', {
recentReviews: [],
recentUpdates: [],
});

View File

@ -4,8 +4,8 @@ import { HomeController } from './controller'; // The controller for this view,
import { loggedOutView } from './loggedOut';
// This is the view function that is exported and used in the view manager.
export const homeView = (state, emit) => {
const controller = new HomeController(state);
export const homeView = (state, emit, i18n) => {
const controller = new HomeController(state, i18n);
// Returning an array in a view allows non-shared parent HTML elements.
// This one doesn't have the problem right now, but it's good to remember.

View File

@ -1,11 +1,11 @@
import html from 'choo/html';
export const loggedOutView = (homeController, emit) => {
const { i18n } = homeController;
const { __ } = homeController.i18n;
return [
html`<section>
<h2>${i18n.__('home.logged_out_subtitle')}</h2>
<h2>${__('home.logged_out_subtitle')}</h2>
<article class="flex one three-500">
<div>
<div class="card">
@ -15,7 +15,7 @@ export const loggedOutView = (homeController, emit) => {
</span>
</header>
<footer>
${i18n.__('home.logged_out_track_books')}
${__('home.logged_out_track_books')}
</footer>
</div>
</div>
@ -27,7 +27,7 @@ export const loggedOutView = (homeController, emit) => {
</span>
</header>
<footer>
${i18n.__('home.logged_out_share_friends')}
${__('home.logged_out_share_friends')}
</footer>
</div>
</div>
@ -39,20 +39,20 @@ export const loggedOutView = (homeController, emit) => {
</span>
</header>
<footer>
${i18n.__('home.logged_out_read_rate')}
${__('home.logged_out_read_rate')}
</footer>
</div>
</div>
</article>
</section>`,
html`<section>
<h2>${i18n.__('home.logged_out_community_header')}</h2>
<h2>${__('home.logged_out_community_header')}</h2>
<div class="flex one two-700">
<div>
<div class="card">
<header>
<h3>${i18n.__('home.logged_out_recent_reviews')}</h3>
<button class="small pseudo pull-right tooltip-left" data-tooltip=${i18n.__('interaction.reload')}>
<h3>${__('home.logged_out_recent_reviews')}</h3>
<button class="small pseudo pull-right tooltip-left" data-tooltip=${__('interaction.reload')}>
<i class="icon-loading"></i><!--/* This needs to get updated to a reload icon */-->
</button>
</header>
@ -64,8 +64,8 @@ export const loggedOutView = (homeController, emit) => {
<div>
<div class="card">
<header>
<h3>${i18n.__('home.logged_out_recent_updates')}</h3>
<button class="small pseudo pull-right tooltip-left" data-tooltip=${i18n.__('interaction.reload')}>
<h3>${__('home.logged_out_recent_updates')}</h3>
<button class="small pseudo pull-right tooltip-left" data-tooltip=${__('interaction.reload')}>
<i class="icon-loading"></i><!--/* This needs to get updated to a reload icon */-->
</button>
</header>
@ -77,7 +77,7 @@ export const loggedOutView = (homeController, emit) => {
</div>
</section>`,
html`<section class="center-align">
<a href="/login" class="large success button">${i18n.__('home.logged_out_join_now')}</a>
<a href="/login" class="large success button">${__('home.logged_out_join_now')}</a>
</section>`,
];
}

View File

@ -1,10 +1,10 @@
import { ViewController } from '../controller';
export class LoginController extends ViewController {
constructor(state) {
constructor(state, i18n) {
// Super passes state, view name, and default state to ViewController,
// which stores state in this.appState and the view controller's state to this.state
super(state, 'login', {});
super(state, i18n, 'login', {});
// If using controller methods in an input's onchange or onclick instance,
// either bind the class's 'this' instance to the method first...

View File

@ -2,9 +2,9 @@ import html from 'choo/html';
import { LoginController } from './controller';
export const loginView = (state, emit) => {
const controller = new LoginController(state);
const { i18n } = controller;
export const loginView = (state, emit, i18n) => {
const controller = new LoginController(state, i18n);
const { __ } = controller.i18n;
return html`<section>
@ -12,48 +12,48 @@ export const loginView = (state, emit) => {
<div>
<article class="card">
<header>
<h3>${i18n.__('login.log_in')}</h3>
<h3>${__('login.log_in')}</h3>
</header>
<footer>
<label>
<span>${i18n.__('login.email')}</span>
<span>${__('login.email')}</span>
<input type="email" name="email">
</label>
<label>
<span>${i18n.__('login.password')}</span>
<span>${__('login.password')}</span>
<input type="password" name="password">
</label>
<input type="submit" value="${i18n.__('login.login_button')}">
<input type="submit" value="${__('login.login_button')}">
</footer>
</article>
</div>
<div>
<article class="card">
<header>
<h3>${i18n.__('login.create_account')}</h3>
<h3>${__('login.create_account')}</h3>
</header>
<footer>
<label>
<span>${i18n.__('login.email')}</span>
<span>${__('login.email')}</span>
<input type="email" name="new_email">
</label>
<label>
<span>${i18n.__('login.password')}</span>
<span>${__('login.password')}</span>
<input type="password" name="new_password">
</label>
<label>
<span>${i18n.__('login.confirm_password')}</span>
<span>${__('login.confirm_password')}</span>
<input type="password" name="confirm_password">
</label>
<label>
<span>${i18n.__('login.username')}</span>
<span>${__('login.username')}</span>
<input type="text" name="new_username">
</label>
<label>
<span>${i18n.__('login.display_name')}</span>
<span>${__('login.display_name')}</span>
<input type="text" name="new_displayname">
</label>
<input type="submit" class="success" value="${i18n.__('login.create_account_button')}">
<input type="submit" class="success" value="${__('login.create_account_button')}">
</footer>
</article>
</div>

View File

@ -8,22 +8,22 @@ import { loginView } from './login';
import { searchView } from './search';
export const viewManager = (state, emit) => {
const i18n = new I18n(state);
const i18n = new I18n(state); // Global I18n class passed to all views
// In viewManager all we are doing is checking the app's state
// and passing the state and emit to the relevant view.
let htmlContent = html`<div>loading</div>`;
switch (state.params.page) {
case 'home':
default: {
htmlContent = homeView(state, emit);
htmlContent = homeView(state, emit, i18n);
break;
}
case 'login': {
htmlContent = loginView(state, emit);
htmlContent = loginView(state, emit, i18n);
break;
}
case 'search': {
htmlContent = searchView(state, emit);
htmlContent = searchView(state, emit, i18n);
break;
}
}

View File

@ -3,7 +3,7 @@ import html from 'choo/html';
import { starRating } from './starRating';
export const reviewCard = (controller, review) => {
const { i18n } = controller;
const { __ } = controller.i18n;
return html`<article class="card">
<header style="font-weight:normal;">
@ -16,7 +16,7 @@ export const reviewCard = (controller, review) => {
${review.review}
</p>
</div>
<span class="tooltip-top" data-tooltip=${i18n.__('interaction.heart')}>
<span class="tooltip-top" data-tooltip=${__('interaction.heart')}>
<button class="pseudo">
<i class="icon-heart-outline"></i>
</button>

View File

@ -1,10 +1,10 @@
import { ViewController } from '../controller';
export class SearchController extends ViewController {
constructor(state) {
constructor(state, i18n) {
// Super passes state, view name, and default state to ViewController,
// which stores state in this.appState and the view controller's state to this.state
super(state, 'search', {
super(state, i18n, 'search', {
lastSearch: undefined,
done: false,
results: {

View File

@ -4,12 +4,11 @@ import { SearchController } from './controller'; // The controller for this vie
import { resultDetails } from './resultDetails';
// This is the view function that is exported and used in the view manager.
export const searchView = (state, emit) => {
const controller = new SearchController(state);
const { i18n } = controller;
export const searchView = (state, emit, i18n) => {
const controller = new SearchController(state, i18n);
const { __ } = controller.i18n;
if (controller.state.lastSearch !== state.query.for) {
console.log('searching!');
controller.search().then(() => {
emit('render');
});
@ -19,7 +18,7 @@ export const searchView = (state, emit) => {
// This one doesn't have the problem right now, but it's good to remember.
return [
html`<section>
<h1 class="title">${i18n.__('search.header')}</h1>
<h1 class="title">${__('search.header')}</h1>
<article>
${controller.doneSearching ? null : html`<h2><i class="icon-loading animate-spin"></i></h2>`}
@ -27,7 +26,7 @@ export const searchView = (state, emit) => {
${controller.results.works < 1
? null
: [
html`<h2>${i18n.__('search.books_header')}</h2>`,
html`<h2>${__('search.books_header')}</h2>`,
controller.results.works.map(result => {
return html`<div class="flex search-result">
<div class="two-third-800 half-500">
@ -44,7 +43,7 @@ export const searchView = (state, emit) => {
${controller.results.series.length < 1
? null
: [
html`<h2>${i18n.__('search.series_header')}</h2>`,
html`<h2>${__('search.series_header')}</h2>`,
controller.results.series.map(result => {
return html`<div class="flex search-result">
<div class="two-third-800 half-500">
@ -52,9 +51,9 @@ export const searchView = (state, emit) => {
${result.description ? html`<h4 class="subtitle">${result.description}</h4>` : null}
</div>
<div class="third-800 half-500">
<span class="tooltip-left" data-tooltip=${i18n.__('search.see_details_tooltip')}>
<span class="tooltip-left" data-tooltip=${__('search.see_details_tooltip')}>
<a class="small pseudo button" href=${result.link} target="_blank">
${i18n.__('search.see_inventaire_details')}
${__('search.see_inventaire_details')}
</a>
</span>
</div>
@ -65,7 +64,7 @@ export const searchView = (state, emit) => {
${controller.results.humans.length < 1
? null
: [
html`<h2>${i18n.__('search.people_header')}</h2>`,
html`<h2>${__('search.people_header')}</h2>`,
controller.results.humans.map(result => {
return html`<div class="flex search-result">
<div class="sixth">
@ -76,9 +75,9 @@ export const searchView = (state, emit) => {
${result.description ? html`<h4 class="subtitle">${result.description}</h4>` : null}
</div>
<div class="third-800">
<span class="tooltip-left" data-tooltip=${i18n.__('search.see_details_tooltip')}>
<span class="tooltip-left" data-tooltip=${__('search.see_details_tooltip')}>
<a class="small pseudo button" href=${result.link} target="_blank">
${i18n.__('search.see_inventaire_details')}
${__('search.see_inventaire_details')}
</a>
</span>
</div>

View File

@ -5,14 +5,14 @@ import { starRating } from '../partials/starRating';
import { modal } from '../partials/modal';
export const resultDetails = (searchController, result, emit = () => {}) => {
const { i18n } = searchController;
const { __ } = searchController.i18n;
const modalId = `result_${result.uri}`;
const buttonHTML = html`<label for=${modalId} class="pseudo button">
<span data-tooltip="${i18n.__('interaction.average_rating')}: ${result.averageRating}">
<span data-tooltip="${__('interaction.average_rating')}: ${result.averageRating}">
${starRating(result.averageRating)}
</span>
<span style="margin-left:10px;" data-tooltip=${i18n.__('interaction.reviews_written')}>
<span style="margin-left:10px;" data-tooltip=${__('interaction.reviews_written')}>
<span style="margin-right:8px;"><i class="icon-chat"></i></span>
<span>${result.numberOfReviews}</span>
</span>
@ -55,7 +55,7 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
}
</div>
<div class="two-third-700">
<h4>${i18n.__('interaction.average_rating')}</h4>
<h4>${__('interaction.average_rating')}</h4>
<span data-tooltip="${result.averageRating}">${starRating(result.averageRating)}</span>
<div class="flex">
@ -66,7 +66,7 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
<a href="/book/${result.uri}" class="small button">
<span style="margin-right:8px;"><i class="icon-chat"></i></span>
<span>${result.numberOfReviews}</span>
<span>${i18n.__('search.see_interaction_details')}</span>
<span>${__('search.see_interaction_details')}</span>
</a>
</div>
</div>
@ -76,16 +76,16 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
</div>
<div class="sixth-700">
<p>
<span data-tooltip=${i18n.__('interaction.add')}>
<span data-tooltip=${__('interaction.add')}>
<button class="success">
<i class="icon-plus"></i>
</button>
</span>
</p>
<p>
<span data-tooltip=${i18n.__('search.see_details_tooltip')}>
<span data-tooltip=${__('search.see_details_tooltip')}>
<a class="small pseudo button" href=${result.link} target="_blank">
${i18n.__('search.see_book_details')}
${__('search.see_book_details')}
</a>
</span>
</p>