Files
armorpaint/paint/sources/translator.ts
T

199 lines
6.6 KiB
TypeScript
Raw Normal View History

2024-03-09 14:52:33 +01:00
2024-03-11 15:10:18 +01:00
let translator_translations: map_t<string, string> = map_create();
2024-03-21 21:06:41 +01:00
// The font index is a value specific to font_cjk.ttc
let translator_cjk_font_indices: map_t<string, i32> = null;
2024-03-09 14:52:33 +01:00
let translator_last_locale: string = "en";
2024-11-08 23:46:39 +01:00
let _translator_load_translations_cjk_font_path: string;
let _translator_load_translations_cjk_font_disk_path: string;
let _translator_init_font_cjk: bool;
let _translator_init_font_font_path: string;
let _translator_init_font_font_scale: f32;
2024-03-09 14:52:33 +01:00
2024-03-22 14:17:49 +01:00
// Mark strings as localizable in order to be parsed by the extract_locale script
// The string will not be translated to the currently selected locale though
2024-05-03 21:29:39 +02:00
function _tr(s: string): string {
2024-03-09 14:52:33 +01:00
return s;
}
2024-03-22 14:17:49 +01:00
// Localizes a string with the given placeholders replaced (format is "{placeholder_name}")
// If the string isn't available in the translation, this method will return the source English string
2024-03-11 15:10:18 +01:00
function tr(id: string, vars: map_t<string, string> = null): string {
2025-03-02 17:00:40 +01:00
let translation: string = string_copy(id);
2024-03-09 14:52:33 +01:00
// English is the source language
2025-03-02 17:00:40 +01:00
if (config_raw.locale != "en") {
if (string_index_of(id, "\n") > -1) {
id = string_replace_all(id, "\n", "\\n");
}
let s: string = map_get(translator_translations, id);
if (s != null) {
if (string_index_of(s, "\\n") > -1) {
s = string_replace_all(s, "\\n", "\n");
}
translation = s;
}
2024-03-09 14:52:33 +01:00
}
if (vars != null) {
2024-04-12 12:51:40 +02:00
let keys: string[] = map_keys(vars);
2024-03-22 14:17:49 +01:00
for (let i: i32 = 0; i < keys.length; ++i) {
2024-05-03 21:29:39 +02:00
let search: string = "{" + keys[i] + "}";
translation = string_replace_all(translation, search, map_get(vars, keys[i]));
2024-03-09 14:52:33 +01:00
}
}
return translation;
}
// (Re)loads translations for the specified locale
function translator_load_translations(new_locale: string) {
2024-03-21 21:06:41 +01:00
if (translator_cjk_font_indices == null) {
translator_cjk_font_indices = map_create();
map_set(translator_cjk_font_indices, "ja", 0);
map_set(translator_cjk_font_indices, "ko", 1);
map_set(translator_cjk_font_indices, "zh_cn", 2);
map_set(translator_cjk_font_indices, "zh_tw", 3);
map_set(translator_cjk_font_indices, "zh_tw.big5", 4);
}
2024-03-09 14:52:33 +01:00
if (new_locale == "system") {
2025-03-09 17:02:12 +01:00
config_raw.locale = iron_language();
2024-03-09 14:52:33 +01:00
}
// Check whether the requested or detected locale is available
2024-03-20 16:13:54 +01:00
if (config_raw.locale != "en" && array_index_of(translator_get_supported_locales(), config_raw.locale) == -1) {
2024-03-09 14:52:33 +01:00
// Fall back to English
config_raw.locale = "en";
}
// No translations to load, as source strings are in English
// Clear existing translations if switching languages at runtime
2024-05-03 21:29:39 +02:00
translator_translations = map_create();
2024-03-09 14:52:33 +01:00
if (config_raw.locale == "en" && translator_last_locale == "en") {
// No need to generate extended font atlas for English locale
return;
}
translator_last_locale = config_raw.locale;
if (config_raw.locale != "en") {
// Load the translation file
2024-09-03 16:39:16 +02:00
let translation_json: string = sys_buffer_to_string(iron_load_blob("data/locale/" + config_raw.locale + ".json"));
2025-03-02 17:00:40 +01:00
translator_translations = json_parse_to_map(translation_json);
2024-03-09 14:52:33 +01:00
}
// Generate extended font atlas
translator_extended_glyphs();
// Push additional char codes contained in translation file
let cjk: bool = false;
2024-04-12 12:51:40 +02:00
let keys: string[] = map_keys(translator_translations);
for (let i: i32 = 0; i < keys.length; ++i) {
let s: string = map_get(translator_translations, keys[i]);
2024-09-24 22:54:50 +02:00
for (let i: i32 = 0; char_code_at(s, i) != 0; ) {
let l: i32 = 0;
let codepoint: i32 = string_utf8_decode((s) + i, ADDRESS(l));
i += l;
// Assume cjk in the > 1119 range
2025-03-10 20:26:45 +01:00
if (codepoint > 1119 && !draw_font_has_glyph(codepoint)) {
cjk = true;
draw_font_add_glyph(codepoint);
2024-03-09 14:52:33 +01:00
}
}
}
if (cjk) {
2024-05-03 21:29:39 +02:00
if (path_is_protected()) {
2025-03-09 17:02:12 +01:00
_translator_load_translations_cjk_font_path = iron_internal_save_path();
_translator_load_translations_cjk_font_disk_path = iron_internal_save_path();
2024-05-03 21:29:39 +02:00
}
else {
_translator_load_translations_cjk_font_path = "";
_translator_load_translations_cjk_font_disk_path = path_data() + path_sep;
}
_translator_load_translations_cjk_font_path += "font_cjk.ttc";
_translator_load_translations_cjk_font_disk_path += "font_cjk.ttc";
2024-04-07 09:52:45 +02:00
2025-09-01 13:44:44 +02:00
if (!iron_file_exists(_translator_load_translations_cjk_font_disk_path)) {
2025-09-12 15:29:02 +02:00
file_download_to("https://github.com/armory3d/armorbase/raw/main/Assets/common/extra/font_cjk.ttc", _translator_load_translations_cjk_font_disk_path, function () {
2024-04-07 09:52:45 +02:00
2025-09-01 13:44:44 +02:00
if (!iron_file_exists(_translator_load_translations_cjk_font_disk_path)) {
2024-03-09 14:52:33 +01:00
// Fall back to English
config_raw.locale = "en";
translator_extended_glyphs();
2024-05-03 21:29:39 +02:00
translator_translations = map_create();
2024-03-09 14:52:33 +01:00
translator_init_font(false, "font.ttf", 1.0);
}
2024-03-20 16:13:54 +01:00
else {
2024-05-03 21:29:39 +02:00
translator_init_font(true, _translator_load_translations_cjk_font_path, 1.4);
2024-03-20 16:13:54 +01:00
}
2024-03-09 14:52:33 +01:00
}, 20332392);
}
2024-03-20 16:13:54 +01:00
else {
2024-05-03 21:29:39 +02:00
translator_init_font(true, _translator_load_translations_cjk_font_path, 1.4);
2024-03-20 16:13:54 +01:00
}
}
else {
translator_init_font(false, "font.ttf", 1.0);
2024-03-09 14:52:33 +01:00
}
}
2024-03-20 16:13:54 +01:00
function translator_init_font(cjk: bool, font_path: string, font_scale: f32) {
2024-04-07 09:52:45 +02:00
_translator_init_font_cjk = cjk;
_translator_init_font_font_path = font_path;
_translator_init_font_font_scale = font_scale;
2024-03-09 14:52:33 +01:00
// Load and assign font with cjk characters
2025-08-16 20:43:45 +02:00
sys_notify_on_next_frame(function () {
2024-04-07 09:52:45 +02:00
let cjk: bool = _translator_init_font_cjk;
let font_path: string = _translator_init_font_font_path;
let font_scale: f32 = _translator_init_font_font_scale;
2025-03-02 21:07:17 +01:00
let f: draw_font_t = data_get_font(font_path);
2024-03-09 14:52:33 +01:00
if (cjk) {
2025-03-10 20:26:45 +01:00
let font_index: i32 = map_get(translator_cjk_font_indices, config_raw.locale) != -1 ?
map_get(translator_cjk_font_indices, config_raw.locale) : 0;
f.index = font_index;
f.glyphs_version = 0;
draw_font_init(f);
2024-03-09 14:52:33 +01:00
}
base_font = f;
// Scale up the font size and elements width a bit
2024-03-20 16:13:54 +01:00
base_theme.FONT_SIZE = math_floor(base_default_font_size * font_scale);
2024-03-11 15:10:18 +01:00
base_theme.ELEMENT_W = math_floor(base_default_element_w * (config_raw.locale != "en" ? 1.4 : 1.0));
2025-08-15 22:04:07 +02:00
2025-08-31 19:23:47 +02:00
ui_set_font(ui, f);
2025-08-15 22:04:07 +02:00
ui_set_scale(UI_SCALE());
2024-03-09 14:52:33 +01:00
});
}
function translator_extended_glyphs() {
// Basic Latin + Latin-1 Supplement + Latin Extended-A
2025-03-10 20:26:45 +01:00
draw_font_init_glyphs(32, 383);
2024-03-09 14:52:33 +01:00
// + Greek
2024-03-20 16:13:54 +01:00
for (let i: i32 = 880; i < 1023; ++i) {
2025-03-10 20:26:45 +01:00
draw_font_add_glyph(i);
2024-03-20 16:13:54 +01:00
}
2024-03-09 14:52:33 +01:00
// + Cyrillic
2024-03-20 16:13:54 +01:00
for (let i: i32 = 1024; i < 1119; ++i) {
2025-03-10 20:26:45 +01:00
draw_font_add_glyph(i);
2024-03-20 16:13:54 +01:00
}
2024-03-09 14:52:33 +01:00
}
// Returns a list of supported locales (plus English and the automatically detected system locale)
function translator_get_supported_locales(): string[] {
let locales: string[] = ["system", "en"];
2024-05-03 21:29:39 +02:00
let files: string[] = file_read_directory(path_data() + path_sep + "locale");
for (let i: i32 = 0; i < files.length; ++i) {
let locale_filename: string = files[i];
2024-03-22 14:17:49 +01:00
// Trim the ".json" file extension from file names
2024-03-20 16:13:54 +01:00
array_push(locales, substring(locale_filename, 0, locale_filename.length - 5));
2024-03-09 14:52:33 +01:00
}
return locales;
}