Skip to content

I18n

ll/api/i18n/ · Common

Overview

The I18n module provides internationalization and localization support with a simple key-value translation system. It supports loading translations from files, runtime translation updates, and compile-time checked format strings via user-defined literals.

Headers

Header Description
ll/api/i18n/I18n.h I18n manager and translation literals

Key Classes

I18n

Singleton translation manager.

C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace ll::i18n {
class I18n {
public:
    Expected<> load(std::filesystem::path const& path) noexcept;
    void clear();
    void set(std::string_view localeCode, std::string_view key, std::string_view value);
    std::string_view get(std::string_view key, std::string_view localeCode) const;
};

I18n& getInstance();
std::string_view getDefaultLocaleCode();
}

User-Defined Literals

_tr — Translate with Default Locale

C++
1
2
3
4
using namespace ll::literals::i18n_literals;

auto msg = "hello.world"_tr();           // No arguments
auto greeting = "hello.user"_tr("Alice"); // With format arguments

_trl — Translate with Specific Locale

C++
1
2
auto msg = "hello.world"_trl("zh");           // Chinese
auto greeting = "hello.user"_trl("en", "Bob"); // English with argument

Usage

Loading Translations

The load() function accepts either a directory path or a JSON file path:

Option 1: Directory with Separate Language Files

Create separate JSON files for each language in a directory:

Text Only
1
2
3
4
lang/
├── en.json
├── zh.json
└── ja.json

Each file contains only that language's translations:

en.json:

JSON
1
2
3
4
5
{
  "hello.world": "Hello, World!",
  "hello.user": "Hello, {}!",
  "item.count": "You have {} items"
}

zh.json:

JSON
1
2
3
4
5
{
  "hello.world": "你好,世界!",
  "hello.user": "你好,{}!",
  "item.count": "你有 {} 个物品"
}

Load the directory:

C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include "ll/api/i18n/I18n.h"
#include "ll/api/mod/Mod.h"

void loadTranslations(ll::mod::Mod& mod) {
    auto& i18n = ll::i18n::getInstance();
    // Load all language files from directory
    auto result = i18n.load(mod.getLangDir());
    if (!result) {
        mod.getLogger().error("Failed to load translations");
    }
}

Option 2: Single JSON File with All Languages

Create a single JSON file with locale codes as top-level keys:

translations.json:

JSON
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "en": {
    "hello.world": "Hello, World!",
    "hello.user": "Hello, {}!",
    "item.count": "You have {} items"
  },
  "zh": {
    "hello.world": "你好,世界!",
    "hello.user": "你好,{}!",
    "item.count": "你有 {} 个物品"
  }
}

Load the file:

C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include "ll/api/i18n/I18n.h"
#include "ll/api/mod/Mod.h"

void loadTranslations(ll::mod::Mod& mod) {
    auto& i18n = ll::i18n::getInstance();
    // Load single file with all languages
    auto result = i18n.load(mod.getLangDir() / "translations.json");
    if (!result) {
        mod.getLogger().error("Failed to load translations");
    }
}

Using Translations

C++
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#include "ll/api/i18n/I18n.h"

using namespace ll::literals::i18n_literals;

void greetPlayer(std::string const& name) {
    // Uses default locale
    auto msg = "hello.user"_tr(name);
    // msg == "Hello, Alice!" or "你好,Alice!" depending on default locale
}

void showItemCount(int count) {
    auto msg = "item.count"_tr(count);
}

Runtime Translation Updates

C++
1
2
3
4
5
6
7
#include "ll/api/i18n/I18n.h"

void addTranslation() {
    auto& i18n = ll::i18n::getInstance();
    i18n.set("en", "custom.key", "Custom message");
    i18n.set("zh", "custom.key", "自定义消息");
}

Explicit Locale Selection

C++
1
2
3
4
5
6
using namespace ll::literals::i18n_literals;

void showInChinese() {
    auto msg = "hello.world"_trl("zh");
    // msg == "你好,世界!"
}
  • ModMod::getLangDir() returns the language directory