Interface Localized
- All Known Implementing Classes:
UltiTools,UltiToolsPlugin
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final String[]The language-file extensions a code may be declared by, matchingUltiToolsPlugin's loader. -
Method Summary
Modifier and TypeMethodDescriptiondefault StringReturns a localized string for the given default text.static booleanisSafeLanguageCode(String code) Checkscodeagainst the character allowlistlanguageCodeOf(String)documents: non-empty, starting with an ASCII letter or digit, every character thereafter an ASCII letter, digit,'_'or'-'.static StringlanguageCodeOf(String fileName) ReturnsfileNamewithout its language extension, ornullif it has none -- or if the remainder is not itself a plain language-code token.static StringofficialLanguageOf(String configured, List<String> officialCodes) Resolves the official language a configuredlanguagename is based on (#608).scanLangDirectory(File langDir) Lists the immediate language-file children oflangDir-- nested entries such aslang/extra/en.jsonare not descended into.scanLangJar(File jarFile) EnumeratesjarFile's entries for immediatelang/*language children -- neither non-language entries (e.g.scanLangResources(URL codeSourceLocation) Enumerates thelang/*language resources at the given code-source location, handling both a packaged JAR and an exploded directory (development workspace) layout.Get the language code of the plugin module.
-
Field Details
-
LANGUAGE_EXTENSIONS
The language-file extensions a code may be declared by, matchingUltiToolsPlugin's loader..yml/.yamlwere added in 6.3.0 (#389): eight of this ecosystem's modules ship YAML, and while only.jsoncounted here they reported no supported languages at all, soresolveLanguageCodehad nothing to consult.- Since:
- 6.3.0
-
-
Method Details
-
languageCodeOf
ReturnsfileNamewithout its language extension, ornullif it has none -- or if the remainder is not itself a plain language-code token.16-05 / CodeQL
java/zipslipalert #11 (CWE-22). The returned value is not merely displayed:UltiToolsPlugincombines it directly into aFilepath (e.g.lang/<code>.json) with no other sanitisation, and this method is fed raw jar-entry names byscanLangJar(File)as well as raw on-disk filenames byscanLangDirectory(File). Before this fix, a jar entry namedlang/..\..\evil.json(or the URL-decoded equivalentlang/../../evil.json) survived unchanged as the code..\..\evil, which a downstream sink could then resolve outside the module's ownlang/directory.The remainder is therefore also checked against a character allowlist --
[A-Za-z0-9][A-Za-z0-9_-]*-- before being accepted as a code at all: it must start with an ASCII letter or digit, and every character must be an ASCII letter, digit,'_'or'-'. This is deliberately a character allowlist, not a BCP-47 (or any other) language-tag grammar: every code this framework or any of its shipped modules actually uses (en,zh,en_US,zh-CN, ...) matches it, and no plausible language code needs a'.','/','\'or any other character this allowlist rejects. A candidate failing the allowlist returnsnull-- exactly the same "not a language file" outcome as a name with no recognised extension at all -- so a caller cannot tell "wrong extension" apart from "rejected as unsafe", by design: neither is a case a caller needs to react to differently.- Parameters:
fileName- a file or jar-entry name, without any directory part- Returns:
- the language code, or
nullwhen the name is not a language file or its stripped remainder is not a safe language-code token - Since:
- 6.3.0
-
isSafeLanguageCode
Checkscodeagainst the character allowlistlanguageCodeOf(String)documents: non-empty, starting with an ASCII letter or digit, every character thereafter an ASCII letter, digit,'_'or'-'.Exposed as
public staticfor the same reasonscanLangJar(File)andscanLangDirectory(File)are -- interface methods cannot be non-public before Java 9, so this is a direct test seam rather than API meant for module authors to call.- Parameters:
code- the candidate language code, already stripped of its extension- Returns:
- whether
codeis safe to treat as a language code - Since:
- 6.3.0
-
officialLanguageOf
Resolves the official language a configuredlanguagename is based on (#608).Official language files are owned by the framework; an operator customises messages by copying an official file under a new name and selecting that name in
plugins/UltiTools/config.yml(maintainer decision 2026-10-04). The new name starts with the official code it was copied from and a hyphen --zh-myserveris based onzh-- and keys the custom file lacks come from that official file.Returns
configureditself when it is one ofofficialCodes; otherwise the longest official codecsuch thatconfiguredstarts withc + "-", sozh-CN-myserveris based onzh-CNwhen bothzhandzh-CNare official. Returnsnullwhen there is no such code, whenconfiguredisnull, or when it failsisSafeLanguageCode(String)-- a name that could form a path outside alang/folder is never a custom language name. The caller chooses the fallback fornulland says so in the log.- Parameters:
configured- the configuredlanguagevalue, possiblynullofficialCodes- the official language codes the caller ships- Returns:
- the official code
configuredis based on, ornullif none - Since:
- 6.3.0
-
supported
Get the language code of the plugin module. more Language code list
The returned list is derived from thelang/*.json,lang/*.ymlandlang/*.yamlresources the implementor's own code source (its JAR, or an exploded directory in a development workspace) actually ships. An empty list means no language resources were found -- not that no language is supported. Overriding this method still wins over the derivation.
Gets the language codes a plugin supported.- Returns:
- Supported language codes
- Since:
- 6.3.0 derived from lang/*.json resources rather than
@I18n(D-20) - See Also:
-
scanLangResources
Enumerates thelang/*language resources at the given code-source location, handling both a packaged JAR and an exploded directory (development workspace) layout. Reuses thegetProtectionDomain().getCodeSource()->JarFileidiomUltiToolsPlugin.saveResources()already uses, so this is correct on a module's first-ever startup, before its embedded resources have been extracted to disk. The location is resolved throughCodeSourceLocations.toFile(URL), the same resolver the dictionary reader uses, so a module installed under a path with a space or a non-ASCII character still reports the languages it ships (#676 case 26).Exposed as
public staticout of necessity, not invitation -- interface methods cannot be non-public before Java 9, so this is a direct test seam forsupported()'s derivation rather than API meant for module authors to call.- Parameters:
codeSourceLocation- the URL returned byCodeSource.getLocation()- Returns:
- the language codes found, sorted and de-duplicated; empty on any failure
-
scanLangDirectory
Lists the immediate language-file children oflangDir-- nested entries such aslang/extra/en.jsonare not descended into.- Parameters:
langDir- thelang/directory to scan- Returns:
- the language codes found; empty if
langDirdoes not exist or is empty
-
scanLangJar
EnumeratesjarFile's entries for immediatelang/*language children -- neither non-language entries (e.g.lang/README.txt) nor nested entries (e.g.lang/extra/en.json) are returned. No entry is extracted; this only reads names.- Parameters:
jarFile- the module's own JAR- Returns:
- the language codes found; empty if
jarFilecannot be opened as a JAR
-
i18n
Returns a localized string for the given default text. Thecodeparameter is not honoured by the framework's own implementation --UltiToolsPluginoverrides this methodfinaland resolves directly against the module's already-loadedLanguage, discardingcodeentirely. Language selection happens once at load time, viasupported(), not per call.stris returned unchanged when it is absent as a key from that already-loaded dictionary.- Parameters:
code- language code -- not honoured by the framework's owni18n(String, String)overridestr- default display text, also the dictionary lookup key- Returns:
- a localized string, or
strunchanged if the key is absent from the loaded dictionary - Since:
- 6.3.0 corrected wording -- see D-22 (#315)
-