{"record":{"id":"fcf75aaa945a98ff","repo":"halo-dev/halo","slug":"locale-locale-cannot-be-used-as-it-does-not-sp","errorCode":null,"errorMessage":"Locale \"{locale}\" cannot be used as it does not specify a language.","messagePattern":"Locale \"(.+?)\" cannot be used as it does not specify a language\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"warning","filePath":"application/src/main/java/run/halo/app/notification/LanguageUtils.java","lineNumber":29,"sourceCode":" *\n * @author guqing\n * @since 2.10.0\n */\n@UtilityClass\npublic class LanguageUtils {\n\n    /**\n     * Compute all the possible languages we should use: *_gl_ES-gheada, *_gl_ES, _gl... from a given locale. The first\n     * element of the list is \"default\" if it can not find the language, use default.\n     *\n     * @param locale locale\n     * @return list of possible languages, from less specific to more specific.\n     */\n    public static List<String> computeLangFromLocale(Locale locale) {\n        final List<String> resourceNames = new ArrayList<>(5);\n\n        if (StringUtils.isBlank(locale.getLanguage())) {\n            throw new IllegalArgumentException(\n                    \"Locale \\\"\" + locale + \"\\\" \" + \"cannot be used as it does not specify a language.\");\n        }\n\n        resourceNames.add(\"default\");\n        resourceNames.add(locale.getLanguage());\n\n        if (StringUtils.isNotBlank(locale.getCountry())) {\n            resourceNames.add(locale.getLanguage() + \"_\" + locale.getCountry());\n        }\n\n        if (StringUtils.isNotBlank(locale.getVariant())) {\n            resourceNames.add(locale.getLanguage() + \"_\" + locale.getCountry() + \"-\" + locale.getVariant());\n        }\n        return resourceNames;\n    }\n}\n","sourceCodeStart":11,"sourceCodeEnd":46,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/application/src/main/java/run/halo/app/notification/LanguageUtils.java#L11-L46","documentation":"Thrown as IllegalArgumentException by LanguageUtils.computeLangFromLocale when the Locale has a blank language tag. The method builds resource-name candidates (_lang, _lang_COUNTRY, ...) and needs at least the language component to proceed.","triggerScenarios":"Calling computeLangFromLocale with a Locale whose getLanguage() is empty, e.g. new Locale(\"\") or a Locale built from a country-only/variant-only string, or Locale.ROOT.","commonSituations":"Parsing an Accept-Language header that yields an empty language; defaulting to Locale.ROOT accidentally; constructing Locale from malformed input; a notification/template resolver receiving a blank locale.","solutions":["Fall back to a default Locale (e.g. Locale.ENGLISH or the system default) when the language is blank before calling computeLangFromLocale.","Validate the Accept-Language/locale input and reject/normalize blank languages upstream.","Use Locale.forLanguageTag with a checked, well-formed tag."],"exampleFix":"// before\nList<String> langs = LanguageUtils.computeLangFromLocale(locale);\n\n// after\nLocale safe = StringUtils.isBlank(locale.getLanguage()) ? Locale.getDefault() : locale;\nList<String> langs = LanguageUtils.computeLangFromLocale(safe);","handlingStrategy":"validation","validationCode":"Locale safe = (locale == null || StringUtils.isBlank(locale.getLanguage()))\n    ? Locale.getDefault() : locale;\nList<String> langs = LanguageUtils.computeLangFromLocale(safe);","typeGuard":"static boolean localeHasLanguage(Locale l) {\n    return l != null && StringUtils.isNotBlank(l.getLanguage());\n}","tryCatchPattern":"try {\n    LanguageUtils.computeLangFromLocale(locale);\n} catch (IllegalArgumentException e) {\n    // fall back to default language bundle\n    LanguageUtils.computeLangFromLocale(Locale.getDefault());\n}","preventionTips":["Normalize blank-language Locales to a sensible default before resolving templates.","Validate Accept-Language parsing output upstream.","Never pass Locale.ROOT to language-resource resolution."],"tags":["i18n","locale","notification","validation"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}