Example code

The ten easy-start examples of the @aurorah/i18n module, ready to test: copy any file below into a folder, install the module, and run it with node. Each example shows the CODE you run and the OUTPUT it prints, so you can see the result without testing. Set "type": "module" in your package.json. No API key, no signup — the examples connect to the free default public API server.

terminal
$ mkdir easy-start && cd easy-start
$ npm install @aurorah/i18n
$ node exam-helloworld-1.js
package.json
{
  "type": "module",
  "dependencies": {
    "@aurorah/i18n": "^1.0.5"
  }
}

1 exam-helloworld-1.js

First run — t shows the source text NOW; await i18n.waitFor("translate") waits for the translations, then the same t calls print Korean.

exam-helloworld-1.js
import { I18n } from "@aurorah/i18n";

// "www.example.com" = your project's namespace (scopes its translation tables)
// "ko_kr" = {language}_{country} (ISO 639-1 + ISO 3166-1)
const i18n = new I18n({
  namespace: "www.example.com",
  language: "ko_kr",
});
const t = i18n.t;

// display text without translation
console.log(t("Hello~ world !!!")); // Hello~ world !!!
console.log(t("menu/marketplace")); // menu/marketplace

// wait for translations to be loaded
await i18n.waitFor("translate");

// display translations
console.log(t("Hello~ world !!!")); // 안녕~ 세상아 !!!
console.log(t("menu/marketplace")); // 메뉴/마켓플레이스
OUTPUT
# first run — source text now, translations after waitFor("translate")

$ node exam-helloworld-1.js
Hello~ world !!!
menu/marketplace
안녕~ 세상아 !!!
메뉴/마켓플레이스

2 exam-helloworld-2.js

Later run — await i18n.load() downloads the whole translation cache (filled by the previous run) in ONE request; no waitFor needed.

exam-helloworld-2.js
import { I18n } from "@aurorah/i18n";

// "www.example.com" = your project's namespace (scopes its translation tables)
// "ko_kr" = {language}_{country} (ISO 639-1 + ISO 3166-1)
const i18n = new I18n({
  namespace: "www.example.com",
  language: "ko_kr",
});
const t = i18n.t;

// load translation cache (filled by a previous translate run)
await i18n.load();

// display translations
console.log(t("Hello~ world !!!")); // 안녕~ 세상아 !!!
console.log(t("menu/marketplace")); // 메뉴/마켓플레이스
OUTPUT
# later run — the cache is warm from the previous translate run

$ node exam-helloworld-2.js
안녕~ 세상아 !!!
메뉴/마켓플레이스

3 exam-subscribe.js

Long-lived UI (or console loop) — i18n.subscribe() re-renders when a translation arrives, including the refined version that replaces the fast draft shortly after.

exam-subscribe.js
import { I18n } from "@aurorah/i18n";

let iRenderCount = 0;

// "www.example.com" = your project's namespace (scopes its translation tables)
// "ko_kr" = {language}_{country} (ISO 639-1 + ISO 3166-1)
const i18n = new I18n({
  namespace: "www.example.com",
  language: "ko_kr",
});
const t = i18n.t;

// load translation cache (filled by a previous translate run)
await i18n.load();

// render translations
function renderTexts() {
  iRenderCount++;
  console.log(`Render count: ${iRenderCount}`);
  console.log(
    t("Hello~ everyone !!! This is Steve, developer of @aurorah/i18n."),
  );
  console.log(
    t("It's very easy to use for software localization with @aurorah/i18n."),
  );
}

// subscribe to i18n events
i18n.subscribe((e) => {
  console.log(
    `\n\ni18n-event: ${e.reason}${e.phase ? ` - ${e.phase}` : ""} [${e.language}]`,
  );
  // render texts when translations are loaded
  if (e.reason === "translate") {
    renderTexts();
  }
});

// render texts immediately
renderTexts();

await i18n.waitFor("exit"); // wait for the application to exit
OUTPUT
# first run — 1) source text now, 2) fast draft, 3) refined

$ node exam-subscribe.js
Render count: 1
Hello~ everyone !!! This is Steve, developer of @aurorah/i18n.
It's very easy to use for software localization with @aurorah/i18n.

i18n-event: translate - draft [ko_kr]
Render count: 2
안녕하세요~ 여러분!!! 저는 @aurorah/i18n 개발자 스티브입니다.
@aurorah/i18n을 사용하면 소프트웨어 현지화에 매우 쉽게 사용할 수 있습니다.

