{"record":{"id":"4ec5abd01d628fb7","repo":"HMCL-dev/HMCL","slug":"localized-text-field-is-empty-field","errorCode":null,"errorMessage":"Localized text field is empty: ${field}","messagePattern":"Localized text field is empty: (.+?)","errorType":"validation","errorClass":"JsonParseException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java","lineNumber":209,"sourceCode":"    private static String requireMemberString(JsonObject object, String fieldName) {\n        JsonElement element = object.get(fieldName);\n        if (element == null) {\n            throw new JsonParseException(\"Theme-pack manifest is missing \" + fieldName);\n        }\n        if (!(element instanceof JsonPrimitive primitive) || !primitive.isString()) {\n            throw new JsonParseException(\"Theme-pack manifest field must be a string: \" + fieldName);\n        }\n        return requireNonBlank(primitive.getAsString(), fieldName);\n    }\n\n    /// Parses a localized text value.\n    static LocalizedText parseLocalizedText(JsonElement element, String field) {\n        if (element instanceof JsonPrimitive primitive && primitive.isString()) {\n            return LocalizedText.plain(requireNonBlank(primitive.getAsString(), field));\n        }\n        if (element instanceof JsonObject localizedObject) {\n            if (localizedObject.isEmpty()) {\n                throw new JsonParseException(\"Localized text field is empty: \" + field);\n            }\n\n            LinkedHashMap<String, String> localizedValues = new LinkedHashMap<>();\n            for (Map.Entry<String, JsonElement> entry : localizedObject.entrySet()) {\n                JsonElement value = entry.getValue();\n                if (!(value instanceof JsonPrimitive primitive) || !primitive.isString()) {\n                    throw new JsonParseException(\"Localized text values must be strings: \" + field);\n                }\n                localizedValues.put(\n                        requireNonBlank(entry.getKey(), field),\n                        requireNonBlank(primitive.getAsString(), field));\n            }\n            return new LocalizedText(localizedValues);\n        }\n        throw new JsonParseException(\"Theme-pack localized text must be a string or object: \" + field);\n    }\n\n    /// Returns a validated localized text value.","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/theme/ThemePackManifest.java#L191-L227","documentation":"Thrown by parseLocalizedText when a localized text field is a JSON object but contains no entries. Localized text is either a plain string or a non-empty map of locale keys to strings; an empty object carries no text in any locale, so it is rejected.","triggerScenarios":"Deserializing a manifest where a localized field (e.g. \"name\" or \"description\") is set to {}: \"name\": {}.","commonSituations":"A localization pipeline emitted an empty map when no translations were generated; an author cleared all languages from a translation editor, saving an empty object; a template placeholder {} was never filled.","solutions":["Add at least one locale entry, e.g. { \"en\": \"My Theme\", \"zh\": \"我的主题\" }, or use a single plain string.","If no localization is needed, replace the empty object with a plain string value.","Fix the translation export step so it falls back to a default locale instead of emitting {}."],"exampleFix":"// before\n\"name\": {}\n// after\n\"name\": { \"en\": \"My Theme\" }","handlingStrategy":"validation","validationCode":"JsonElement name = manifestJson.get(\"name\");\nif (name instanceof JsonObject o && o.entrySet().isEmpty()) {\n    throw new IllegalArgumentException(\"localized field 'name' must not be an empty object\");\n}","typeGuard":"static boolean isNonEmptyLocalizedObject(JsonElement el) {\n    return el instanceof JsonObject o && !o.entrySet().isEmpty();\n}","tryCatchPattern":"try {\n    ThemePackManifest pack = gson.fromJson(json, ThemePackManifest.class);\n} catch (JsonParseException e) {\n    // note that 'description' failures are tolerated (logged and ignored), 'name' is not\n}","preventionTips":["Fall back to a plain string when no translations exist","Ensure translation exports always include a default locale entry","Never leave {} placeholders in shipped manifests"],"tags":["json","i18n","manifest","empty"],"backgroundTag":"empty-required-field","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}