Nanfeng

Notes on software development, code, and curious ideas

Localization Parameters and Rich Text in Cocos Creator

Localization is common in Cocos Creator. Plain strings are easy, but rich text and parameters require additional handling. Parameters are especially important because word order differs between languages, so fixed %s positions are not always sufficient.

Rich text

You can either embed Cocos rich-text markup directly in translations, or use custom semantic tags and convert them with regular expressions. The second approach keeps the translation format easier to control.

Suppose “Terms” and “Privacy Policy” must be blue and clickable:

1
2
3
4
"Terms": {
"zh-CN": "[str1]同意我们的[/str1][str2]使用条款[/str2]和[str3]隐私政策[/str3]",
"en-US": "[str1]Agree to our [/str1][str2]Terms[/str2] and [str3]Privacy Policy[/str3]"
}

Assign the converted string to RichText:

1
this.richText.string = this.parseToRichText(Lang.getText('Terms'));
1
2
3
4
5
6
parseToRichText(text: string): string {
return text
.replace(/\[str1\](.*?)\[\/str1\]/g, '<color=#a1a3bfC0>$1</color>')
.replace(/\[str2\](.*?)\[\/str2\]/g, '<color=#1583ff><u><on click="onClick" param="terms">$1</on></u></color>')
.replace(/\[str3\](.*?)\[\/str3\]/g, '<color=#1583ff><u><on click="onClick" param="privacy">$1</on></u></color>');
}

Positional parameters

If parameter order is identical across languages, %s is adequate:

1
2
3
4
"Terms": {
"zh-CN": "同意我们的%s和%s",
"en-US": "Agree to our %s and %s"
}
1
this.label.string = Lang.getText('Terms', 'Terms', 'Privacy Policy');

Named parameters

When word order differs, use named placeholders:

1
2
3
4
"Terms": {
"zh-CN": "同意我们的{term}和{privacy}",
"en-US": "Agree to our {term} and {privacy}"
}
1
2
3
4
this.label.string = Lang.getText('Terms', {
term: 'Terms',
privacy: 'Privacy Policy'
});

This helper supports both formats:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static getText(key: string, ...args: any[]): string {
const langConfig = this.config[key]?.[this.curLanguageStr];
if (!langConfig) return '';

const template = langConfig;
if (args.length === 1 && typeof args[0] === 'object' && !Array.isArray(args[0])) {
const params = args[0] as Record<string, string>;
return template.replace(/\{(\w+)\}/g, (_, key) => params[key] ?? `{${key}}`);
}

let i = 0;
return template.replace(/%s/g, () => args[i++] ?? '');
}

Treat this as a starting point and adapt the tags, escaping rules, and parameter validation to your project.

+