2525import java .util .*;
2626import java .util .logging .Level ;
2727
28+ /**
29+ * QuickShop universal text manager
30+ * With multi-files and multi-languages support
31+ */
2832public class TextManager {
2933 private final QuickShop plugin ;
3034 private final Distribution distribution ;
3135 // <File <Locale, Section>>
3236 private final Map <String , Map <String , JsonConfiguration >> locale2ContentMapping = new HashMap <>();
3337 private final static String languageFileCrowdin = "/master/src/main/resources/lang/%locale%/messages.json" ;
3438 public List <PostProcessor > postProcessors = new ArrayList <>();
39+ // <File, Section>
40+ private final Map <String , JsonConfiguration > bundledMapping = new HashMap <>();
3541 private JsonConfiguration bundledLang = new JsonConfiguration ();
3642
3743 public TextManager (QuickShop plugin ) {
@@ -40,69 +46,78 @@ public TextManager(QuickShop plugin) {
4046 load ();
4147 }
4248
49+ /**
50+ * Generate and returns the override files storage folder for specific file
51+ *
52+ * @param distributionPath The file name or path on distribution platform
53+ * @return The storage folder
54+ */
4355 @ NotNull
44- private File getOverrideFilesFolder (@ NotNull String crowdinPath ) {
45- File file = new File (crowdinPath );
46- File folder = new File (new File (plugin .getDataFolder (), "overrides" ), file .getName () + ".overrides" );
56+ private File getOverrideFilesFolder (@ NotNull String distributionPath ) {
57+ File folder = new File (new File (plugin .getDataFolder (), "overrides" ), getFileNameFromFullPath (distributionPath ) + ".overrides" );
4758 folder .mkdirs ();
4859 return folder ;
4960 }
5061
62+ private String getFileNameFromFullPath (@ NotNull String path ) {
63+ return new File (path ).getName ();
64+ }
65+
5166 public void load () {
5267 plugin .getLogger ().info ("Checking for translation updates..." );
5368 locale2ContentMapping .clear ();
5469 postProcessors .clear ();
5570 // Load mapping
56- //for (String availableFile : distribution.getAvailableFiles()) {
57- try {
58- bundledLang .loadFromString (new String (IOUtils .toByteArray (new InputStreamReader (plugin .getResource ("lang-original/messages.json" )), StandardCharsets .UTF_8 )));
59- } catch (IOException | InvalidConfigurationException ex ) {
60- bundledLang = new JsonConfiguration ();
61- plugin .getLogger ().log (Level .SEVERE , "Cannot load bundled language file from Jar, some strings may missing!" , ex );
62- }
71+
72+
6373 // init file mapping
6474 locale2ContentMapping .computeIfAbsent (languageFileCrowdin , e -> new HashMap <>());
6575 // Multi File and Multi-Language loader
6676
67-
68- distribution . getAvailableLanguages (). parallelStream (). forEach ( crowdinCode -> distribution . getAvailableFiles (). parallelStream (). forEach ( crowdinFile -> {
77+ distribution . getAvailableFiles (). parallelStream (). forEach ( crowdinFile -> {
78+ JsonConfiguration bundledLang = new JsonConfiguration ();
6979 try {
70- // load OTA text from Crowdin
71-
72- String minecraftCode = crowdinCode .toLowerCase (Locale .ROOT ).replace ("-" , "_" );
73-
74- Util .debugLog ("Loading translation for locale: " + crowdinCode + " (" + minecraftCode + ")" );
75- JsonConfiguration configuration = new JsonConfiguration ();
80+ bundledLang .loadFromString (new String (IOUtils .toByteArray (new InputStreamReader (plugin .getResource ("bundled/" + getFileNameFromFullPath (crowdinFile ))), StandardCharsets .UTF_8 )));
81+ } catch (IOException | InvalidConfigurationException ex ) {
82+ bundledLang = new JsonConfiguration ();
83+ plugin .getLogger ().log (Level .SEVERE , "Cannot load bundled file " + crowdinFile + " from Jar, some strings may missing!" , ex );
84+ }
85+ bundledMapping .put (crowdinFile , bundledLang );
86+ distribution .getAvailableLanguages ().parallelStream ().forEach (crowdinCode -> {
7687 try {
77- configuration .loadFromString (distribution .getFile (crowdinFile , crowdinCode ));
78- } catch (InvalidConfigurationException exception ) {
79- configuration .loadFromString (distribution .getFile (crowdinFile , crowdinCode , true ));
80- }
81- // load override text (allow user modification the translation)
82- JsonConfiguration override = new JsonConfiguration ();
83- File localOverrideFile = new File (getOverrideFilesFolder (crowdinFile ), minecraftCode + ".json" );
84- if (!localOverrideFile .exists ()) {
85- localOverrideFile .getParentFile ().mkdirs ();
86- localOverrideFile .createNewFile ();
88+ // load OTA text from Crowdin
89+ String minecraftCode = crowdinCode .toLowerCase (Locale .ROOT ).replace ("-" , "_" );
90+ Util .debugLog ("Loading translation for locale: " + crowdinCode + " (" + minecraftCode + ")" );
91+ JsonConfiguration configuration = new JsonConfiguration ();
92+ try {
93+ configuration .loadFromString (distribution .getFile (crowdinFile , crowdinCode ));
94+ } catch (InvalidConfigurationException exception ) {
95+ configuration .loadFromString (distribution .getFile (crowdinFile , crowdinCode , true ));
96+ }
97+ // load override text (allow user modification the translation)
98+ JsonConfiguration override = new JsonConfiguration ();
99+ File localOverrideFile = new File (getOverrideFilesFolder (crowdinFile ), minecraftCode + ".json" );
100+ if (!localOverrideFile .exists ()) {
101+ localOverrideFile .getParentFile ().mkdirs ();
102+ localOverrideFile .createNewFile ();
103+ }
104+ override .loadFromString (Util .readToString (localOverrideFile ));
105+ for (String key : override .getKeys (true )) {
106+ if (key .equals ("language-version" ) || key .equals ("config-version" ) || key .equals ("version" ))
107+ continue ;
108+ configuration .set (key , override .get (key ));
109+ }
110+ locale2ContentMapping .get (languageFileCrowdin ).computeIfAbsent (minecraftCode , e -> configuration );
111+ } catch (CrowdinOTA .OTAException e ) {
112+ plugin .getLogger ().warning ("Couldn't update the translation for locale " + crowdinCode + " because it not configured, please report to QuickShop" );
113+ } catch (IOException e ) {
114+ plugin .getLogger ().log (Level .WARNING , "Couldn't update the translation for locale " + crowdinCode + " please check your network connection." , e );
115+ } catch (Exception e ) {
116+ plugin .getLogger ().log (Level .WARNING , "Couldn't update the translation for locale " + crowdinCode + "." , e );
87117 }
88- override .loadFromString (Util .readToString (localOverrideFile ));
89- for (String key : override .getKeys (true )) {
90- if (key .equals ("language-version" ) || key .equals ("config-version" ) || key .equals ("version" ))
91- continue ;
92- configuration .set (key , override .get (key ));
93- }
94- locale2ContentMapping .get (languageFileCrowdin ).computeIfAbsent (minecraftCode , e -> configuration );
95- Util .debugLog ("Locale " + crowdinFile );
96- if (configuration .getInt ("language-version" ) < bundledLang .getInt ("language-version" ))
97- Util .debugLog ("Locale " + crowdinCode + " file version is outdated, some string will fallback to English." );
98- } catch (CrowdinOTA .OTAException e ) {
99- plugin .getLogger ().warning ("Couldn't update the translation for locale " + crowdinCode + " because it not configured, please report to QuickShop" );
100- } catch (IOException e ) {
101- plugin .getLogger ().log (Level .WARNING , "Couldn't update the translation for locale " + crowdinCode + " please check your network connection." , e );
102- } catch (Exception e ) {
103- plugin .getLogger ().log (Level .WARNING , "Couldn't update the translation for locale " + crowdinCode + "." , e );
104- }
105- }));
118+ });
119+ });
120+
106121
107122
108123// for (String availableLanguage : distribution.getAvailableLanguages()) {
@@ -114,27 +129,27 @@ public void load() {
114129 }
115130
116131 public Text of (@ NotNull String path , String ... args ) {
117- return new Text (this , (CommandSender ) null , locale2ContentMapping . get ( languageFileCrowdin ) , path , args );
132+ return new Text (this , (CommandSender ) null , languageFileCrowdin , path , args );
118133 }
119134
120135 public Text of (@ Nullable CommandSender sender , @ NotNull String path , String ... args ) {
121- return new Text (this , sender , locale2ContentMapping . get ( languageFileCrowdin ) , path , args );
136+ return new Text (this , sender , languageFileCrowdin , path , args );
122137 }
123138
124139 public Text of (@ Nullable UUID sender , @ NotNull String path , String ... args ) {
125- return new Text (this , sender , locale2ContentMapping . get ( languageFileCrowdin ) , path , args );
140+ return new Text (this , sender , languageFileCrowdin , path , args );
126141 }
127142
128143 public TextList ofList (@ NotNull String path , String ... args ) {
129- return new TextList (this , (CommandSender ) null , locale2ContentMapping . get ( languageFileCrowdin ) , path , args );
144+ return new TextList (this , (CommandSender ) null , languageFileCrowdin , path , args );
130145 }
131146
132147 public TextList ofList (@ Nullable UUID sender , @ NotNull String path , String ... args ) {
133- return new TextList (this , sender , locale2ContentMapping . get ( languageFileCrowdin ) , path , args );
148+ return new TextList (this , sender , languageFileCrowdin , path , args );
134149 }
135150
136151 public TextList ofList (@ Nullable CommandSender sender , @ NotNull String path , String ... args ) {
137- return new TextList (this , sender , locale2ContentMapping . get ( languageFileCrowdin ) , path , args );
152+ return new TextList (this , sender , languageFileCrowdin , path , args );
138153 }
139154
140155 public static class TextList {
@@ -145,23 +160,23 @@ public static class TextList {
145160 private final CommandSender sender ;
146161 private final String [] args ;
147162
148- private TextList (TextManager manager , CommandSender sender , Map < String , JsonConfiguration > mapping , String path , String ... args ) {
163+ private TextList (TextManager manager , CommandSender sender , String file , String path , String ... args ) {
149164 this .plugin = manager .plugin ;
150165 this .manager = manager ;
151166 this .sender = sender ;
152- this .mapping = mapping ;
167+ this .mapping = manager . locale2ContentMapping . get ( file ) ;
153168 this .path = path ;
154169 this .args = args ;
155170 }
156171
157- private TextList (TextManager manager , UUID sender , Map < String , JsonConfiguration > mapping , String path , String ... args ) {
172+ private TextList (TextManager manager , UUID sender , String file , String path , String ... args ) {
158173 this .plugin = manager .plugin ;
159174 this .manager = manager ;
160175 if (sender != null )
161176 this .sender = Bukkit .getPlayer (sender );
162177 else
163178 this .sender = null ;
164- this .mapping = mapping ;
179+ this .mapping = manager . locale2ContentMapping . get ( file ) ;
165180 this .path = path ;
166181 this .args = args ;
167182 }
@@ -229,23 +244,23 @@ public static class Text {
229244 private final CommandSender sender ;
230245 private final String [] args ;
231246
232- private Text (TextManager manager , CommandSender sender , Map < String , JsonConfiguration > mapping , String path , String ... args ) {
247+ private Text (TextManager manager , CommandSender sender , String file , String path , String ... args ) {
233248 this .plugin = manager .plugin ;
234249 this .manager = manager ;
235250 this .sender = sender ;
236- this .mapping = mapping ;
251+ this .mapping = manager . locale2ContentMapping . get ( file ) ;
237252 this .path = path ;
238253 this .args = args ;
239254 }
240255
241- private Text (TextManager manager , UUID sender , Map < String , JsonConfiguration > mapping , String path , String ... args ) {
256+ private Text (TextManager manager , UUID sender , String file , String path , String ... args ) {
242257 this .plugin = manager .plugin ;
243258 this .manager = manager ;
244259 if (sender != null )
245260 this .sender = Bukkit .getPlayer (sender );
246261 else
247262 this .sender = null ;
248- this .mapping = mapping ;
263+ this .mapping = manager . locale2ContentMapping . get ( file ) ;
249264 this .path = path ;
250265 this .args = args ;
251266 }
0 commit comments