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, thelanguagesdirectory)
- 
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 translatormodule
- Defines a list of required translation keys
- Uses translator.translateto get translations for each key
- Stores translations as an object
- Retrieves translations using the getTextfunction
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:
<div class="modal-header">
    <h5 class="modal-title">[[caiz:create_community]]</h5>
    <button type="button" class="close" data-dismiss="modal">
        <span>×</span>
    </button>
</div>
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.
 

 
    
Top comments (0)