Skip to content
This repository has been archived by the owner on Jun 4, 2022. It is now read-only.

Commit

Permalink
feat(i18n): introduce enhanced i18n generators
Browse files Browse the repository at this point in the history
  • Loading branch information
ppoffice committed Apr 17, 2018
1 parent 1755ba3 commit f026985
Show file tree
Hide file tree
Showing 5 changed files with 273 additions and 8 deletions.
5 changes: 4 additions & 1 deletion layout/archive.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<div class="container">
<% const groups = {};
const years = [];
site.posts.each(post => {
page.posts.each(post => {
const year = post.date.year();
if (typeof(groups[year]) === 'undefined') {
groups[year] = [];
Expand All @@ -25,5 +25,8 @@
</div>
</div>
<% } %>
<% if (page.total > 1) { %>
<%- partial('common/paginator') %>
<% } %>
</div>
</section>
3 changes: 3 additions & 0 deletions layout/categories.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<% page._categories.forEach(category => {%>
<%= category.name %>
<% }) %>
11 changes: 4 additions & 7 deletions layout/common/article.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,9 @@
<% if (post.categories && post.categories.length){ %>
<span class="column is-narrow article-category">
<i class="far fa-folder"></i>
<%- list_categories(post.categories, {
show_count: false,
class: 'article-category',
style: 'none',
separator: '<span>></span>'
}) %>
<%- post._categories.map(category =>
`<a class="article-category-link" href="${url_for(category.path)}">${category.name}</a>`)
.join('<span>></span>') %>
</span>
<% } %>
<% if (!has_config('article.readtime') || get_config('article.readtime') === true) { %>
Expand All @@ -41,7 +38,7 @@
</div>
<% if (!index && post.tags && post.tags.length){ %>
<div class="columns is-multiline is-mobile article-tags">
<% post.tags.forEach(tag => { %>
<% (post._tags || post.tags).forEach(tag => { %>
<span class="column is-narrow"><a href="<%- url_for(tag.path) %>">#<%= tag.name %></a></span>
<% }) %>
</div>
Expand Down
3 changes: 3 additions & 0 deletions layout/tags.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<% page._tags.forEach(tag => {%>
<%= tag.name %>
<% }) %>
259 changes: 259 additions & 0 deletions scripts/10_generator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
const _ = require('underscore');
const indexGenerator = require('hexo-generator-index/lib/generator');
const archiveGenerator = require('hexo-generator-archive/lib/generator');
const categoryGenerator = require('hexo-generator-category/lib/generator');
const tagGenerator = require('hexo-generator-tag/lib/generator');

function pathJoin(...paths) {
return paths.join('/');
}

function withLanguage(func) {
return function(locals) {
let languages = this.config.language;
if (!Array.isArray(languages)) {
languages = [languages];
}
return func.call(this, languages, locals);
}
}

/**
* Multi-language index generator.
*
* ATTENTION: This will override the default index generator!
*/
hexo.extend.generator.register('index', withLanguage(function(languages, locals) {
return _.flatten(languages.map((language, i) => {
// Filter posts by language considering. Posts without a language is considered of the default language.
const posts = locals.posts.filter(post => post.lang === language || (i === 0 && !post.lang));
if (posts.length === 0) {
return null;
}
const routes = indexGenerator.call(this, Object.assign({}, locals, {
posts: posts
}));
if (i === 0) {
return routes;
}
return routes.map(route => {
const data = Object.assign({}, route.data, {
base: pathJoin(language, route.data.base),
current_url: pathJoin(language, route.data.current_url)
});
return Object.assign({}, route, {
path: pathJoin(language, route.path),
data: data
});
});
}).filter(post => post !== null), true);
}));

/**
* Multi-language archive generator.
*
* ATTENTION: This will override the default archive generator!
*/
hexo.extend.generator.register('archive', withLanguage(function(languages, locals) {
return _.flatten(languages.map((language, i) => {
// Filter posts by language considering. Posts without a language is considered of the default language.
const posts = locals.posts.filter(post => post.lang === language || (i === 0 && !post.lang));
if (posts.length === 0) {
return null;
}
const routes = archiveGenerator.call(this, Object.assign({}, locals, {
posts: posts
}));
if (i === 0) {
return routes;
}
return routes.map(route => {
const data = Object.assign({}, route.data, {
base: pathJoin(language, route.data.base),
current_url: pathJoin(language, route.data.current_url)
});
return Object.assign({}, route, {
path: pathJoin(language, route.path),
data: data
});
});
}).filter(post => post !== null), true);
}));

/**
* Multi-language category generator.
*
* ATTENTION: This will override the default category generator!
*/
hexo.extend.generator.register('category', withLanguage(function(languages, locals) {
return _.flatten(languages.map((language, i) => {
const categories = locals.categories.map(category => {
// Filter posts by language considering. Posts without a language is considered of the default language.
const posts = category.posts.filter(post => post.lang === language || (i === 0 && !post.lang));
if (posts.length === 0) {
return null;
}
return Object.assign({}, category, {
posts: posts
});
}).filter(category => category !== null);
if (categories.length === 0) {
return null;
}

const routes = categoryGenerator.call(this, Object.assign({}, locals, {
categories: categories
}));
if (i === 0) {
return routes;
}
return routes.map(route => {
const data = Object.assign({}, route.data, {
base: pathJoin(language, route.data.base),
current_url: pathJoin(language, route.data.current_url)
});
return Object.assign({}, route, {
path: pathJoin(language, route.path),
data: data
});
});
}).filter(post => post !== null), true);
}));

/**
* Multi-language tag generator.
*
* ATTENTION: This will override the default tag generator!
*/
hexo.extend.generator.register('tag', withLanguage(function(languages, locals) {
return _.flatten(languages.map((language, i) => {
const tags = locals.tags.map(tag => {
// Filter posts by language considering. Posts without a language is considered of the default language.
const posts = tag.posts.filter(post => post.lang === language || (i === 0 && !post.lang));
if (posts.length === 0) {
return null;
}
return Object.assign({}, tag, {
posts: posts
});
}).filter(category => category !== null);
if (tags.length === 0) {
return null;
}

const routes = tagGenerator.call(this, Object.assign({}, locals, {
tags: tags
}));
if (i === 0) {
return routes;
}

return routes.map(route => {
const data = Object.assign({}, route.data, {
base: pathJoin(language, route.data.base),
current_url: pathJoin(language, route.data.current_url)
});
return Object.assign({}, route, {
path: pathJoin(language, route.path),
data: data
});
});
}).filter(post => post !== null), true);
}));

/**
* Category list page generator
*/
hexo.extend.generator.register('categories', withLanguage(function(languages, locals) {
return languages.map((language, i) => {
const categories = locals.categories.map(category => {
// Filter posts by language considering. Posts without a language is considered of the default language.
const posts = category.posts.filter(post => post.lang === language || (i === 0 && !post.lang));
if (posts.length === 0) {
return null;
}
return Object.assign({}, category, {
posts: posts
});
}).filter(category => category !== null);
return {
path: i !== 0 ? pathJoin(language, 'categories/') : 'categories/',
layout: ['categories'],
data: Object.assign({}, locals, {
_categories: categories
})
};
})
}));

/**
* Tag list page generator
*/
hexo.extend.generator.register('tags', withLanguage(function(languages, locals) {
return languages.map((language, i) => {
const tags = locals.tags.map(tag => {
// Filter posts by language considering. Posts without a language is considered of the default language.
const posts = tag.posts.filter(post => post.lang === language || (i === 0 && !post.lang));
if (posts.length === 0) {
return null;
}
return Object.assign({}, tag, {
posts: posts
});
}).filter(category => category !== null);
return {
path: i !== 0 ? pathJoin(language, 'tags/') : 'tags/',
layout: ['tags'],
data: Object.assign({}, locals, {
_tags: tags
})
};
})
}));

try {
require.resolve('hexo-generator-json-content');
const jsonContentGenerator = hexo.extend.generator.get('json-content');

/**
* Multi-language tag generator.
*
* ATTENTION: This will override the default tag generator!
*/
hexo.extend.generator.register('json-content', withLanguage(function(languages, locals) {
return _.flatten(languages.map((language, i) => {
const site = {
pages: locals.pages.filter(page => page.lang === language || (i === 0 && !page.lang)),
posts: locals.posts.filter(post => post.lang === language || (i === 0 && !post.lang))
};
try {
// Shouldn't use private function _rejectionHandler0 here, but I don't want to copy
// the entire hexo-generator-json-content!
return Object.assign({}, jsonContentGenerator(site)._rejectionHandler0, {
path: i === 0 ? 'content.json' : 'content.' + language + '.json'
})
} catch(e) {
return null;
}
}).filter(json => json !== null));
}));
} catch(e) {}

/**
* Append language directory to the post tags and categories
*/
hexo.extend.filter.register('before_post_render', function(data){
data._categories = data.categories ? data.categories.map(category => {
return {
name: category.name,
path: data.lang ? pathJoin(data.lang, category.path) : category.path
};
}) : [];
data._tags = data.tags ? data.tags.map(tag => {
return {
name: tag.name,
path: data.lang ? pathJoin(data.lang, tag.path) : tag.path
};
}) : [];
return data;
});

0 comments on commit f026985

Please sign in to comment.