i18n-event: translate - refined [ko_kr]
Render count: 3
안녕하세요~ 여러분!!! 저는 @aurorah/i18n 개발자 스티브입니다.
@aurorah/i18n을 사용하면 소프트웨어 현지화가 매우 쉬워집니다.

# second run — warm cache, translated immediately

$ node exam-subscribe.js
Render count: 1
안녕하세요~ 여러분!!! 저는 @aurorah/i18n 개발자 스티브입니다.
@aurorah/i18n을 사용하면 소프트웨어 현지화가 매우 쉬워집니다.

4 exam-source-language-1.js

The app is WRITTEN in Japanese, and an English user sees English — the same t call, one-shot style: await i18n.load() after setLanguage().

exam-source-language-1.js
import { I18n } from "@aurorah/i18n";

// "www.example.com" = your project's namespace (scopes its translation tables)
// "ja_jp" = {language}_{country} (ISO 639-1 + ISO 3166-1)
const i18n = new I18n({
  namespace: "www.example.com",
  sourceLanguage: "ja_jp",
  language: "ja_jp",
});
const t = i18n.t;

console.log(t("こんにちは〜 世界 !!!")); // こんにちは〜 世界 !!! (the source — no load() needed)

i18n.setLanguage("en_us"); // switch to English
await i18n.load(); // load the en_us cache

console.log(t("こんにちは〜 世界 !!!")); // Hello~ world !!! (same call, now English)

await i18n.waitFor("exit"); // wait for the application to exit
OUTPUT
# first run — the en_us cache is still empty for the Japanese source

$ node exam-source-language-1.js
こんにちは〜 世界 !!!
[@aurorah/i18n] no en_us translation for "こんにちは〜 世界 !!!" (hashId 17bfirr1aam9kv) in the loaded table
こんにちは〜 世界 !!!

# second run — load() returns English immediately

$ node exam-source-language-1.js
こんにちは〜 世界 !!!
Hello World !!!

5 exam-source-language-2.js

The same Japanese source with subscribe — English appears on the FIRST run, because setLanguage() kicks a background load() and the "load" / "translate" events re-render.

exam-source-language-2.js
import { I18n } from "@aurorah/i18n";

let iRenderCount = 0;

// "www.example.com" = your project's namespace (scopes its translation tables)
// "ja_jp" = {language}_{country} (ISO 639-1 + ISO 3166-1)
const i18n = new I18n({
  namespace: "www.example.com",
  sourceLanguage: "ja_jp",
  language: "ja_jp",
});
const t = i18n.t;

// render texts
function renderTexts() {
  console.log(t("こんにちは〜 世界 !!!"));
}

// subscribe to i18n events
i18n.subscribe((e) => {
  console.log(`\n\ni18n-event: ${e.reason}${e.phase ? ` - ${e.phase}` : ""} [${e.language}]`);
  if (e.reason === "load" || e.reason === "translate") {
    // after i18n.setLanguage("en_us") : Hello~ world !!! (same call, now English)
    renderTexts();
  }
});

renderTexts(); // before i18n.setLanguage("en_us") : こんにちは〜 世界 !!! (the source — no load() needed)

i18n.setLanguage("en_us"); // switch to English

await i18n.waitFor("exit"); // wait for the application to exit
OUTPUT
$ node exam-source-language-2.js
こんにちは〜 世界 !!!

i18n-event: language [en_us]

i18n-event: load [en_us]
Hello~ World !!!

6 exam-switch-language.js

One call switches the whole app — setLanguage() plus await load() per language pulls that language's translations once; after that, every t() call renders instantly.

exam-switch-language.js
import { I18n } from "@aurorah/i18n";

const i18n = new I18n({
  namespace: "www.example.com",
});
const t = i18n.t; // `t` stays bound to the instance

// default language is 'en_us'
console.log(t("Hello~ world !!!")); // Hello~ world !!! (the source — no load() needed)

i18n.setLanguage("ko_kr"); // switch to Korean
await i18n.load(); // load the ko_kr cache
console.log(t("Hello~ world !!!")); // 안녕~ 세상아 !!! (same call, now Korean)

i18n.setLanguage("ja_jp"); // Japanese
await i18n.load();
console.log(t("Hello~ world !!!")); // こんにちは〜 世界 !!!

i18n.setLanguage("zh_cn"); // Chinese
await i18n.load();
console.log(t("Hello~ world !!!")); // 你好〜 世界 !!!

i18n.setLanguage("es_es"); // Spanish
await i18n.load();
console.log(t("Hello~ world !!!")); // ¡Hola~ mundo !!!

await i18n.waitFor("translate"); // wait for the translations to be loaded

