001/* 002 * ============================================================================ 003 * Copyright © 2002-2023 by Thomas Thrien. 004 * All Rights Reserved. 005 * ============================================================================ 006 * Licensed to the public under the agreements of the GNU Lesser General Public 007 * License, version 3.0 (the "License"). You may obtain a copy of the License at 008 * 009 * http://www.gnu.org/licenses/lgpl.html 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations 015 * under the License. 016 */ 017 018package org.tquadrat.foundation.i18n; 019 020import static java.lang.annotation.ElementType.FIELD; 021import static java.lang.annotation.ElementType.METHOD; 022import static java.lang.annotation.RetentionPolicy.SOURCE; 023import static org.apiguardian.api.API.Status.STABLE; 024import static org.tquadrat.foundation.i18n.TextUse.TEXTUSE_DEFAULT; 025 026import java.lang.annotation.Repeatable; 027import java.lang.annotation.Retention; 028import java.lang.annotation.Target; 029 030import org.apiguardian.api.API; 031import org.tquadrat.foundation.annotation.ClassVersion; 032 033/** 034 * <p>{@summary Use this annotation to define a text – usually for a UI 035 * element or alike – that has to be translated.} Messages will be 036 * defined with the annotation 037 * {@link Message}.</p> 038 * <p>The texts will be stored in a 039 * {@link java.util.ResourceBundle ResourceBundle} 040 * with the base bundle name that is identified through the annotation 041 * {@link BaseBundleName @BaseBundleName}. 042 * The documentation for the method 043 * {@link java.util.ResourceBundle#getBundle(String,java.util.Locale,ClassLoader) getBundle()} 044 * describes the detection strategy. The build process takes care of the 045 * generation of the resource bundle properties file.</p> 046 * <p>Use this annotation as follows:</p> 047 * <pre><code> … 048 * @Text 049 * ( 050 * description = "A text", 051 * translations = 052 * { 053 * @Translation( language = "en", text = "English text" ), 054 * @Translation( language = "de", text = "Text in Deutsch" ) 055 * } 056 * ) 057 * private static final String TXT_TextKey = I18nUtil.composeTextKey( SampleClass.class, TextUse.TXT, "TextKey" ); 058 * …</code></pre> 059 * <p>For the generation, the content of the field {@code TXT_TextKey} is 060 * irrelevant, the key will be built from the name of the field plus the 061 * fully qualified name of the class. But for the retrieval of the text, the 062 * contents of the field needs to match that generated key.</p> 063 * <p>The prefix {@code TXT} is defined in 064 * {@link TextUse} 065 * and will be derived from the name; if this is not desired, an alternative 066 * form of the annotation can be used:</p> 067 * <pre><code> … 068 * @Text 069 * ( 070 * … 071 * ) 072 * private static final String m_TextKey = I18nUtil.composeTextKey( SampleClass.class, TextUse.TXT, "TextKey" ); 073 * …</code></pre> 074 * <p>This works because {@code TXT} is the default for the text use.</p> 075 * <p>It is also possible to define the id and the text use explicitly:</p> 076 * <pre><code> … 077 * @Text 078 * ( 079 * description = "A text", 080 * id = "TextKey", 081 * use = TextUse.TXT, 082 * translations = 083 * { 084 * @Translation( language = "en", text = "English text" ), 085 * @Translation( language = "de", text = "Text in Deutsch" ) 086 * } 087 * ) 088 * private static final String m_Text = I18nUtil.composeTextKey( SampleClass.class, TextUse.TXT, "TextKey" ); 089 * …</code></pre> 090 * <p>This format is required when the annotation is applied to a method, in 091 * this case to a getter:</p> 092 * <pre><code> … 093 * @Text 094 * ( 095 * description = "The name of the property", 096 * translations = 097 * { 098 * @Translation( language = "en", text = "Property" ), 099 * @Translation( language = "de", text = "Eigenschaft" ) 100 * } 101 * ) 102 * @Text 103 * ( 104 * description = "The caption for the property", 105 * use = TextUse.CAPTION, 106 * translations = 107 * { 108 * @Translation( language = "en", text = "Property: " ), 109 * @Translation( language = "de", text = "Eigenschaft: " ) 110 * } 111 * ) 112 * @Text 113 * ( 114 * description = "The tooltip for the property", 115 * use = TextUse.TOOLTIP, 116 * translations = 117 * { 118 * @Translation( language = "en", text = "The property" ), 119 * @Translation( language = "de", text = "Die Eigenschaft" ) 120 * } 121 * ) 122 * public String getProperty(); 123 * …</code></pre> 124 * <p>This sample would generate texts with the keys below, given that the 125 * method belongs to the interface {@code com.sample.Example}:</p> 126 * <ul> 127 * <li>{@code com.sample.Example.NAME_Property}</li> 128 * <li>{@code com.sample.Example.CAPTION_Property}</li> 129 * <li>{@code com.sample.Example.TOOLTIP_Property}</li> 130 * </ul> 131 * <p>If the method is not a getter, a setter or an "add" method, 132 * both {@code id} and {@code use} are always mandatory.</p> 133 * <p>For {@code enum}s, this form is applicable:</p> 134 * <pre><code> … 135 * public enum WhatEver 136 * { 137 * @Text 138 * ( 139 * description = "The name for an enum value", 140 * translations = 141 * { 142 * @Translation( language = "en", text = "Enumeration Value" ), 143 * @Translation( language = "de", text = "Aufzählungswert" ) 144 * } 145 * ) 146 * ENUM_VALUE; 147 * 148 * … 149 * } 150 * // enum WhatEver</code></pre> 151 * <p>The argument for 152 * {@link java.util.ResourceBundle#getString(String) ResourceBundle.getString()} 153 * in this case can be composed through a call to 154 * {@link org.tquadrat.foundation.i18n.I18nUtil#composeTextKey(Enum) I18nUtil.composeTextKey()}; 155 * that can be used for the implementation of 156 * {@code WhatEver.toString()} like this:</p> 157 * <pre><code> … 158 * public final toString() 159 * { 160 * String key = composeTextKey( this ); 161 * String retValue = getBundle().getString( key ); 162 * 163 * //---* Done *----------------------------------------------------------- 164 * return retValue; 165 * } // toString() 166 * …</code></pre> 167 * <p>Different from messages, it is somehow expected that the returned values 168 * may contain escape sequences that can be converted by a call to 169 * {@link String#translateEscapes()}.</p> 170 * 171 * @extauthor Thomas Thrien - thomas.thrien@tquadrat.org 172 * @version $Id: Text.java 1062 2023-09-25 23:11:41Z tquadrat $ 173 * @since 0.1.0 174 */ 175@SuppressWarnings( "NewClassNamingConvention" ) 176@Retention( SOURCE ) 177@Target( {FIELD, METHOD} ) 178@Repeatable( Texts.class ) 179@ClassVersion( sourceVersion = "$Id: Text.java 1062 2023-09-25 23:11:41Z tquadrat $" ) 180@API( status = STABLE, since = "0.1.0" ) 181public @interface Text 182{ 183 /*------------*\ 184 ====** Attributes **======================================================= 185 \*------------*/ 186 /** 187 * Returns the description for the text. 188 * 189 * @return The description. 190 */ 191 String description(); 192 193 /** 194 * <p>{@summary The use of the text; the default is 195 * {@link TextUse#TEXTUSE_DEFAULT}.}</p> 196 * <p>This will be replaced with 197 * {@link TextUse#NAME} 198 * if the annotated element is method for a property (a getter, setter or 199 * an "add" method), 200 * with 201 * {@link TextUse#STRING} 202 * if an {@code enum} is annotated, and with 203 * {@link TextUse#TXT} 204 * for any other case.</p> 205 * 206 * @return The text use. 207 */ 208 TextUse use() default TEXTUSE_DEFAULT; 209 210 /** 211 * Returns the text id for the text. If empty, the <i>name</i> of the 212 * annotated field is used when the annotation is applied to field; 213 * otherwise the annotation processor will throw an error. 214 * 215 * @return The id, if set; otherwise the empty String. 216 */ 217 @SuppressWarnings( "NewMethodNamingConvention" ) String id() default ""; 218 219 /** 220 * Returns the list of valid translations for the text. 221 * 222 * @return The translations. 223 */ 224 Translation [] translations(); 225} 226// annotation Text 227 228/* 229 * End of File 230 */