Pluralization
Pluralization is a process of handling the plural form of a word. It's also known as plural handling
or plural form
in other localization system. It's also a powerful feature that makes any internationalization system complete!
Let's say, you have a message that says "You have {plural_value}
apple". It's correct if you have only one apple. But if you have more than one apple, it should be "You have {plural_value}
apples", right? That's where pluralization comes in handy!
Static Pluralization
GM-I18n provides a simple pluralization feature that can handle the plural form of a word/phrase in the message.
Format:
form0 | form1 | ...
Access:<index>
or{plural: <index>}
Used In:i18n_get_messages()
,i18n_create_ref_message()
,i18n_draw_message()
For the static pluralization, the simplest way, you need to provide 2 forms of the word/phrase in the message. Generally, the first form is for singular, and the second form is for plural. And then you can pass the index of the form you want to use in the data.
// assume the system is initialized on global variable
// i18n_get_messages(key, [data], [locale], [i18n])
// i18n_create_ref_message(var_name, key, [data], [i18n])
// static messages, static pluralization
msg1 = i18n_get_messages("have_apple"); // "You don't have any apple | You have apple(s)", raw message
msg2 = [ // in an array
i18n_get_messages("have_apple", 0) // "You don't have any apple", 0 = directly use the first form
];
msg3 = { // in a struct
my_msg : i18n_get_messages("have_apple", 1, "id"); // "Kamu punya apel", 1 = directly use the second form
};
msg4 = i18n_get_messages("have_apple_cnt", {plural: 1}); // "I have 1 apple", {plural: 1} = use the second form through the `plural` key
msg5 = i18n_get_messages("have_apple_cnt", { // "I have 10 apples", {plural: 2} = use the third form, {count: 10} = replace the {plural_value} placeholder
plural : 2, // need to set the index value of the `plural` key manually
plural_value : 10 // interpolate the {plural_value} placeholder
});
// dynamic messages, static pluralization, no difference with static messages
global.ref_msg1 = i18n_create_ref_message("global.ref_msg1", "have_apple");
global.ref_msg2 = [
i18n_create_ref_message("g.ref_msg2.0", "have_apple", 0)
];
ref_msg3 = {
my_msg : i18n_create_ref_message("ref_msg3.my_msg", "have_apple", 1, "id")
}
global.ref_msg4 = i18n_create_ref_message("global.ref_msg4", "have_apple_cnt", {plural: 1});
ref_msg5 = i18n_create_ref_message("ref_msg5", "have_apple_cnt", {
plural : 2,
plural_value : 10
});
<index>
or {plural: <index>}
to access the plural form. Both are valid. But it's recommended to use the {plural: <index>}
because it's more readable and flexible. You can see the example in the next section. plural
key after creating the message, it won't affect the plural form in the message. You can't use the pluralization feature with the indexed data. You need to use the named data instead. See the Interpolation section for more information.
Dynamic Pluralization
Dynamic pluralization use the same format as static pluralization, but the forms are dynamic. So, you can change the plural form in the message, even after creating the message.
Format:
form0 | form1 | ...
Access:<index>
or{plural: <index>}
or{plural: <function>, plural_value: <value>}
Used In:i18n_get_messages()
,i18n_create_ref_message()
,i18n_draw_message()
You can make your own pluralization rule in the plural
key in the named data. The function will be called with the plural_value
as the parameter, and then it will return the index
of the plural form you want to use. It's great for complex pluralization rule!
In Static Messages
This method is quite easy to implement the dynamic pluralization. You just need to update the message every step, and the pluralization will be updated automatically based on your pluralization rule.
Pros:
- Quite easy to implement.
- No need to create the message reference.
- Can be used in anywhere in the game, just like a static message.
Cons:
- Need to update the message every step (may cause performance issue).
- Only support with direct pluralization (by passing
<index>
to thedata
parameter in the message).- Not suitable for complex pluralization rule.
- No natural support for interpolated, linked, or nested message.
// assume the system is initialized on global variable
// the value to be passed to the pluralization function
apple_count = 0;
plural_index = 0;
// a simple method for pluralization rule
plural_rule = function() {
// modify the plural_index based on the apple_count value
plural_index = !apple_count ? 0 : 1;
}
// static messages in instance variable
msg1 = i18n_get_messages("have_apple_cnt", 0, "en"); // "I don't have any apple", will updated in Step Event
msg2 = [
"" // empty string, will updated in Step Event
];
msg3 = {
my_msg : i18n_get_messages("confirm", 0, "en") // "No", will updated in Step Event
};
// static messages in global variable
global.my_msg = i18n_get_messages("have_apple_cnt", {
plural : 0, // "Aku tidak punya apel", will updated in Step Event
plural_value : apple_count
}, "id");
global.my_arr = [
i18n_get_messages("shop.buy", plural_index, "en") // "Buy 1 {name}? | Buy {plural_value} {name}{suffix}?", will updated in Step Event
];
global.my_struct = {
my_msg : i18n_get_messages("confirm", 1, "en") // "Yes", will updated in Step Event
};
You can also store a value in a variable (such as
plural_index
), and then pass the variable to the data
parameter.Using Direct Drawing
This method is the simplest and quickest way to implement the dynamic pluralization. You just need to pass the plural index (or a simple function that return the index) and the key message to the i18n_draw_message()
function.
Pros:
- Super easy and quick to implement. Good choice if you only need to draw the message.
- No need to create the message reference, not even create a variable for storing the message.
- Can draw a static or dynamic message, with static or dynamic pluralization.
Cons:
- Only used for drawing the message. The
Draw Event
orDraw GUI Event
is the only place you can use this method.- May cause a performance issue if you have a lot of message keys in that locale (like, 1000+ keys in a locale).
- Only support with direct pluralization (by passing
<index>
to thedata
parameter in the message).- Not suitable for complex pluralization rule.
- No natural support for interpolated, linked, or nested message.
// assume the system is initialized on global variable
// the value to be passed to the pluralization function
apple_count = 0;
plural_index = 0;
// a simple method for pluralization rule
plural_rule = function() {
// modify the plural_index based on the apple_count value
plural_index = !apple_count ? 0 : 1;
}
@:
prefix to the text
parameter in the i18n_draw_message()
function to use the message key instead of the actual text. It's useful if you want to use the same message key in different locale (so it become a dynamic message). See the example above. The pluralization function (ternary operator in the example above) is called every time you draw the message. So, it's better to make the function as simple as possible to avoid performance issue.
You can also store a value in a variable (such as
plural_index
), and then pass the variable to the data
parameter.The dynamic message in this method come with a performance cost. GM-I18n system will lookup the message from the locale data every time you draw the message. So, use it wisely.
Using Message Reference
This method is the most flexible and powerful way to implement the dynamic pluralization. It's recommended for you to implement the dynamic pluralization with this method.
Pros:
- A true dynamic message.
- Really flexible and powerful to implement the dynamic pluralization.
- Suitable for complex pluralization rule.
- Can apply interpolation, linked message, and nested message.
- Really fast performance. The message is only lookup once, and then it will be updated if the locale is changed.
- For the pluralization, you don't need to call the update function every time you want to update the message. Just update the data (
plural_value
), and the message will be updated automatically.
Cons:
- Take more effort to implement.
- The pluralization rule may be a bit complex if you want to support multiple locale.
- You need to manage the message reference yourself (such as updating the data).
// assume the system is initialized on global variable
// the value to be passed to the pluralization function
apple_count = 0;
plural_index = 0;
// dynamic messages and pluralization
// in instance variable
ref_msg1 = i18n_create_ref_message("simple_ref", "confirm", {
plural: function(plural_value) { // the function for simple pluralization rule
return plural_value >= 10 ? 0 : 1; // if plural_value is 10 or more, use the first form (index 0). otherwise, use the second form (index 1)
},
plural_value: apple_count // the value to be passed to the pluralization function
});
// in global variable
global.ref_msg2 = i18n_create_ref_message("global.ref_msg1", "have_apple_cnt", {
plural: function(plural_value) { // the function for complex pluralization rule, you need to make 1 parameter to pass the `plural_value`
if (i18n_get_locale() == "en") { // en locale has 3 forms
return !plural_value ? 0 : (plural_value == 1 ? 1 : 2); // if plural_value is 0, use the first form (index 0). if plural_value is 1, use the second form (index 1). otherwise, use the third form (index 2)
} else if (i18n_get_locale() == "id") { // id locale has only 2 forms
return !plural_value ? 0 : 1; // if plural_value is 0, use the first form (index 0). otherwise, use the second form (index 1)
}
},
plural_value: apple_count // the value to be passed to the pluralization function
});
// in an array
ref_msg3 = [
i18n_create_ref_message("ref_msg3.0", "shop.buy", {
plural: function(plural_value) {
return plural_value == 1 ? 0 : 1; // if plural_value is 1, use the first form (index 0). otherwise, use the second form (index 1)
},
plural_value: apple_count, // because we are using named data, the interpolation will work
name: "apple", // if plural_value is 0, the message is "Buy 1 apple?" or "Beli 1 apple?" (the "apple" still in english!)
suffix: "s" // otherwise, the message is "Buy {plural_value} apples?" or "Beli {plural_value} apple?" (the {plural_value} is interpolated, but the "apple" still in english!})
})
];
// in a struct
global.ref_msg4 = {
my_msg : i18n_create_ref_message("g.ref_msg4.my_msg", "confirm", {
plural: function(plural_value) {
return plural_value >= 10 ? 0 : 1;
},
plural_value: apple_count
}),
my_arr : [
i18n_create_ref_message("global.ref_msg4.my_arr.0", "shop.confirm", {
plural: function(plural_value) {
if (i18n_get_locale() == "en") { // en locale has 3 forms
return !plural_value ? 0 : (plural_value == 1 ? 1 : 2); // if plural_value is 0, use the first form (index 0). if plural_value is 1, use the second form (index 1). otherwise, use the third form (index 2)
} else if (i18n_get_locale() == "id") { // id locale has only 2 forms
return !plural_value ? 0 : 1; // if plural_value is 0, use the first form (index 0). otherwise, use the second form (index 1)
}
},
plural_value: apple_count,
name: "apple",
resc: "copper coin",
suffix: "s"
})
]
};
// see the key pressed event for the update function
plural
in the data is the rule that return the index of the plural form you want to use. You need to make sure that the function have 1 parameter, and return the correct index. The
plural_value
is not limited to number
type. You can use any data type that you want. For example, you can use string
, array
, struct
, etc. But of course, the simplest and most common type is a number
type. Though the
plural_value
is reserved for pluralization, you can still use it for interpolation as well. You can get a dynamic interpolation by updating the
plural_value
in the message reference using i18n_update_plurals()
function. If you're using both pluralization and interpolation in the message, the system will process the pluralization first, and then the interpolation.
plural
and plural_value
in the data is reserved for pluralization. You can't use it for other purpose. You need to pass the
true
to the update_refs
parameter in the i18n_update_plurals()
function after you change the plural_value
in the message reference. Otherwise, the message reference won't be updated. See the example in the Key Pressed - Up
and Key Pressed - Down
event. For optimization, you should only pass the
true
to the update_refs
parameter in the i18n_update_plurals()
function on the LAST message reference that you want to update. Passing true
on every i18n_update_plurals()
function may cause performance issue. See the correct usage in the Key Pressed - Up
and Key Pressed - Down
event. i18n_update_plurals()
in any event that updated every step (such as Step Event
, Draw Event
, etc.)! It may cause a performance issue, and it's even worse than updating the message every step.Summary
There are 3 ways to implement the dynamic pluralization in GM-I18n. Each have their own pros and cons. You need to choose the one that best fit your needs, or just mix and match them!
- Updating the Message Every Step
- Pros: Quite easy to implement. No need to create the message reference.
- Cons: Not suitable for complex pluralization rule. No natural support for interpolated, linked, or nested message.
- Direct Drawing
- Pros: Super easy and quick to implement. Good choice if you only need to draw the message.
- Cons: Only used for drawing the message. Not suitable for complex pluralization rule. No natural support for interpolated, linked, or nested message.
- Using Message Reference
- Pros: The most flexible and powerful way to implement the pluralization. Suitable for complex pluralization rule. Have natural support for interpolated, linked, or nested message.
- Cons: A bit more complex to implement. Need to create the message reference.
You can't use the pluralization feature with the indexed data. You need to use the named data instead. See the Interpolation section for more information.
You need to return the index of the plural form in the plural
function explicitly (such as 0
or 1
). If you don't the system won't know which plural form you want to use. See the example above which return the explicit index in the plural
function using ternary operator.
You can customize the starting pluralization index (default: 0
) and the delimiter (default: |
) in the i18n_create()
function.