// next run will be warm cache
OUTPUT
# first run — no translations yet, the source text renders

$ node exam-switch-language.js
Hello~ world !!!
[@aurorah/i18n] no ko_kr translation for "Hello~ world !!!" (hashId 1b917x6mio0ie) in the loaded table
Hello~ world !!!
[@aurorah/i18n] no ja_jp translation for "Hello~ world !!!" (hashId 1b917x6mio0ie) in the loaded table
Hello~ world !!!
[@aurorah/i18n] no zh_cn translation for "Hello~ world !!!" (hashId 1b917x6mio0ie) in the loaded table
Hello~ world !!!
[@aurorah/i18n] no es_es translation for "Hello~ world !!!" (hashId 1b917x6mio0ie) in the loaded table
Hello~ world !!!

# second run — warm cache

$ node exam-switch-language.js
Hello~ world !!!
안녕~ 세상아!!!
こんにちは、世界!!!
你好~世界!!!
Hola~ mundo !!!

7 exam-positional-placeholder-1.js

Positional placeholders — ${name} and ${age} become {0} and {1}, so each language can move them to wherever its word order needs them.

exam-positional-placeholder-1.js
import { I18n } from "@aurorah/i18n";

const i18n = new I18n({
  namespace: "www.example.com",
});
const t = i18n.t; // `t` stays bound to the instance

const name = "Steve";
const age = 20;

i18n.setLanguage("en_us");
console.log(t`${name} is ${age} years old !!!`); // Steve is 20 years old !!!

i18n.setLanguage("ko_kr");
await i18n.load(); // load the ko_kr cache

console.log(t`${name} is ${age} years old !!!`); // Steve는 20살입니다 !!!

await i18n.waitFor("translate"); // wait for the translations to be loaded

// next run will be warm cache
OUTPUT
# 1st run — no translation yet

$ node exam-positional-placeholder-1.js
Steve is 20 years old !!!
[@aurorah/i18n] no ko_kr translation for "{0} is {1} years old !!!" (hashId 4s5hfondoi0e) in the loaded table
Steve is 20 years old !!!

# 2nd run — draft (fast first answer; often still English)

$ node exam-positional-placeholder-1.js
Steve is 20 years old !!!
Steve is 20 years old !!!

# 3rd run — refined

$ node exam-positional-placeholder-1.js
Steve is 20 years old !!!
Steve는 20살입니다 !!!

8 exam-positional-placeholder-2.js

Positional placeholders with subscribe — the draft and refined translation updates re-render in one process; no second or third run needed.

exam-positional-placeholder-2.js
import { I18n } from "@aurorah/i18n";

const i18n = new I18n({
  namespace: "www.example.com",
});
const t = i18n.t; // `t` stays bound to the instance

const name = "Steve";
const age = 20;

// render texts
function renderTexts() {
  console.log(t`Is ${name} really ${age} years old ???`);
}

// subscribe to i18n events
i18n.subscribe((e) => {
  console.log(
    `\n\ni18n-event: ${e.reason}${e.phase ? ` - ${e.phase}` : ""} [${e.language}]`,
  );
  if (e.reason === "load" || e.reason === "translate") {
    renderTexts();
  }
});

i18n.setLanguage("en_us"); // switch to English (default)
renderTexts(); // first render: Steve is 20 years old !!!

i18n.setLanguage("ko_kr"); // switch to Korean

await i18n.waitFor("exit"); // wait for the application to exit
OUTPUT
# first run — draft and refined re-render in ONE process

$ node exam-positional-placeholder-2.js
Is Steve really 20 years old ???

i18n-event: language [ko_kr]
[@aurorah/i18n] no ko_kr translation for "Is {0} really {1} years old ???" (hashId jfebmd1bbrvr5) in the loaded table

i18n-event: load [ko_kr]
Is Steve really 20 years old ???

i18n-event: translate - draft [ko_kr]
Is Steve really 20 years old ???

i18n-event: translate - refined [ko_kr]
Steve이(가) 정말 20살인가요???

# second run — warm cache

$ node exam-positional-placeholder-2.js
Is Steve really 20 years old ???

i18n-event: language [ko_kr]

i18n-event: load [ko_kr]
Steve이(가) 정말 20살인가요???

9 exam-named-placeholder.js

Named placeholder ${{ something }} — define a message once with m, reuse it with different values, and .note() leaves a comment for the i18n translator.

exam-named-placeholder.js
import { I18n } from "@aurorah/i18n";

