Fallback

Fallback is a mechanism that allows you to provide default value (translations for messages, or localized assets) that are not available in the current locale.

This ensures that your game can still display meaningful content even when specific translations or assets are missing.

You're recommended to set the fallback locale to the most complete locale you have. For example, if you have 3 locales (en, id, and ja), and the en locale has the most complete translation, you should set the fallback locale to en.

Initialization

You're required to set the fallback locale when initializing the GM-I18n system using i18n_create() function.

Create Event
// i18n_create(var_name, default_locale, locales, [options])
// the `default_locale` is the fallback locale
// so, if message keys or localized assets are not found in the current locale, 
// it will take the value from the fallback locale

global.i18n = i18n_create("global.i18n", "en", [
    new I18nLocaleInit("en", "English", "~/langs/en.json"),
    new I18nLocaleInit("id", "Indonesian", "~/langs/id.json"),
    new I18nLocaleInit("ja", "Japanese", "~/langs/ja.json")
]);

Your fallback system is now ready to use!

You can start using i18n_get_messages(), i18n_create_ref_message(), and i18n_create_ref_asset() function to get messages and localized assets with fallback mechanism.


How It Works?

Fallback Flowchart

You can set the default message for message fallback in the i18n_create() function by passing the default_message in the options parameter.

Create Event
// i18n_create(var_name, default_locale, locales, [options])
global.i18n = i18n_create("global.i18n", "en", [
    new I18nLocaleInit("en", "English", "~/langs/en.json"),
    new I18nLocaleInit("id", "Indonesian", "~/langs/id.json"),
    new I18nLocaleInit("ja", "Japanese", "~/langs/ja.json")
], {
    default_message: "Missing Translation"          // default message for message fallback (default = empty string)
});
The default_message is only used for message fallback. It won't affect the localized asset fallback.

You can see the available options in the API Reference.

Message Fallback

The message fallback is triggered when the message key is not found in the current locale. It will take the message from the fallback locale instead, or the default_message if the message is not found in the fallback locale.

You're recommended to read the Messages section first before proceeding to this section.

Create Event
// assume the system is initialized on global variable
// assume the fallback locale is "en" and the default message is "Missing Translation"
// i18n_get_messages(key, [data], [locale], [i18n])

// static messages
msg1 = i18n_get_messages("hello", , "en");              // "Hello World!"
msg2 = i18n_get_messages("bye", , "ja");                // "さようなら世界!"
msg3 = i18n_get_messages("info", , "en");               // "Missing Translation", because "info" is not defined in "en" locale
msg4 = i18n_get_messages("cancel", , "ja");             // "Missing Translation", because "cancel" is not defined in "ja" locale, and also not defined in the fallback locale

// dynamic messages
ref_msg1 = i18n_create_ref_message("ref_msg1", "hello");            // "Hello World!", "Halo Dunia!", or "こんにちは世界!"
ref_msg2 = i18n_create_ref_message("ref_msg2", "world.stand");      // "The World!", "Missing Translation", or "ザ・ワールド!"
ref_msg3 = i18n_create_ref_message("ref_msg3", "info");             // always "Missing Translation", because "info" is not defined in any locale
Key Pressed - Space
// change the locale
// i18n_set_locale(code, [update_refs], [i18n])

switch (i18n_get_locale()) {
    case "en":
        i18n_set_locale("id");      // ref_msg1 = "Halo Dunia!", ref_msg2 = "Missing Translation",
        break;                      // ref_msg3 = "Missing Translation" 

    case "id":
        i18n_set_locale("ja");      // ref_msg1 = "こんにちは世界!", ref_msg2 = "ザ・ワールド!"
        break;                      // ref_msg3 = "Missing Translation" 

    case "ja":
        i18n_set_locale("en");      // ref_msg1 = "Hello World!", ref_msg2 = "The World!", 
        break;                      // ref_msg3 = "Missing Translation" 
}
en.json
{
    "hello": "Hello World!",
    "bye": "Bye World!",
    "world": {
        "stand": "The World!",
        "effect": "Stop the Time!"
    }
}
id.json
{
    "hello": "Halo Dunia!",
    "bye": "Sampai Jumpa Dunia!"
}
ja.json
{
    "hello": "こんにちは世界!",
    "bye": "さようなら世界!",
    "world": {
        "stand": "ザ・ワールド!",
        "effect": "時よ止まれ!"
    }
}
The message interpolation, pluralization, and dictionary features are still working as usual even with the fallback mechanism.

The data you passed to the i18n_get_messages() function or i18n_create_ref_message() function is also passed to the message in the fallback locale (and even to the default message if the message is not found in the fallback locale).

Localized Asset Fallback

The localized asset fallback is triggered when the asset is not found in the current locale. It will take the asset from the fallback locale instead, or the asset in the default locale if the asset is not found in the fallback locale.

You're recommended to read the Localized Assets section first before proceeding to this section.

Create Event
// assume the system is initialized on global variable
// assume the fallback locale is "en"
// i18n_create_ref_asset(var_name, locale_asset, [i18n])

// create the asset references
my_spr = i18n_create_ref_asset("my_spr", {
    en: sprSplashEn,
    id: sprSplashId,
    ja: sprSplashJa
});

my_info_spr = i18n_create_ref_asset("my_info_spr", {
    en: sprInfoEn,
    id: sprInfoId
});

my_snd = i18n_create_ref_asset("my_snd", {
    en: sndVoiceEn,
    id: sndVoiceId,
    ja: sndVoiceJa
});

my_sfx = i18n_create_ref_asset("my_sfx", {
    id: sfxButtonId,
    ja: sfxButtonJa
});

my_obj = i18n_create_ref_asset("my_obj", {
    en: objPlayerEn
});
Key Pressed - Space
// change the locale
// i18n_set_locale(code, [update_refs], [i18n])

switch (i18n_get_locale()) {
    case "en":
        i18n_set_locale("id");      // my_spr = sprSplashId, my_info_spr = sprInfoId, my_snd = sndVoiceId, 
        break;                      // my_sfx = sfxButtonId, my_obj = objPlayerEn ("id" locale doesn't have the asset)

    case "id":
        i18n_set_locale("ja");      // my_spr = sprSplashJa, my_info_spr = sprInfoEn ("ja" locale doesn't have the asset), 
        break;                      // my_snd = sndVoiceJa, my_sfx = sfxButtonJa, my_obj = objPlayerEn ("ja" locale doesn't have the asset)

    case "ja":
        i18n_set_locale("en");      // my_spr = sprSplashEn, my_info_spr = sprInfoEn, my_snd = sndVoiceEn, 
        break;                      // my_sfx = sfxButtonJa (fallback locale doesn't have the asset, so it won't be changed), my_obj = objPlayerEn
}
Key Pressed - Enter
// play the sound
audio_play_sound(my_snd, 1, false);
audio_play_sound(my_sfx, 1, false);
Draw Event
// draw the sprite
draw_sprite(my_spr, 0, 100, 50);
draw_sprite(my_info_spr, 0, 100, 200);

The i18n_get_locale() function will return the current locale code. You can use this function to change the locale.

Take note that the i18n_set_locale() function will also update all references (message and asset) by default. So, you don't need to update the references manually using i18n_update_refs().
  It's that easy to implement the fallback mechanism in your game!