0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-04-15 03:01:37 -05:00

Removed use of i18n from helpers in favour of tpl

- i18n is an old pattern that failed
- we are slowly replacing i18n with the tpl helper
This commit is contained in:
Hannah Wolfe 2021-09-23 20:46:22 +01:00
parent 1c8c55992a
commit 870bf27394
No known key found for this signature in database
GPG key ID: 9F8C7532D0A6BA55
16 changed files with 113 additions and 41 deletions

View file

@ -2,16 +2,20 @@
// Usage: `{{asset "css/screen.css"}}`
//
// Returns the path to the specified asset.
const {SafeString, metaData, errors, i18n} = require('../services/proxy');
const {SafeString, metaData, errors, tpl} = require('../services/proxy');
const get = require('lodash/get');
const {getAssetUrl} = metaData;
const messages = {
pathIsRequired: 'The {{asset}} helper must be passed a path'
};
module.exports = function asset(path, options) {
const hasMinFile = get(options, 'hash.hasMinFile');
if (!path) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.asset.pathIsRequired')
message: tpl(messages.pathIsRequired)
});
}

View file

@ -6,13 +6,17 @@
//
// Defaults to class="cancel-subscription-link" errorClass="cancel-subscription-error" cancelLabel="Cancel subscription" continueLabel="Continue subscription"
const {templates, errors, i18n, labs} = require('../services/proxy');
const {templates, errors, tpl, labs} = require('../services/proxy');
const messages = {
invalidData: 'The {{cancel_link}} helper was used outside of a subscription context. See https://ghost.org/docs/themes/members/#cancel-links.'
};
function cancel_link(options) { // eslint-disable-line camelcase
let truncateOptions = (options || {}).hash || {};
if (this.id === undefined || this.cancel_at_period_end === undefined) {
throw new errors.IncorrectUsageError({message: i18n.t('warnings.helpers.cancel_link.invalidData')});
throw new errors.IncorrectUsageError({message: tpl(messages.invalidData)});
}
const data = {

View file

@ -3,13 +3,17 @@
//
// Block helper designed for looping through posts
const _ = require('lodash');
const {logging, i18n, hbs, checks} = require('../services/proxy');
const {logging, tpl, hbs, checks} = require('../services/proxy');
const {Utils: hbsUtils, handlebars: {createFrame}} = hbs;
const ghostHelperUtils = require('@tryghost/helpers').utils;
const messages = {
iteratorNeeded: 'Need to pass an iterator to {{#foreach}}'
};
module.exports = function foreach(items, options) {
if (!options) {
logging.warn(i18n.t('warnings.helpers.foreach.iteratorNeeded'));
logging.warn(tpl(messages.iteratorNeeded));
}
if (hbsUtils.isFunction(items)) {

View file

@ -1,11 +1,16 @@
// # Get Helper
// Usage: `{{#get "posts" limit="5"}}`, `{{#get "tags" limit="all"}}`
// Fetches data from the API
const {config, logging, errors, i18n, hbs, api, prepareContextResource} = require('../services/proxy');
const {config, logging, errors, tpl, hbs, api, prepareContextResource} = require('../services/proxy');
const _ = require('lodash');
const Promise = require('bluebird');
const jsonpath = require('jsonpath');
const messages = {
mustBeCalledAsBlock: 'The {{{helperName}}} helper must be called as a block. E.g. {{#{helperName}}}...{{/{helperName}}}',
invalidResource: 'Invalid resource given to get helper'
};
const createFrame = hbs.handlebars.createFrame;
const RESOURCES = {
@ -121,13 +126,13 @@ module.exports = function get(resource, options) {
let returnedRowsCount;
if (!options.fn) {
data.error = i18n.t('warnings.helpers.mustBeCalledAsBlock', {helperName: 'get'});
data.error = tpl(messages.mustBeCalledAsBlock, {helperName: 'get'});
logging.warn(data.error);
return Promise.resolve();
}
if (!RESOURCES[resource]) {
data.error = i18n.t('warnings.helpers.get.invalidResource');
data.error = tpl(messages.invalidResource);
logging.warn(data.error);
return Promise.resolve(options.inverse(self, {data: data}));
}

View file

@ -4,9 +4,13 @@
//
// Checks if a post has a particular property
const {logging, i18n} = require('../services/proxy');
const {logging, tpl} = require('../services/proxy');
const _ = require('lodash');
const validAttrs = ['tag', 'author', 'slug','visibility', 'id', 'number', 'index', 'any', 'all'];
const validAttrs = ['tag', 'author', 'slug', 'visibility', 'id', 'number', 'index', 'any', 'all'];
const messages = {
invalidAttribute: 'Invalid or no attribute given to has helper'
};
function handleCount(ctxAttr, data) {
if (!data || !_.isFinite(data.length)) {
@ -155,7 +159,7 @@ module.exports = function has(options) {
let result;
if (_.isEmpty(attrs)) {
logging.warn(i18n.t('warnings.helpers.has.invalidAttribute'));
logging.warn(tpl(messages.invalidAttribute));
return;
}

View file

@ -9,21 +9,25 @@
const url = require('url');
const _ = require('lodash');
const {urlUtils, logging, i18n} = require('../services/proxy');
const {urlUtils, logging, tpl} = require('../services/proxy');
const messages = {
attrIsRequired: 'Attribute is required e.g. {{img_url feature_image}}'
};
const STATIC_IMAGE_URL_PREFIX = `${urlUtils.STATIC_IMAGE_URL_PREFIX}`;
module.exports = function imgUrl(requestedImageUrl, options) {
// CASE: if no url is passed, e.g. `{{img_url}}` we show a warning
if (arguments.length < 2) {
logging.warn(i18n.t('warnings.helpers.img_url.attrIsRequired'));
logging.warn(tpl(messages.attrIsRequired));
return;
}
// CASE: if url is passed, but it is undefined, then the attribute was
// an unknown value, e.g. {{img_url feature_img}} and we also show a warning
if (requestedImageUrl === undefined) {
logging.warn(i18n.t('warnings.helpers.img_url.attrIsRequired'));
logging.warn(tpl(messages.attrIsRequired));
return;
}

View file

@ -1,16 +1,20 @@
// # Is Helper
// Usage: `{{#is "paged"}}`, `{{#is "index, paged"}}`
// Checks whether we're in a given context.
const {logging, i18n} = require('../services/proxy');
const {logging, tpl} = require('../services/proxy');
const _ = require('lodash');
const messages = {
invalidAttribute: 'Invalid or no attribute given to is helper'
};
module.exports = function is(context, options) {
options = options || {};
const currentContext = options.data.root.context;
if (!_.isString(context)) {
logging.warn(i18n.t('warnings.helpers.is.invalidAttribute'));
logging.warn(tpl(messages.invalidAttribute));
return;
}

View file

@ -1,8 +1,12 @@
// # link helper
const _ = require('lodash');
const {config, SafeString, errors, i18n, localUtils} = require('../services/proxy');
const {config, SafeString, errors, tpl, localUtils} = require('../services/proxy');
const {buildLinkClasses} = localUtils;
const messages = {
hrefIsRequired: 'The {{#link}}{{/link}} helper requires an href="" attribute.'
};
const managedAttributes = ['href', 'class', 'activeClass', 'parentActiveClass'];
function _formatAttrs(attributes) {
@ -25,7 +29,7 @@ module.exports = function link(options) {
// If there is no href provided, this is theme dev error, so we throw an error to make this clear.
if (!_.has(options.hash, 'href')) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.link.hrefIsRequired')
message: tpl(messages.hrefIsRequired)
});
}
// If the href attribute is empty, this is probably a dynamic data problem, hard for theme devs to track down

View file

@ -1,8 +1,12 @@
// # link_class helper
const _ = require('lodash');
const {config, SafeString, errors, i18n, localUtils} = require('../services/proxy');
const {config, SafeString, errors, tpl, localUtils} = require('../services/proxy');
const {buildLinkClasses} = localUtils;
const messages = {
forIsRequired: 'The {{link_class}} helper requires a for="" attribute.'
};
module.exports = function link_class(options) { // eslint-disable-line camelcase
options = options || {};
options.hash = options.hash || {};
@ -11,7 +15,7 @@ module.exports = function link_class(options) { // eslint-disable-line camelcase
// If there is no for provided, this is theme dev error, so we throw an error to make this clear.
if (!_.has(options.hash, 'for')) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.link_class.forIsRequired')
message: tpl(messages.forIsRequired)
});
}

View file

@ -1,6 +1,10 @@
const {logging, i18n, SafeString, labs} = require('../services/proxy');
const {logging, tpl, SafeString, labs} = require('../services/proxy');
const _ = require('lodash');
const messages = {
invalidAttribute: 'Invalid or no attribute given to match helper'
};
/**
* This is identical to the built-in if helper, except inverse/fn calls are replaced with false/true
* https://github.com/handlebars-lang/handlebars.js/blob/19bdace85a8d0bc5ed3a4dec4071cb08c8d003f2/lib/handlebars/helpers/if.js#L9-L20
@ -58,7 +62,7 @@ function match(...attrs) {
let result;
if (_.isEmpty(attrs)) {
logging.warn(i18n.t('warnings.helpers.has.invalidAttribute'));
logging.warn(tpl(messages.invalidAttribute));
return;
}
@ -68,7 +72,7 @@ function match(...attrs) {
} else if (attrs.length === 3) {
result = handleMatch(attrs[0], attrs[1], attrs[2], options);
} else {
logging.warn(i18n.t('warnings.helpers.has.invalidAttribute'));
logging.warn(tpl(messages.invalidAttribute));
return;
}

View file

@ -2,9 +2,16 @@
// `{{navigation}}`
// Outputs navigation menu of static urls
const {SafeString, i18n, errors, templates, hbs} = require('../services/proxy');
const {SafeString, tpl, errors, templates, hbs} = require('../services/proxy');
const {slugify} = require('@tryghost/string');
const _ = require('lodash');
const messages = {
invalidData: 'navigation data is not an object or is a function',
valuesMustBeDefined: 'All values must be defined for label, url and current',
valuesMustBeString: 'Invalid value, Url and Label must be strings'
};
const createFrame = hbs.handlebars.createFrame;
module.exports = function navigation(options) {
@ -25,7 +32,7 @@ module.exports = function navigation(options) {
if (!_.isObject(navigationData) || _.isFunction(navigationData)) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.navigation.invalidData')
message: tpl(messages.invalidData)
});
}
@ -33,7 +40,7 @@ module.exports = function navigation(options) {
return (_.isUndefined(e.label) || _.isUndefined(e.url));
}).length > 0) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.navigation.valuesMustBeDefined')
message: tpl(messages.valuesMustBeDefined)
});
}
@ -43,7 +50,7 @@ module.exports = function navigation(options) {
(!_.isNull(e.url) && !_.isString(e.url)));
}).length > 0) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.navigation.valuesMustBeString')
message: tpl(messages.valuesMustBeString)
});
}

View file

@ -2,8 +2,16 @@
// `{{pagination}}`
// Outputs previous and next buttons, along with info about the current page
const {errors, i18n, templates, hbs} = require('../services/proxy');
const {errors, tpl, templates, hbs} = require('../services/proxy');
const _ = require('lodash');
const messages = {
invalidData: 'The {{pagination}} helper was used outside of a paginated context. See https://ghost.org/docs/themes/helpers/pagination/.',
valuesMustBeDefined: 'All values must be defined for page, pages, limit and total',
nextPrevValuesMustBeNumeric: 'Invalid value, Next/Prev must be a number',
valuesMustBeNumeric: 'Invalid value, check page, pages, limit and total are numbers'
};
const createFrame = hbs.handlebars.createFrame;
module.exports = function pagination(options) {
@ -14,7 +22,7 @@ module.exports = function pagination(options) {
if (!_.isObject(this.pagination) || _.isFunction(this.pagination)) {
throw new errors.IncorrectUsageError({
level: 'normal',
message: i18n.t('warnings.helpers.pagination.invalidData'),
message: tpl(messages.invalidData),
help: 'https://ghost.org/docs/themes/helpers/pagination/'
});
}
@ -22,20 +30,20 @@ module.exports = function pagination(options) {
if (_.isUndefined(this.pagination.page) || _.isUndefined(this.pagination.pages) ||
_.isUndefined(this.pagination.total) || _.isUndefined(this.pagination.limit)) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.pagination.valuesMustBeDefined')
message: tpl(messages.valuesMustBeDefined)
});
}
if ((!_.isNull(this.pagination.next) && !_.isNumber(this.pagination.next)) ||
(!_.isNull(this.pagination.prev) && !_.isNumber(this.pagination.prev))) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.pagination.nextPrevValuesMustBeNumeric')
message: tpl(messages.nextPrevValuesMustBeNumeric)
});
}
if (!_.isNumber(this.pagination.page) || !_.isNumber(this.pagination.pages) ||
!_.isNumber(this.pagination.total) || !_.isNumber(this.pagination.limit)) {
throw new errors.IncorrectUsageError({message: i18n.t('warnings.helpers.pagination.valuesMustBeNumeric')});
throw new errors.IncorrectUsageError({message: tpl(messages.valuesMustBeNumeric)});
}
// CASE: The pagination helper should have access to the pagination properties at the top level.

View file

@ -10,14 +10,18 @@
// The 3rd argument is the string that will be output if the variable's value is 1
// The 4th argument is the string that will be output if the variable's value is 2+
const {errors, i18n, SafeString} = require('../services/proxy');
const {errors, tpl, SafeString} = require('../services/proxy');
const isUndefined = require('lodash/isUndefined');
const messages = {
valuesMustBeDefined: 'All values must be defined for empty, singular and plural'
};
module.exports = function plural(number, options) {
if (isUndefined(options.hash) || isUndefined(options.hash.empty) ||
isUndefined(options.hash.singular) || isUndefined(options.hash.plural)) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.plural.valuesMustBeDefined')
message: tpl(messages.valuesMustBeDefined)
});
}

View file

@ -3,11 +3,15 @@
// `{{#prev_post}}<a href ="{{url}}>previous post</a>{{/prev_post}}'
// `{{#next_post}}<a href ="{{url absolute="true">next post</a>{{/next_post}}'
const {logging, i18n, api, hbs, checks} = require('../services/proxy');
const {logging, tpl, api, hbs, checks} = require('../services/proxy');
const get = require('lodash/get');
const Promise = require('bluebird');
const moment = require('moment');
const messages = {
mustBeCalledAsBlock: 'The {{{helperName}}} helper must be called as a block. E.g. {{#{helperName}}}...{{/{helperName}}}'
};
const createFrame = hbs.handlebars.createFrame;
const buildApiOptions = function buildApiOptions(options, post) {
@ -78,7 +82,7 @@ module.exports = function prevNext(options) {
// Guard against incorrect usage of the helpers
if (!options.fn || !options.inverse) {
data.error = i18n.t('warnings.helpers.mustBeCalledAsBlock', {helperName: options.name});
data.error = tpl(messages.mustBeCalledAsBlock, {helperName: options.name});
logging.warn(data.error);
return Promise.resolve();
}

View file

@ -11,9 +11,14 @@
// Returns amount equal to the dominant denomintation of the currency.
// For example, if 2100 is passed, it will return 21.
const isNumber = require('lodash/isNumber');
const {errors, i18n} = require('../services/proxy');
const {errors, tpl} = require('../services/proxy');
const _ = require('lodash');
const messages = {
attrIsRequired: 'Attribute is required e.g. {{price plan.amount}}',
attrMustBeNumeric: 'Attribute value should be a number'
};
function formatter({amount, currency, numberFormat = 'short', currencyFormat = 'symbol', locale}) {
const formatterOptions = {
style: 'currency',
@ -77,20 +82,20 @@ module.exports = function price(planOrAmount, options) {
// CASE: if no amount is passed, e.g. `{{price}}` we throw an error
if (arguments.length < 2) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.price.attrIsRequired')
message: tpl(messages.attrIsRequired)
});
}
// CASE: if amount is passed, but it is undefined we throw an error
if (amount === undefined) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.price.attrIsRequired')
message: tpl(messages.attrIsRequired)
});
}
if (!isNumber(amount)) {
throw new errors.IncorrectUsageError({
message: i18n.t('warnings.helpers.price.attrMustBeNumeric')
message: tpl(messages.attrMustBeNumeric)
});
}

View file

@ -3,6 +3,7 @@
// We can later refactor to enforce this something like we did in apps
const hbs = require('./theme-engine/engine');
const errors = require('@tryghost/errors');
const tpl = require('@tryghost/tpl');
const i18n = require('../../shared/i18n');
const logging = require('@tryghost/logging');
@ -29,7 +30,9 @@ module.exports = {
// These 3 are kind of core and required all the time
errors,
// @deprecated
i18n,
tpl,
logging,
// Theme i18n is separate to common i18n