Project Fluent localization support for Hexo themes.
hexo-fluent is additive. It does not replace Hexo's existing hexo-i18n
integration or the __() and _p() template functions. A theme may use either
system, or both during a migration.
Important
This project is currently experimental. Until a 1.0 release, minor versions may refine the resource conventions and template API based on theme-author feedback.
- Hexo 8 or later
- Node.js 20.19 or later
Until the first npm release, install the plugin directly from GitHub in a Hexo site or declare it as a dependency of a theme:
npm install github:hexojs/hexo-fluentAfter the package is published to npm, it can be installed with:
npm install hexo-fluentHexo automatically loads dependencies whose names start with hexo-.
Place Fluent Translation List (.ftl) resources below either languages/ or
locales/ in the theme. Both a single file per locale and multiple files per
locale are supported:
themes/example/
├── languages/
│ ├── en.ftl
│ └── zh-CN.ftl
└── locales/
├── en/
│ ├── navigation.ftl
│ └── posts.ftl
└── zh-CN/
├── navigation.ftl
└── posts.ftl
For a nested resource, the first directory after languages/ or locales/ is
the locale. Locale names are normalized as BCP 47 language tags. For example,
zh_cn is normalized to zh-CN.
An optional default.ftl resource acts as the last fallback:
languages/default.ftl
Example resource:
welcome = Welcome, { $name }!
post-count =
{ $count ->
[one] One post
*[other] { $count } posts
}
open-post =
.title = Open this postResources are reloaded when running Hexo in watch or server mode. Multiple files for the same locale are loaded in path order. Duplicate message IDs are reported as warnings and the first definition wins.
The plugin adds fluent() and fluent_attr() to template locals:
<h1><%= fluent('welcome', { name: config.author }) %></h1>
<p><%= fluent('post-count', { count: site.posts.length }) %></p>
<a title="<%= fluent_attr('open-post', 'title') %>">...</a>The formatter also exposes attr() and has():
fluent.attr('open-post', 'title')
fluent.has('post-count')If a message or attribute cannot be found in the negotiated fallback chain, its ID is returned. Fluent formatting errors are reported as Hexo warnings, while Fluent still produces its best-effort result.
The current page locale is selected in this order:
page.langorpage.language- A locale prefix matched by Hexo's
i18n_dir - The first locale in the site's
languageconfiguration - The first available Fluent locale
Message fallback uses Fluent language negotiation, followed by the configured
site languages and then default.ftl.
Fluent isolates interpolated variables with Unicode bidi isolation characters by default. This is useful for mixed left-to-right and right-to-left text and matches Fluent's default behavior. It can be disabled in the site configuration:
fluent:
use_isolating: falseThe existing template functions remain unchanged:
<%= __('menu.home') %>
<%= _p('posts', site.posts.length) %>
<%= fluent('post-count', { count: site.posts.length }) %>hexo.theme.i18n continues to use hexo-i18n. Fluent bundles are available to
theme scripts as hexo.theme.fluent.
npm install
npm testThe test suite covers resource paths, locale negotiation, fallback, plural selection, attributes, resource updates and deletion, diagnostics, and Hexo plugin registration.