Nested Message Data

This section is a bit advanced. You can skip this section if you're not using the linked message.
You need to read about the named data interpolation and linked message first before you continue reading this section.

If you're using linked message, you may want to pass a data to the linked message. For example, you have a message like this:

en.json
{
    "greet": "Welcome to GM-I18n, {name}! [[greet2]]",
    "greet2": "Hope this library useful for you, {who}!"
}
id.json
{
    "greet": "Selamat datang di GM-I18n, {name}! [[greet2]]",
    "greet2": "Harap library ini bermanfaat untukmu, {who}!"
}

And then you get the static message or create a message reference like this:

Create Event
// assume the system is initialized on global variable

// static message
my_msg = i18n_get_messages("greet", {
    name : "John",
    who : "John"
}, "en");

// dynamic message
global.ref_msg = i18n_create_ref_message("global.ref_msg", "greet", {
    name : "John",
    who : "John"
});

The my_msg and global.ref_msg variable will return the same message:

Welcome to GM-I18n, John! Hope this library useful for you, {who}!

The {who} is not replaced, even though we've passed the data. Why is that? It's because the data is not passed to the linked message. The data is only passed to the main message (greet), but not to the linked message (greet2).

The GM-I18n system set this rule because:
  1. It's confusing. Should we pass the data to the main message, or to the linked message? What if we want to pass different data to the linked message?
  2. It's dangerous. What if the linked message is used in another message, but with different data? It will cause a data collision. For example, in the example above, what if we're using the same placeholder ({name}) in the greet2 instead of {who}, but with different data?
  3. It's unnecessary. You can just pass the data to the linked message directly, without passing it to the main message first.
  4. It's not always needed. The linked message can be used without any data, and it will still work as expected.
  5. It's not consistent. The linked message should be treated as a separate message, not as a part of the main message.
You'll only get this issue when you're using the named data. The indexed data ({0}, {1}, {2}, etc.) is not affected by this issue, because the indexed data doesn't support linked message.

You can still pass the data to the linked message, but you need to do it manually.

Data in Linked Messages

As I mentioned before, the linked messages should be treated as a separate message.

To pass the data to the linked message, you need to use a child or child_* key in the main message data.

Create Event
// assume the system is initialized on global variable

// static message
my_msg = i18n_get_messages("greet", {
    name : "John",                      // interpolate {name} in "greet" message
                       
    child : {                           // act as the "data" for the linked message
        who : "John"                    // interpolate {who} in "greet2" message
    }
}, "en");

// dynamic message
global.ref_msg = i18n_create_ref_message("global.ref_msg", "greet3", {
    user : "Reader of GM-I18n",         // interpolate {user} in "greet3" message

    child : {                           // works the same as the static message
        user : "John"                   // using the same key (`user`) is fine, because it's in different "scope"
    }
});
en.json
{
    "greet": "Welcome to GM-I18n, {name}! [[greet2]]",
    "greet2": "Hope this library useful for you, {who}!",
    "greet3": "Hello, {user}! This is a main message. [[greet4]]",
    "greet4": "And this is a child message, {user}!"
}
id.json
{
    "greet": "Selamat datang di GM-I18n, {name}! [[greet2]]",
    "greet2": "Harap library ini bermanfaat untukmu, {who}!",
    "greet3": "Halo, {user}! Ini adalah pesan induk. [[greet4]]",
    "greet4": "Dan ini adalah pesan anak, {user}!"
}

That's the basic of passing data to the linked message. Are you ready for the next section?


Default Child Data

The child key is used to pass the data to all of the linked message in the main message. It's good choice if you want to pass the same data to all of the linked message.

Think the child key as an else block in an if-else statement, or a default keyword in a switch statement. You can override the default data by using the child_* key. But we will discuss about it in the next section.

Create Event
// assume the system is initialized on global variable

// applicable on both static and dynamic message
// in this example, we will only focus on the data passing

// no data passed
npc1 = i18n_get_messages("dialog.npc_1", , "en");       // return the raw string in `dialog.npc_1`, because the linked message is not activated
npc1 = i18n_get_messages("dialog.npc_1", {}, "en");     // remember, you still need to pass the data (struct), even if it's empty, to activate the linked message
                                                        // "Do you have 20 apples? How about trading them with me for 5 bamboos? " (in English)
msg_arr = [
    i18n_get_messages("welcome", {                      // "Selamat datang di desa Sukamakan, John! Harap betah di desa ini!" (in Indonesian)
        village: "Sukamakan",
        name: "John"
    }, "id")
];

