001/////////////////////////////////////////////////////////////////////////////////////////////// 002// checkstyle: Checks Java source code and other text files for adherence to a set of rules. 003// Copyright (C) 2001-2026 the original author or authors. 004// 005// This library is free software; you can redistribute it and/or 006// modify it under the terms of the GNU Lesser General Public 007// License as published by the Free Software Foundation; either 008// version 2.1 of the License, or (at your option) any later version. 009// 010// This library is distributed in the hope that it will be useful, 011// but WITHOUT ANY WARRANTY; without even the implied warranty of 012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013// Lesser General Public License for more details. 014// 015// You should have received a copy of the GNU Lesser General Public 016// License along with this library; if not, write to the Free Software 017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 018/////////////////////////////////////////////////////////////////////////////////////////////// 019 020package com.puppycrawl.tools.checkstyle; 021 022import java.text.MessageFormat; 023import java.util.Locale; 024import java.util.MissingResourceException; 025import java.util.ResourceBundle; 026 027import com.puppycrawl.tools.checkstyle.utils.UnmodifiableCollectionUtil; 028 029/** 030 * Represents a message that can be localised. The translations come from 031 * message.properties files. The underlying implementation uses 032 * java.text.MessageFormat. 033 */ 034public class LocalizedMessage { 035 036 /** The locale to localise messages to. */ 037 private static Locale messageLocale = Locale.getDefault(); 038 039 /** Name of the resource bundle to get messages from. */ 040 private final String bundle; 041 042 /** Class of the source for this message. */ 043 private final Class<?> sourceClass; 044 045 /** 046 * Key for the message format. 047 */ 048 private final String key; 049 050 /** 051 * Arguments for java.text.MessageFormat, that is why type is Object[]. 052 * 053 * <p>Note: Changing types from Object[] will be huge breaking compatibility, as Module 054 * messages use some type formatting already, so better to keep it as Object[]. 055 * </p> 056 */ 057 private final Object[] args; 058 059 /** 060 * Creates a new {@code LocalizedMessage} instance. 061 * 062 * @param bundle resource bundle name 063 * @param sourceClass the Class that is the source of the message 064 * @param key the key to locate the translation. 065 * @param args arguments for the translation. 066 */ 067 public LocalizedMessage(String bundle, Class<?> sourceClass, String key, 068 Object... args) { 069 this.bundle = bundle; 070 this.sourceClass = sourceClass; 071 this.key = key; 072 if (args == null) { 073 this.args = null; 074 } 075 else { 076 this.args = UnmodifiableCollectionUtil.copyOfArray(args, args.length); 077 } 078 } 079 080 /** 081 * Sets a locale to use for localization. 082 * 083 * @param locale the locale to use for localization 084 */ 085 public static void setLocale(Locale locale) { 086 if (Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) { 087 messageLocale = Locale.ROOT; 088 } 089 else { 090 messageLocale = locale; 091 } 092 } 093 094 /** 095 * Gets the translated message. 096 * 097 * @return the translated message. 098 */ 099 public String getMessage() { 100 String result; 101 try { 102 // Important to use the default class loader, and not the one in 103 // the GlobalProperties object. This is because the class loader in 104 // the GlobalProperties is specified by the user for resolving 105 // custom classes. 106 final ResourceBundle resourceBundle = getBundle(); 107 final String pattern = resourceBundle.getString(key); 108 final MessageFormat formatter = new MessageFormat(pattern, Locale.ROOT); 109 result = formatter.format(args); 110 } 111 catch (final MissingResourceException ignored) { 112 // If the Check author didn't provide i18n resource bundles 113 // and logs audit event messages directly, this will return 114 // the author's original message 115 final MessageFormat formatter = new MessageFormat(key, Locale.ROOT); 116 result = formatter.format(args); 117 } 118 return result; 119 } 120 121 /** 122 * Obtain the ResourceBundle. Uses the classloader 123 * of the class emitting this message, to be sure to get the correct 124 * bundle. Property files are read as UTF-8 by the JDK since Java 9, 125 * so no custom {@code ResourceBundle.Control} is needed. 126 * 127 * @return a ResourceBundle. 128 */ 129 private ResourceBundle getBundle() { 130 return ResourceBundle.getBundle(bundle, messageLocale, sourceClass.getClassLoader()); 131 } 132 133}