Language.java 4.11 KB
Newer Older
1
2
3
4
5
6
7
8
package emu.grasscutter.utils;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import emu.grasscutter.Grasscutter;

import javax.annotation.Nullable;
import java.io.InputStream;
Secretboy-SMR's avatar
Secretboy-SMR committed
9
import java.util.concurrent.ConcurrentHashMap;
10
11
12
13
import java.util.Map;

public final class Language {
    private final JsonObject languageData;
Secretboy-SMR's avatar
Secretboy-SMR committed
14
15
    private final Map<String, String> cachedTranslations = new ConcurrentHashMap<>();
    private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
16
17
18
19
20
21
22

    /**
     * Creates a language instance from a code.
     * @param langCode The language code.
     * @return A language instance.
     */
    public static Language getLanguage(String langCode) {
Secretboy-SMR's avatar
Secretboy-SMR committed
23
24
25
26
27
28
29
        if (cachedLanguages.containsKey(langCode)) {
            return cachedLanguages.get(langCode);
        }

        var languageInst = new Language(langCode + ".json", Utils.getLanguageCode(Grasscutter.getConfig().DefaultLanguage) + ".json");
        cachedLanguages.put(langCode, languageInst);
        return languageInst;
30
31
32
33
34
35
36
37
38
    }

    /**
     * Returns the translated value from the key while substituting arguments.
     * @param key The key of the translated value to return.
     * @param args The arguments to substitute.
     * @return A translated value with arguments substituted.
     */
    public static String translate(String key, Object... args) {
KingRainbow44's avatar
KingRainbow44 committed
39
        String translated = Grasscutter.getLanguage().get(key);
40
        
KingRainbow44's avatar
KingRainbow44 committed
41
42
43
44
45
46
        try {
            return translated.formatted(args);
        } catch (Exception exception) {
            Grasscutter.getLogger().error("Failed to format string: " + key, exception);
            return translated;
        }
47
48
    }

Secretboy's avatar
Secretboy committed
49
50
51
    /**
     * Reads a file and creates a language instance.
     * @param fileName The name of the language file.
Secretboy-SMR's avatar
Secretboy-SMR committed
52
     * @param fallback The name of the fallback language file.
Secretboy's avatar
Secretboy committed
53
     */
54
    private Language(String fileName, String fallback) {
Secretboy's avatar
Secretboy committed
55
        @Nullable JsonObject languageData = null;
56

57
        InputStream file = Grasscutter.class.getResourceAsStream("/languages/" + fileName);
58
        if (file == null) { // Provided fallback language.
59
            file = Grasscutter.class.getResourceAsStream("/languages/" + fallback);
60
61
62
            Grasscutter.getLogger().warn("Failed to load language file: " + fileName + ", falling back to: " + fallback);
        }
        if(file == null) { // Fallback the fallback language.
63
            file = Grasscutter.class.getResourceAsStream("/languages/en-US.json");
64
65
            Grasscutter.getLogger().warn("Failed to load language file: " + fallback + ", falling back to: en-US.json");
        }
66
67
68
        if(file == null)
            throw new RuntimeException("Unable to load the primary, fallback, and 'en-US' language files.");
        
69
70
71
        try {
            languageData = Grasscutter.getGsonFactory().fromJson(Utils.readFromInputStream(file), JsonObject.class);
        } catch (Exception exception) {
72
            Grasscutter.getLogger().warn("Failed to load language file: " + fileName, exception);
Secretboy's avatar
Secretboy committed
73
        }
74
75
        
        this.languageData = languageData;
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    }

    /**
     * Returns the value (as a string) from a nested key.
     * @param key The key to look for.
     * @return The value (as a string) from a nested key.
     */
    public String get(String key) {
        if(this.cachedTranslations.containsKey(key)) {
            return this.cachedTranslations.get(key);
        }
        
        String[] keys = key.split("\\.");
        JsonObject object = this.languageData;

        int index = 0;
92
        String result = "This value does not exist. Please report this to the Discord: " + key;
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

        while (true) {
            if(index == keys.length) break;
            
            String currentKey = keys[index++];
            if(object.has(currentKey)) {
                JsonElement element = object.get(currentKey);
                if(element.isJsonObject())
                    object = element.getAsJsonObject();
                else {
                    result = element.getAsString(); break;
                }
            } else break;
        }
        
        this.cachedTranslations.put(key, result); return result;
    }
}