// only pass to the child message
npc2 = i18n_create_ref_message("npc2", "dialog.npc_2", {
    child : {                                               // pass the data to the child message (`item.apple_trait`, `item.bamboo_trait`, and `item.potion_trait`)
        adj : "Shiny"                                       // "adj" is the placeholder in those child messages
    }                                                       // all of them will be replaced with "Shiny"
});

global.npc3 = i18n_get_messages("dialog.npc_3", {
    child : ["Fresh"]                                       // using indexed data? why not? GM-I18n system accepts both named and indexed data in the `child` key
});                                                         // it's because the system treats the `child` key as a separate message

// with pluralization
my_apple = 10;
buy_apple = 5;
confirm_buy = i18n_create_ref_message("confirm_buy", "shop.buyable", {
    plural: function(val) {
        return (val > 1) ? 1 : 0;                   // explicitly return the index value
    },
    plural_value: my_apple,                         // the system will do the pluralization first before processing the `child` key
    suffix: "s",
    
    child: {                                        // pass the data to the child message (`shop.template_1`)
        count: buy_apple,                           // will return "Are you sure you want to buy 5 Apples?"
        item: i18n_get_messages("item.apple")
    }
});

// nested child
global.npc_dialogs = {
    npc4 : i18n_create_ref_message("global.npc_dialogs.npc4", "dialog.npc_4.num_1", {   // activate the `dialog.npc_4.num_2` linked message
        child : {                           // activate the `welcome` child message
            child : {                       // pass `village` and `name` to the `welcome` message 
                village: "Sukamakan",       // and activate the `welcome_2` grandchild message
                name: "John"
            }
        }
    })
}
en.json
{
    "welcome": "Welcome to {village} village, {name}! [[welcome_2]]",
    "welcome_2": "Hope you enjoy your stay in this village!",
    "shop": {
        "template_1": "Are you sure you want to buy {count} {item}",
        "buyable": "[[shop.template_1]]? | [[shop.template_1]]{suffix}?"
    },
    "item": {
        "owned": "You already have {count} {item}.",
        "not_owned": "You don't have this {item}. [[shop.confirm]]",
        "apple": "Apple",
        "apple_trait": "{adj} Apple",
        "bamboo": "Bamboo",
        "bamboo_trait": "{adj} Bamboo",
        "potion": "Potion",
        "potion_trait": "{adj} Potion",
        "chicken": "Chicken",
        "chicken_trait": "{0} Chicken",
        "duck": "Duck",
        "duck_trait": "{0} Duck"
    },
    "dialog": {
        "npc_1": "Do you have 20 [[item.apple]]s? How about trading them with me for 5 [[item.bamboo]]s?",
        "npc_2": "Welcome to my shop! Take a look at this [[item.apple_trait]], [[item.bamboo_trait]], and [[item.potion_trait]]. Do you want to buy any of them?",
        "npc_3": "Ah, how about [[item.chicken_trait]] and [[item.duck_trait]] then?",
        "npc_4": {
            "num_1": "Is this your first time to visit our village? [[dialog.npc_4.num_2]]",
            "num_2": "Huh, really?\nThen, [[welcome]]",
        }
    }
}
id.json
{
    "welcome": "Selamat datang di desa {village}, {name}! [[welcome_2]]",
    "welcome_2": "Harap betah di desa ini!",
    "shop": {
        "template_1": "Apakah kamu yakin ingin membeli {count} {item}",
        "buyable": "[[shop.template_1]]? | [[shop.template_1]]{suffix}?"
    },
    "item": {
        "owned": "Kamu sudah memiliki {count} {item}.",
        "not_owned": "Kamu tidak memiliki ini {item}. [[shop.confirm]]",
        "apple": "Apel",
        "apple_trait": "{adj} Apel",
        "bamboo": "Bambu",
        "bamboo_trait": "{adj} Bambu",
        "potion": "Ramuan",
        "potion_trait": "{adj} Ramuan",
        "chicken": "Ayam",
        "chicken_trait": "{0} Ayam",
        "duck": "Bebek",
        "duck_trait": "{0} Bebek"
    },
    "dialog": {
        "npc_1": "Apakah kamu memiliki 20 [[item.apple]]? Bagaimana dengan menukar mereka dengan saya untuk 5 [[item.bamboo]]?",
        "npc_2": "Selamat datang di toko saya! Lihatlah ini [[item.apple_trait]], [[item.bamboo_trait]], dan [[item.potion_trait]]. Apakah Anda ingin membeli salah satu dari mereka?",
        "npc_3": "Ah, bagaimana dengan [[item.chicken_trait]] dan [[item.duck_trait]]?",
        "npc_4": {
            "num_1": "Apakah ini pertama kalinya kamu datang ke desa kami? [[dialog.npc_4.num_2]]",
            "num_2": "Huh, benarkah?\nKalau begitu, [[welcome]]"
        }
    }
}
You can nest the child key as deep as you want, but it's not recommended to have a very deep nesting, because it can be hard to manage the data. Just look at the example above, it's already 3 levels deep. It's already hard to read, right?
The pluralization works properly in the main message (either static or dynamic). But, if it goes to the child message or deeper, the pluralization will only accept static pluralization. So, even if you pass a function to the plural key (with plural_value) in the child data, it will only executed once (when the message is created), and can't be updated later using i18n_update_plurals() function.

