1 /* 2 ============================================================================== 3 4 This file is part of the JUCE library. 5 Copyright (c) 2020 - Raw Material Software Limited 6 7 JUCE is an open source library subject to commercial or open-source 8 licensing. 9 10 The code included in this file is provided under the terms of the ISC license 11 http://www.isc.org/downloads/software-support-policy/isc-license. Permission 12 To use, copy, modify, and/or distribute this software for any purpose with or 13 without fee is hereby granted provided that the above copyright notice and 14 this permission notice appear in all copies. 15 16 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER 17 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE 18 DISCLAIMED. 19 20 ============================================================================== 21 */ 22 23 namespace juce 24 { 25 26 //============================================================================== 27 /** 28 Used to convert strings to localised foreign-language versions. 29 30 This is basically a look-up table of strings and their translated equivalents. 31 It can be loaded from a text file, so that you can supply a set of localised 32 versions of strings that you use in your app. 33 34 To use it in your code, simply call the translate() method on each string that 35 might have foreign versions, and if none is found, the method will just return 36 the original string. 37 38 The translation file should start with some lines specifying a description of 39 the language it contains, and also a list of ISO country codes where it might 40 be appropriate to use the file. After that, each line of the file should contain 41 a pair of quoted strings with an '=' sign. 42 43 E.g. for a french translation, the file might be: 44 45 @code 46 language: French 47 countries: fr be mc ch lu 48 49 "hello" = "bonjour" 50 "goodbye" = "au revoir" 51 @endcode 52 53 If the strings need to contain a quote character, they can use '\"' instead, and 54 if the first non-whitespace character on a line isn't a quote, then it's ignored, 55 (you can use this to add comments). 56 57 Note that this is a singleton class, so don't create or destroy the object directly. 58 There's also a TRANS(text) macro defined to make it easy to use the this. 59 60 E.g. @code 61 printSomething (TRANS("hello")); 62 @endcode 63 64 This macro is used in the JUCE classes themselves, so your application has a chance to 65 intercept and translate any internal JUCE text strings that might be shown. (You can easily 66 get a list of all the messages by searching for the TRANS() macro in the JUCE source 67 code). 68 69 @tags{Core} 70 */ 71 class JUCE_API LocalisedStrings 72 { 73 public: 74 //============================================================================== 75 /** Creates a set of translations from the text of a translation file. 76 77 When you create one of these, you can call setCurrentMappings() to make it 78 the set of mappings that the system's using. 79 */ 80 LocalisedStrings (const String& fileContents, bool ignoreCaseOfKeys); 81 82 /** Creates a set of translations from a file. 83 84 When you create one of these, you can call setCurrentMappings() to make it 85 the set of mappings that the system's using. 86 */ 87 LocalisedStrings (const File& fileToLoad, bool ignoreCaseOfKeys); 88 89 LocalisedStrings (const LocalisedStrings&); 90 LocalisedStrings& operator= (const LocalisedStrings&); 91 92 /** Destructor. */ 93 ~LocalisedStrings(); 94 95 //============================================================================== 96 /** Selects the current set of mappings to be used by the system. 97 98 The object you pass in will be automatically deleted when no longer needed, so 99 don't keep a pointer to it. You can also pass in nullptr to remove the current 100 mappings. 101 102 See also the TRANS() macro, which uses the current set to do its translation. 103 104 @see translateWithCurrentMappings 105 */ 106 static void setCurrentMappings (LocalisedStrings* newTranslations); 107 108 /** Returns the currently selected set of mappings. 109 110 This is the object that was last passed to setCurrentMappings(). It may 111 be nullptr if none has been created. 112 */ 113 static LocalisedStrings* getCurrentMappings(); 114 115 /** Tries to translate a string using the currently selected set of mappings. 116 117 If no mapping has been set, or if the mapping doesn't contain a translation 118 for the string, this will just return the original string. 119 120 See also the TRANS() macro, which uses this method to do its translation. 121 122 @see setCurrentMappings, getCurrentMappings 123 */ 124 static String translateWithCurrentMappings (const String& text); 125 126 /** Tries to translate a string using the currently selected set of mappings. 127 128 If no mapping has been set, or if the mapping doesn't contain a translation 129 for the string, this will just return the original string. 130 131 See also the TRANS() macro, which uses this method to do its translation. 132 133 @see setCurrentMappings, getCurrentMappings 134 */ 135 static String translateWithCurrentMappings (const char* text); 136 137 //============================================================================== 138 /** Attempts to look up a string and return its localised version. 139 If the string isn't found in the list, the original string will be returned. 140 */ 141 String translate (const String& text) const; 142 143 /** Attempts to look up a string and return its localised version. 144 If the string isn't found in the list, the resultIfNotFound string will be returned. 145 */ 146 String translate (const String& text, const String& resultIfNotFound) const; 147 148 /** Returns the name of the language specified in the translation file. 149 150 This is specified in the file using a line starting with "language:", e.g. 151 @code 152 language: german 153 @endcode 154 */ getLanguageName()155 String getLanguageName() const { return languageName; } 156 157 /** Returns the list of suitable country codes listed in the translation file. 158 159 These is specified in the file using a line starting with "countries:", e.g. 160 @code 161 countries: fr be mc ch lu 162 @endcode 163 164 The country codes are supposed to be 2-character ISO compliant codes. 165 */ getCountryCodes()166 const StringArray& getCountryCodes() const { return countryCodes; } 167 168 /** Provides access to the actual list of mappings. */ getMappings()169 const StringPairArray& getMappings() const { return translations; } 170 171 //============================================================================== 172 /** Adds and merges another set of translations into this set. 173 174 Note that the language name and country codes of the new LocalisedStrings 175 object must match that of this object - an assertion will be thrown if they 176 don't match. 177 178 Any existing values will have their mappings overwritten by the new ones. 179 */ 180 void addStrings (const LocalisedStrings&); 181 182 /** Gives this object a set of strings to use as a fallback if a string isn't found. 183 The object that is passed-in will be owned and deleted by this object 184 when no longer needed. It can be nullptr to clear the existing fallback object. 185 */ 186 void setFallback (LocalisedStrings* fallbackStrings); 187 188 private: 189 //============================================================================== 190 String languageName; 191 StringArray countryCodes; 192 StringPairArray translations; 193 std::unique_ptr<LocalisedStrings> fallback; 194 195 void loadFromText (const String&, bool ignoreCase); 196 197 JUCE_LEAK_DETECTOR (LocalisedStrings) 198 }; 199 200 //============================================================================== 201 #ifndef TRANS 202 /** Uses the LocalisedStrings class to translate the given string literal. 203 This macro is provided for backwards-compatibility, and just calls the translate() 204 function. In new code, it's recommended that you just call translate() directly 205 instead, and avoid using macros. 206 @see translate(), LocalisedStrings 207 */ 208 #define TRANS(stringLiteral) juce::translate (stringLiteral) 209 #endif 210 211 /** A dummy version of the TRANS macro, used to indicate a string literal that should be 212 added to the translation file by source-code scanner tools. 213 214 Wrapping a string literal in this macro has no effect, but by using it around strings 215 that your app needs to translate at a later stage, it lets automatic code-scanning tools 216 find this string and add it to the list of strings that need translation. 217 */ 218 #define NEEDS_TRANS(stringLiteral) (stringLiteral) 219 220 /** Uses the LocalisedStrings class to translate the given string literal. 221 @see LocalisedStrings 222 */ 223 JUCE_API String translate (const String& stringLiteral); 224 225 /** Uses the LocalisedStrings class to translate the given string literal. 226 @see LocalisedStrings 227 */ 228 JUCE_API String translate (const char* stringLiteral); 229 230 /** Uses the LocalisedStrings class to translate the given string literal. 231 @see LocalisedStrings 232 */ 233 JUCE_API String translate (CharPointer_UTF8 stringLiteral); 234 235 /** Uses the LocalisedStrings class to translate the given string literal. 236 @see LocalisedStrings 237 */ 238 JUCE_API String translate (const String& stringLiteral, const String& resultIfNotFound); 239 240 } // namespace juce 241