Put i18n on server so it can free up frontend memory
This commit is contained in:
parent
2ccee904da
commit
0f9757f2c2
|
@ -41,6 +41,7 @@
|
||||||
"fastify-sequelize": "^1.0.4",
|
"fastify-sequelize": "^1.0.4",
|
||||||
"fastify-static": "^2.5.0",
|
"fastify-static": "^2.5.0",
|
||||||
"make-promises-safe": "^5.0.0",
|
"make-promises-safe": "^5.0.0",
|
||||||
|
"marked": "^0.7.0",
|
||||||
"mysql2": "^1.7.0",
|
"mysql2": "^1.7.0",
|
||||||
"node-fetch": "^2.6.0",
|
"node-fetch": "^2.6.0",
|
||||||
"pg": "^7.12.1",
|
"pg": "^7.12.1",
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
const fp = require('fastify-plugin');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const marked = require('marked');
|
||||||
|
|
||||||
|
async function plugin (fastify, opts, done) {
|
||||||
|
const i18n = {
|
||||||
|
available: [],
|
||||||
|
pages: {},
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const locales = fs.readdirSync(path.resolve(__dirname, './locales'));
|
||||||
|
locales
|
||||||
|
.filter(file => !file.split().every(letter => letter === '.')) // Filter out relative folders
|
||||||
|
.forEach(locale => {
|
||||||
|
try {
|
||||||
|
const ui = fs.readFileSync(path.resolve(__dirname, `./locales/${locale}/ui.json`)),
|
||||||
|
about = fs.readFileSync(path.resolve(__dirname, `./locales/${locale}/pages/about.md`)),
|
||||||
|
community = fs.readFileSync(path.resolve(__dirname, `./locales/${locale}/pages/community.md`));
|
||||||
|
|
||||||
|
i18n[locale] = JSON.parse(ui.toString());
|
||||||
|
|
||||||
|
i18n.available.push({
|
||||||
|
name: i18n[locale].name,
|
||||||
|
locale: i18n[locale].locale,
|
||||||
|
});
|
||||||
|
|
||||||
|
i18n.pages[locale] = {
|
||||||
|
about: marked(about.toString()),
|
||||||
|
community: marked(community.toString()),
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
console.error('Encountered a problem with locale.\n', ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the default language to English after parsing locales because it has the most coverage.
|
||||||
|
i18n.default = i18n.en;
|
||||||
|
} catch (ex) {
|
||||||
|
console.error('Could not get locales folder.\n', ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
fastify.decorate('i18n', i18n);
|
||||||
|
|
||||||
|
fastify.register(require(path.resolve(__dirname, './routes'))); // Self-register the routing for fetching locales
|
||||||
|
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = plugin;
|
|
@ -0,0 +1,11 @@
|
||||||
|
# About Readlebee
|
||||||
|
|
||||||
|
Readlebee is a social network for people who read books!
|
||||||
|
|
||||||
|
You can:
|
||||||
|
|
||||||
|
- Keep track of progress on books that you are reading,
|
||||||
|
- Save arbitrary lists of books with Shelves,
|
||||||
|
- Give books ratings and reviews,
|
||||||
|
- Send and receive recommendations for books you think others would like,
|
||||||
|
- And interact with the reviews and updates of your friends!
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Community Policy
|
||||||
|
|
||||||
|
This Readlebee hive has the following community policy:
|
||||||
|
|
||||||
|
Something good.
|
|
@ -0,0 +1,100 @@
|
||||||
|
{
|
||||||
|
"name": "English",
|
||||||
|
"locale": "en",
|
||||||
|
"global": {
|
||||||
|
"menu_search": "Search for Books",
|
||||||
|
"menu_about": "About",
|
||||||
|
"menu_login": "Log In / Create Account",
|
||||||
|
"menu_account": "My Profile",
|
||||||
|
"menu_logout": "Log Out",
|
||||||
|
"footer_repo": "Repo",
|
||||||
|
"footer_chat": "Chat",
|
||||||
|
"change_language": "Change Language"
|
||||||
|
},
|
||||||
|
"home": {
|
||||||
|
"logged_out_subtitle": "All the Book Buzz in Once Place",
|
||||||
|
"logged_out_track_books": "Keep track of books you've read, want to read, and are currently reading.",
|
||||||
|
"logged_out_share_friends": "Share your thoughts about what you're reading and see what your friends think of their books.",
|
||||||
|
"logged_out_read_rate": "Rate, review, and recommmend books or something. I dunno. It's early days, my friends!",
|
||||||
|
"logged_out_community_header": "A Look Inside the Hive",
|
||||||
|
"logged_out_recent_reviews": "Recent Reviews",
|
||||||
|
"logged_out_recent_updates": "Recent Updates",
|
||||||
|
"logged_out_join_now": "Join Now!",
|
||||||
|
"logged_in_subtitle": "Welcome!",
|
||||||
|
"logged_in_updates": "Updates",
|
||||||
|
"logged_in_interactions": "Interactions"
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"header": "Oops!",
|
||||||
|
"subheader": "It looks like the page you requested doesn't exist. Please try a different one!"
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
"log_in": "Log In",
|
||||||
|
"email": "Email",
|
||||||
|
"password": "Password",
|
||||||
|
"login_button": "Log In!",
|
||||||
|
"create_account": "Create a New Account",
|
||||||
|
"confirm_password": "Confirm Password",
|
||||||
|
"username": "Username",
|
||||||
|
"display_name": "Display Name",
|
||||||
|
"create_account_button": "Create Account!",
|
||||||
|
"login_required_field_blank": "You must enter both a valid email address and password.",
|
||||||
|
"create_required_field_blank": "You must complete all required fields.",
|
||||||
|
"create_password_confirm_mismatch": "Both password fields must match."
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"header": "Search",
|
||||||
|
"placeholder": "Search for Books",
|
||||||
|
"button_text": "Search",
|
||||||
|
"search_source_label": "Search Source",
|
||||||
|
"search_source_help_button": "What's This?",
|
||||||
|
"search_source_help_header": "What does \"Search Source\" mean?",
|
||||||
|
"search_source_help_text": "This refers to where the search tries to look for data. Each source can be easily contributed to if you want to add missing books or correct errors.",
|
||||||
|
"search_source_help_inventaire": "Sources and extends data from WikiData, the service structure that powers Wikipedia and the like. Offers as many language options as possible.",
|
||||||
|
"search_source_help_openLibrary": "Sources data from Internet Archive and may provide a digital copy to read. Only offers English unless a work is in another language.",
|
||||||
|
"search_by_label": "Search By",
|
||||||
|
"search_by_title": "Title",
|
||||||
|
"search_by_author": "Author",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"no_results": "None Found",
|
||||||
|
"no_results_suggestion": "If you're expecting book data, go and help fill out the Inventaire database!",
|
||||||
|
"people_header": "People",
|
||||||
|
"series_header": "Series",
|
||||||
|
"books_header": "Books",
|
||||||
|
"see_interaction_details": "See All Interactions",
|
||||||
|
"see_book_details": "See Book Details"
|
||||||
|
},
|
||||||
|
"interaction": {
|
||||||
|
"required": "Required",
|
||||||
|
"reload": "Reload",
|
||||||
|
"heart": "Like",
|
||||||
|
"add": "Add to Shelf",
|
||||||
|
"average_rating": "Average Rating",
|
||||||
|
"reviews_written": "Total Reviews Written"
|
||||||
|
},
|
||||||
|
"api": {
|
||||||
|
"account_already_logged_in": "You are already logged in! You cannot create an account or log in again.",
|
||||||
|
"account_create_required_data_missing": "Could not create account because required data is missing.",
|
||||||
|
"account_create_invalid_email": "The email address entered is not valid.",
|
||||||
|
"account_create_invalid_username": "The username entered is not valid. Usernames must be at least 2 characters long and can only contain letters a–z, numbers 0–9, and underscores",
|
||||||
|
"account_email_exists": "The email address entered is already in use.",
|
||||||
|
"account_username_exists": "The username entered is already in use.",
|
||||||
|
"account_email_send_fail": "Your account was created successfully, but we were unable to send the confirmation email!",
|
||||||
|
"account_confirm_email": "A confirmation email has been sent to the address you specified. Please confirm your account using the link provided.",
|
||||||
|
"account_create_success": "Account created successfully! You may now log in using the email address and password you provided.",
|
||||||
|
"account_confirm_required_data_missing": "Could not confirm account because required data is missing.",
|
||||||
|
"account_confirm_invalid_code": "The specified confirmation code is not valid.",
|
||||||
|
"account_confirm_update_fail": "Something went wrong and we couldn't confirm your account. Please try again later!",
|
||||||
|
"account_confirm_email_send_fail": "Your account has been confirmed, but we were unable to send the email notification about it. You can log in anyway.",
|
||||||
|
"account_confirm_success_email": "Your account has been confirmed, and an email notification has been sent! You may now log in using your email address and password.",
|
||||||
|
"account_confirm_success": "Your account has been confirmed! You may now log in using your email address and password.",
|
||||||
|
"account_login_required_data_missing": "Could not attempt login because required data is missing.",
|
||||||
|
"account_login_invalid_email": "The email address specified does not have an associated account.",
|
||||||
|
"account_login_not_confirmed": "The specified account has not been confirmed. Please use the link you received to confirm your email address.",
|
||||||
|
"account_login_invalid_password": "The password specified is not correct.",
|
||||||
|
"account_login_success": "You have been successfully logged in! You will now be redirected to the home screen.",
|
||||||
|
"account_validate_missing_token": "User not logged in: There is no login token to validate.",
|
||||||
|
"account_validate_invalid_token": "User not logged in: The stored token is not a valid token.",
|
||||||
|
"account_validate_renewed_token": "User logged in, and the token has been renewed."
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
async function routes(fastify, options) {
|
||||||
|
fastify.get('/locales/:locale/ui', async (request, reply) => {
|
||||||
|
const response = {
|
||||||
|
available: fastify.i18n.available,
|
||||||
|
default: fastify.i18n.default,
|
||||||
|
};
|
||||||
|
if (typeof fastify.i18n[request.params.locale] == 'undefined') {
|
||||||
|
console.warn(`The target language (${request.params.locale}) does not exist. Defaulting to ${fastify.i18n.default.name} (${fastify.i18n.default.locale}).`);
|
||||||
|
response.locale = fastify.i18n.default;
|
||||||
|
} else {
|
||||||
|
response.locale = fastify.i18n[request.params.locale];
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
|
||||||
|
fastify.get('/locales/:locale/page/:page', async (request, reply) => {
|
||||||
|
if (typeof fastify.i18n.pages[request.params.locale] == 'undefined') {
|
||||||
|
console.warn(`The target language (${request.params.locale}) does not exist. Defaulting to ${fastify.i18n.default.name} (${fastify.i18n.default.locale}).`);
|
||||||
|
if (typeof fastify.i18n.pages[fastify.i18n.default.locale][request.params.page] == 'undefined') {
|
||||||
|
console.error(`The target page (${request.params.page}) does not exist. Returning blank.`);
|
||||||
|
return request.params.page;
|
||||||
|
}
|
||||||
|
return fastify.i18n.pages[fastify.i18n.default.locale][request.params.page];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fastify.i18n.pages[request.params.locale][request.params.page];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = routes;
|
|
@ -84,6 +84,8 @@ fastify.addHook('onRequest', async (request, reply) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Store i18n files in fastify object and register locales routes
|
||||||
|
fastify.register(require('./i18n'));
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
fastify.register(require('./routes/public'));
|
fastify.register(require('./routes/public'));
|
||||||
|
|
|
@ -4165,6 +4165,11 @@ map-visit@^1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
object-visit "^1.0.0"
|
object-visit "^1.0.0"
|
||||||
|
|
||||||
|
marked@^0.7.0:
|
||||||
|
version "0.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e"
|
||||||
|
integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg==
|
||||||
|
|
||||||
md5.js@^1.3.4:
|
md5.js@^1.3.4:
|
||||||
version "1.3.5"
|
version "1.3.5"
|
||||||
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
|
||||||
|
|
Loading…
Reference in New Issue