Specific Child Data

The child key is used to pass the data to all of the linked message in the main message. But, what if you want to pass different data to different linked message?

You can use the child_* key to pass the data to the specific linked message. The * is the key of the linked message. For example, if you want to pass the data to the greet2 linked message, you can use the child_greet2 key.

Create Event
// assume the system is initialized on global variable

// applicable on both static and dynamic message
// in this example, we will only focus on the data passing

// activate the linked message feature, but not passing any data to the linked message
msg_struct = {
    my_msg : i18n_get_messages("welcome", {                 // "Selamat datang di desa Sukamakan, Agus! Harap betah di desa ini!" (in Indonesian)
        village: "Sukamakan",
        name: "Agus"
    }, "id")
};

// only pass to the child message
npc2 = i18n_create_ref_message("npc2", "dialog.npc_2", {
    // specific child data
    child_item_apple_trait : {                              // pass the data to the `item.apple_trait` linked message
        adj: "Bad"                                          // "adj" is the placeholder in the `item.apple_trait` message
    },                                                      // the {adj} placeholder in this linked message will be replaced with "Bad"
    child_item_bamboo_trait : {
        adj: "Premium"
    },

    // default child data
    child : {                                               // will only be applied to the `item.bamboo_trait` and `item.potion_trait` linked messages
        adj : "Shiny"                                       // the {adj} placeholder all of those non-specified child data will be replaced with "Shiny"
    }                                                       // "Welcome to my shop! Take a look at this Bad Apple, Premium Bamboo, and Shiny Potion. Do you want to buy any of them?"
});

global.npc3 = i18n_get_messages("dialog.npc_3", {           // for specified child data in indexed data message, you can just use a diferent index value
    child : ["Fresh", "Beautiful"]                          // {0} is "Fresh", {1} is "Beautiful"
});                                                         // "Ah, how about Fresh Chicken and Beautiful Duck then?"

// with pluralization
my_coins = global.coins;                                    // assume you have declared `global.coins` somewhere in your code
buy_resc = "Copper Coin";

confirm_buy = i18n_create_ref_message("confirm_buy", "dialog.npc_5", {
    plural: function(val) {
        return (val >= 500) ? 1 : 0;                // explicitly return the index value
    },                                              // use form 2 (index 1) if the player have 500 coins or more, otherwise use form 1 (index 0)
    plural_value: my_coins,
    resc: buy_resc,
    
    // pass a data to `item.bamboo_trait` child message
    child_item_bamboo_trait: {
        adj: "Premium"
    },
    
    // pass a data to other child message
    child: {
        adj: "Legendary"
    }
});