const i18n = new I18n({
  namespace: "www.example.com",
});
const t = i18n.t; // `t` stays bound to the instance
const m = i18n.m; // `m` stays bound to the instance

const something = ""; // dummy — only the key name matters at define time

// define once, reuse anywhere — .note() is for the translator:
const hello = m`Hello~ world !!! And this is ${{ something }} !!!`.note(
  "Greeting on the home page casually. {something} is the user's name, introducing himself.",
);

// render texts
function renderTexts() {
  console.log(hello({ something: "Steve" })); // 안녕~ 세상아!!! 그리고 나는 Steve야!!!
  console.log(hello({ something: "Alex" })); // 안녕~ 세상아!!! 그리고 나는 Alex야!!!
}

// subscribe to i18n events
i18n.subscribe((e) => {
  console.log(
    `\n\ni18n-event: ${e.reason}${e.phase ? ` - ${e.phase}` : ""} [${e.language}]`,
  );
  if (e.reason === "load" || e.reason === "translate") {
    renderTexts();
  }
});

i18n.setLanguage("ko_kr");

await i18n.waitFor("exit"); // wait for the application to exit
OUTPUT
# first run — load shows the source, draft/refined upgrade it live

$ node exam-named-placeholder.js
i18n-event: language [ko_kr]
[@aurorah/i18n] no ko_kr translation for "Hello~ world !!! And this is {something} !!!" (hashId 920g3m1g1qylg) in the loaded table

i18n-event: load [ko_kr]
Hello~ world !!! And this is Steve !!!
Hello~ world !!! And this is Alex !!!

i18n-event: translate - draft [ko_kr]
안녕하세요~ 세상아!!! 그리고 이건 Steve 야!!!
안녕하세요~ 세상아!!! 그리고 이건 Alex 야!!!

i18n-event: translate - refined [ko_kr]
안녕~ 세상아!!! 그리고 나는 Steve야!!!
안녕~ 세상아!!! 그리고 나는 Alex야!!!

# second run — warm cache

$ node exam-named-placeholder.js
i18n-event: language [ko_kr]

i18n-event: load [ko_kr]
안녕~ 세상아!!! 그리고 나는 Steve야!!!
안녕~ 세상아!!! 그리고 나는 Alex야!!!

10 exam-auto-complete.js

i18n engine auto-complete — with upgradeSourceLanguage: true the engine completes the grammar (1st, 2nd, 3rd, 4th) even in the source language.

exam-auto-complete.js
import { I18n } from "@aurorah/i18n";

// "www.example.com" = your project's namespace (scopes its translation tables)
// "en_us" = {language}_{country} (ISO 639-1 + ISO 3166-1)
const i18n = new I18n({
  namespace: "www.example.com",
  language: "en_us", // active language
  sourceLanguage: "en_us", // language the source strings are written in
  upgradeSourceLanguage: true, // let the i18n engine improve the source language too (ordinals, etc.)
});
const t = i18n.t; // `t` stays bound to the instance

const name = "Steve";

// render texts
function renderTexts() {
  for (let n = 1; n <= 4; n++) {
    // 1) NOW: the text as written — "2st", "3st", "4st"
    // 2) ~1-2s: the fast first answer arrives
    // 3) ~10-60s: the refined version — the i18n engine completed the grammar
    console.log(t`${name} is ${n}st winner in the contest.`);
  }
}

// subscribe to i18n events
i18n.subscribe((e) => {
  console.log(
    `\n\ni18n-event: ${e.reason}${e.phase ? ` - ${e.phase}` : ""} [${e.language}]`,
  );
  if (e.reason === "load" || e.reason === "translate") {
    renderTexts();
  }
});

renderTexts(); // first render: text as written

await i18n.waitFor("exit"); // wait for the application to exit
OUTPUT
# first run — the draft may still show "2st"; refined completes the grammar

$ node exam-auto-complete.js
Steve is 1st winner in the contest.
Steve is 2st winner in the contest.
Steve is 3st winner in the contest.
Steve is 4st winner in the contest.
[@aurorah/i18n] {1, plural}: en_us needs [one, other], missing [one] (falls back to "other") — hashId 14ykp781y8zfz4, translation "{1, plural, other {{0} is #st winner in the contest.}}"

i18n-event: translate - draft [en_us]
Steve is 1st winner in the contest.
Steve is 2st winner in the contest.
Steve is 3st winner in the contest.
Steve is 4st winner in the contest.

i18n-event: translate - refined [en_us]
Steve is 1st winner in the contest.
Steve is 2nd winner in the contest.
Steve is 3rd winner in the contest.
Steve is 4th winner in the contest.