Internationalization is a crucial aspect of NodeBB plugin development (NodeBB supports 49 languages as of this writing). This article explains how to implement internationalization in NodeBB, covering both server-side and client-side aspects.
Basic Structure of Internationalization
NodeBB's internationalization is implemented with the following structure:
plugins/
nodebb-plugin-caiz/
languages/
en-US/
caiz.json
global.json
ja/
caiz.json
global.json
library.js
plugin.json
Translation files are placed in subdirectories named with language codes (e.g., en-US
, ja
) within the languages
directory. Translation files are in JSON format, consisting of key-value pairs.
The language codes available in NodeBB can be referenced from the folder names in the public/language
directory of the NodeBB repository. For example:
-
en-US
: American English -
en-GB
: British English -
ja
: Japanese -
zh-CN
: Chinese (Simplified) -
zh-TW
: Chinese (Traditional)
These language codes are based on ISO 639-1 (2-letter language codes) and ISO 639-2 (3-letter language codes). Additionally, country codes can be added with a hyphen to represent regional differences (e.g., en-US
, pt-BR
).
Plugin Configuration Update
The most important aspect of internationalization implementation is the plugin.json
configuration:
{
"id": "nodebb-plugin-caiz",
"name": "NodeBB Plugin for Caiz",
"description": "NodeBB Plugin for Caiz",
"version": "1.0.0",
"library": "./library.js",
"languages": "languages",
"scripts": [
"static/client.js"
]
}
Key settings:
-
languages
: Specifies the directory for translation files (in this example, thelanguages
directory) -
scripts
: Specifies client-side JavaScript files
When the languages
property is set, NodeBB automatically loads translation files from the specified directory. Each language's translation file must be placed in a subdirectory named with its language code.
Example translation file (languages/ja/caiz.json
):
{
"reading": "読み込み中",
"create_community": "コミュニティを作成",
"create_community_message": "新しくコミュニティを作成する",
"community_name": "コミュニティ名",
"community_description": "コミュニティの説明",
"submit_create": "作成",
"follow": "フォロー中",
"unfollow": "未フォロー",
"following": "フォローする",
"unfollowing": "フォロー解除する",
"follow_success": "フォローしました",
"unfollow_success": "フォロー解除しました",
"error.generic": "エラーが発生しました"
}
With this file, you can retrieve text using [[caiz.reading]]
.
Client-Side Implementation
Client-side internationalization is implemented using the translator
module. Since it's not very user-friendly by default, it's better to retrieve it asynchronously:
async function getTranslate() {
return new Promise((resolve, reject) => {
require(['translator'], resolve);
});
}
document.addEventListener('DOMContentLoaded', async () => {
const translator = await getTranslate();
const messageKeys = [
'caiz:reading',
'caiz:follow',
'caiz:unfollow',
'caiz:follow_success',
'caiz:unfollow_success',
'caiz:error.generic',
'caiz:unfollowing',
'caiz:following',
];
const messages = Object.fromEntries(
await Promise.all(
messageKeys.map(key =>
new Promise((resolve) =>
translator.translate(`[[${key}]]`, (t) => resolve([key, t]))
)
)
)
);
const getText = (key) => messages[key] || key;
});
This code performs the following operations:
- Asynchronously loads the
translator
module - Defines a list of required translation keys
- Uses
translator.translate
to get translations for each key - Stores translations as an object
- Retrieves translations using the
getText
function
As a result, you can get the i18n result using getText
:
getText('caiz:reading'); // 読み込み中
Usage in Templates
In template files (*.tpl
), translations are used as follows:
class="modal-header">
class="modal-title">[[caiz:create_community]]
type="button" class="close" data-dismiss="modal">
×
Important Considerations
-
Translation Key Naming Convention
- Use the translation file name as a prefix (e.g.,
caiz:
forcaiz.json
) - Use hierarchical structure for organization (e.g.,
error.generic
)
- Use the translation file name as a prefix (e.g.,
-
Translation Loading Timing
- Server-side: During application startup
- Client-side: During page load
-
Error Handling
- Fallback processing when translations are not found
- Debug support through log output
Summary
NodeBB's internationalization is primarily configured by specifying the translation file location in the languages
property of plugin.json
. By properly designing the translation file structure and maintaining consistent naming conventions, you can achieve maintainable internationalization.