// nested child
global.npc_dialogs = {
    npc4 : i18n_create_ref_message("global.npc_dialogs.npc4", "dialog.npc_4.num_1", {   // activate the `dialog.npc_4.num_2` linked message
        child : {                           // activate the `welcome` child message
            child_welcome : {               // pass `village` and `name` to the `welcome` message 
                village: "Sukamakan",       // there's no `child` key, but it still work as long as you use the `child_*` key
                name: "John"
            }
        }
    })
}
en.json
{
    "welcome": "Welcome to {village} village, {name}! [[welcome_2]]",
    "welcome_2": "Hope you enjoy your stay in this village!",
    "shop": {
        "template_1": "Are you sure you want to buy {count} {item}",
        "buyable": "[[shop.template_1]]? | [[shop.template_1]]{suffix}?"
    },
    "item": {
        "owned": "You already have {count} {item}.",
        "not_owned": "You don't have this {item}. [[shop.confirm]]",
        "apple": "Apple",
        "apple_trait": "{adj} Apple",
        "bamboo": "Bamboo",
        "bamboo_trait": "{adj} Bamboo",
        "potion": "Potion",
        "potion_trait": "{adj} Potion",
        "chicken": "Chicken",
        "chicken_trait": "{0} Chicken",
        "duck": "Duck",
        "duck_trait": "{1} Duck"
    },
    "dialog": {
        "npc_1": "Do you have 20 [[item.apple]]s? How about trading them with me for 5 [[item.bamboo]]s?",
        "npc_2": "Welcome to my shop! Take a look at this [[item.apple_trait]], [[item.bamboo_trait]], and [[item.potion_trait]]. Do you want to buy any of them?",
        "npc_3": "Ah, how about [[item.chicken_trait]] and [[item.duck_trait]] then?",
        "npc_4": {
            "num_1": "Is this your first time to visit our village? [[dialog.npc_4.num_2]]",
            "num_2": "Huh, really?\nThen, [[welcome]]",
        },
        "npc_5": "Sorry, your {resc}s is not enough to buy this [[item.bamboo_trait]]. | Do you want to buy [[item.bamboo_trait]] for {plural_value} {resc}s, sir? I'll add a [[item.apple_trait]] for you as a bonus!"
    }
}
id.json
{
    "welcome": "Selamat datang di desa {village}, {name}! [[welcome_2]]",
    "welcome_2": "Harap betah di desa ini!",
    "shop": {
        "template_1": "Apakah kamu yakin ingin membeli {count} {item}",
        "buyable": "[[shop.template_1]]? | [[shop.template_1]]{suffix}?"
    },
    "item": {
        "owned": "Kamu sudah memiliki {count} {item}.",
        "not_owned": "Kamu tidak memiliki ini {item}. [[shop.confirm]]",
        "apple": "Apel",
        "apple_trait": "{adj} Apel",
        "bamboo": "Bambu",
        "bamboo_trait": "{adj} Bambu",
        "potion": "Ramuan",
        "potion_trait": "{adj} Ramuan",
        "chicken": "Ayam",
        "chicken_trait": "{0} Ayam",
        "duck": "Bebek",
        "duck_trait": "{1} Bebek"
    },
    "dialog": {
        "npc_1": "Apakah kamu memiliki 20 [[item.apple]]? Bagaimana dengan menukar mereka dengan saya untuk 5 [[item.bamboo]]?",
        "npc_2": "Selamat datang di toko saya! Lihatlah ini [[item.apple_trait]], [[item.bamboo_trait]], dan [[item.potion_trait]]. Apakah Anda ingin membeli salah satu dari mereka?",
        "npc_3": "Ah, bagaimana dengan [[item.chicken_trait]] dan [[item.duck_trait]]?",
        "npc_4": {
            "num_1": "Apakah ini pertama kalinya kamu datang ke desa kami? [[dialog.npc_4.num_2]]",
            "num_2": "Huh, benarkah?\nKalau begitu, [[welcome]]"
        },
        "npc_5": "Maaf, {resc} kamu tidak cukup untuk membeli ini [[item.bamboo_trait]]. | Apakah kamu ingin membeli [[item.bamboo_trait]] dengan harga {plural_value} {resc}, tuan? Aku akan menambahkan satu [[item.apple_trait]] untuk kamu sebagai bonus!",
    }
}
You can use both child and child_* keys at the same time, either static or dynamic message. Use those as efficient as possible.

As you can see in the example above, the dot separator ([key].[subkey]) of the message key used in child_* is replaced by underscore ([key]_[subkey]). You need to follow this rule to make sure the child_* key works properly.

The child_* key can be defined in the main message or in the child message. You can even define 2 or more child_* key, like you're using if-else statement.

You can also use the child_* key in the child message or deeper, but it's not recommended to have a very deep nesting, because it can be hard to manage the data.
Same as the default child data, the pluralization works properly in the main message (either static or dynamic). But, if it goes to the child message or deeper, the pluralization will only accept static pluralization. So, even if you pass a function to the plural key (with plural_value) in the child data, it will only executed once (when the message is created), and can't be updated later using i18n_update_plurals() function.

  It seems hard to understand for the first time. But, don't worry, it will be easier as you go along!