@@ -188,12 +188,15 @@ public class JavaSEPort extends CodenameOneImplementation {
188188
189189
190190 private static final int ICON_SIZE=24;
191+ private static final String PREF_AUTO_UPDATE_DEFAULT_BUNDLE = "cn1.autoDefaultResourceBundle";
191192 public final static boolean IS_MAC;
192193 private static boolean isIOS;
193194 public static boolean blockNativeBrowser;
194195 private static final boolean isWindows;
195196 private static String fontFaceSystem;
196197 private Boolean darkMode;
198+ private AutoLocalizationBundle autoLocalizationBundle;
199+ private boolean autoUpdateDefaultResourceBundle;
197200
198201 /**
199202 * @return the fullScreen
@@ -227,6 +230,12 @@ private JFrame findTopFrame() {
227230 @Override
228231 public boolean isFullScreenSupported() {
229232 Preferences pref = Preferences.userNodeForPackage(JavaSEPort.class);
233+ autoUpdateDefaultResourceBundle = pref.getBoolean(PREF_AUTO_UPDATE_DEFAULT_BUNDLE, false);
234+ if (autoUpdateDefaultResourceBundle) {
235+ enableAutoLocalizationBundle();
236+ } else {
237+ disableAutoLocalizationBundle();
238+ }
230239 boolean desktopSkin = pref.getBoolean("desktopSkin", false);
231240 if (isSimulator() && !desktopSkin) {
232241 return false;
@@ -3484,6 +3493,24 @@ public void itemStateChanged(ItemEvent e) {
34843493 });
34853494 simulatorMenu.add(useAppFrameMenu);
34863495
3496+ final JCheckBoxMenuItem autoLocalizationMenu = new JCheckBoxMenuItem("Auto Update Default Bundle");
3497+ autoLocalizationMenu.setSelected(autoUpdateDefaultResourceBundle);
3498+ autoLocalizationMenu.addItemListener(new ItemListener() {
3499+
3500+ @Override
3501+ public void itemStateChanged(ItemEvent e) {
3502+ boolean selected = autoLocalizationMenu.isSelected();
3503+ autoUpdateDefaultResourceBundle = selected;
3504+ pref.putBoolean(PREF_AUTO_UPDATE_DEFAULT_BUNDLE, selected);
3505+ if (selected) {
3506+ enableAutoLocalizationBundle();
3507+ } else {
3508+ disableAutoLocalizationBundle();
3509+ }
3510+ }
3511+ });
3512+ simulatorMenu.add(autoLocalizationMenu);
3513+
34873514 final JCheckBoxMenuItem zoomMenu = new JCheckBoxMenuItem("Zoom", scrollableSkin);
34883515 if (appFrame == null) simulatorMenu.add(zoomMenu);
34893516
@@ -5281,6 +5308,12 @@ public void init(Object m) {
52815308 }*/
52825309
52835310 Preferences pref = Preferences.userNodeForPackage(JavaSEPort.class);
5311+ autoUpdateDefaultResourceBundle = pref.getBoolean(PREF_AUTO_UPDATE_DEFAULT_BUNDLE, false);
5312+ if (autoUpdateDefaultResourceBundle) {
5313+ enableAutoLocalizationBundle();
5314+ } else {
5315+ disableAutoLocalizationBundle();
5316+ }
52845317 boolean desktopSkin = pref.getBoolean("desktopSkin", false);
52855318 if (desktopSkin && m == null) {
52865319 safeAreaLandscape = null;
@@ -13623,7 +13656,260 @@ public Boolean canExecute(String url) {
1362313656 return super.canExecute(url);
1362413657 }
1362513658
13626-
13659+
13660+ private void enableAutoLocalizationBundle() {
13661+ File bundleFile = findDefaultLocalizationBundleFile();
13662+ if (bundleFile == null) {
13663+ return;
13664+ }
13665+ Map<String, String> current = UIManager.getInstance().getBundle();
13666+ if (current instanceof AutoLocalizationBundle) {
13667+ AutoLocalizationBundle existing = (AutoLocalizationBundle) current;
13668+ if (existing.isForFile(bundleFile)) {
13669+ autoLocalizationBundle = existing;
13670+ existing.ensureFileExists();
13671+ return;
13672+ }
13673+ }
13674+ AutoLocalizationBundle newBundle = new AutoLocalizationBundle(bundleFile, current);
13675+ autoLocalizationBundle = newBundle;
13676+ UIManager.getInstance().setBundle(newBundle);
13677+ }
13678+
13679+ private void disableAutoLocalizationBundle() {
13680+ Map<String, String> current = UIManager.getInstance().getBundle();
13681+ if (current instanceof AutoLocalizationBundle) {
13682+ AutoLocalizationBundle existing = (AutoLocalizationBundle) current;
13683+ Map<String, String> snapshot = new HashMap<String, String>(existing);
13684+ UIManager.getInstance().setBundle(snapshot);
13685+ }
13686+ autoLocalizationBundle = null;
13687+ }
13688+
13689+ private File findDefaultLocalizationBundleFile() {
13690+ File localizationDir = findLocalizationDirectory();
13691+ if (localizationDir == null) {
13692+ return null;
13693+ }
13694+ java.util.List<File> bundles = new java.util.ArrayList<File>();
13695+ collectLocalizationBundles(localizationDir, bundles);
13696+ File preferred = new File(localizationDir, "Bundle.properties");
13697+ if (preferred.exists()) {
13698+ return preferred;
13699+ }
13700+ File best = null;
13701+ for (File f : bundles) {
13702+ String name = f.getName();
13703+ if (!name.endsWith(".properties")) {
13704+ continue;
13705+ }
13706+ String base = name.substring(0, name.length() - ".properties".length());
13707+ if (base.indexOf('_') < 0) {
13708+ if (best == null) {
13709+ best = f;
13710+ }
13711+ if ("Bundle".equals(base)) {
13712+ best = f;
13713+ break;
13714+ }
13715+ }
13716+ }
13717+ if (best != null) {
13718+ return best;
13719+ }
13720+ if (!bundles.isEmpty()) {
13721+ java.util.Collections.sort(bundles);
13722+ return bundles.get(0);
13723+ }
13724+ return preferred;
13725+ }
13726+
13727+ private void collectLocalizationBundles(File dir, java.util.List<File> out) {
13728+ File[] files = dir.listFiles();
13729+ if (files == null) {
13730+ return;
13731+ }
13732+ for (File f : files) {
13733+ if (f.isDirectory()) {
13734+ collectLocalizationBundles(f, out);
13735+ } else if (f.getName().endsWith(".properties")) {
13736+ out.add(f);
13737+ }
13738+ }
13739+ }
13740+
13741+ private File findLocalizationDirectory() {
13742+ File projectDir = getCWD();
13743+ File[] candidates = new File[]{
13744+ new File(projectDir, "src" + File.separator + "main" + File.separator + "l10n"),
13745+ new File(projectDir, "l10n"),
13746+ new File(projectDir, "src" + File.separator + "l10n")
13747+ };
13748+ for (File dir : candidates) {
13749+ if (dir.exists() && dir.isDirectory()) {
13750+ return dir;
13751+ }
13752+ }
13753+ File fallback = candidates[0];
13754+ if (!fallback.exists()) {
13755+ fallback.mkdirs();
13756+ }
13757+ if (fallback.exists() && fallback.isDirectory()) {
13758+ return fallback;
13759+ }
13760+ return null;
13761+ }
13762+
13763+ private static class AutoLocalizationBundle extends Hashtable<String, String> {
13764+ private static final long serialVersionUID = 1L;
13765+
13766+ private File bundleFile;
13767+ private final java.util.Properties properties = new java.util.Properties();
13768+ private boolean dirty;
13769+
13770+ AutoLocalizationBundle(File bundleFile, Map<String, String> base) {
13771+ this.bundleFile = bundleFile;
13772+ ensureParentExists();
13773+ if (bundleFile.exists()) {
13774+ loadFromFile();
13775+ } else {
13776+ persist();
13777+ }
13778+ if (base != null && !base.isEmpty()) {
13779+ for (Map.Entry<String, String> entry : base.entrySet()) {
13780+ if (entry.getKey() == null || entry.getValue() == null) {
13781+ continue;
13782+ }
13783+ putInternal(entry.getKey(), entry.getValue());
13784+ storeEntry(entry.getKey(), entry.getValue(), false);
13785+ }
13786+ persistIfNeeded(true);
13787+ }
13788+ }
13789+
13790+ private void loadFromFile() {
13791+ try (InputStream in = new FileInputStream(bundleFile)) {
13792+ properties.clear();
13793+ properties.load(in);
13794+ super.clear();
13795+ for (String name : properties.stringPropertyNames()) {
13796+ putInternal(name, properties.getProperty(name));
13797+ }
13798+ dirty = false;
13799+ } catch (IOException err) {
13800+ Log.e(err);
13801+ }
13802+ }
13803+
13804+ private void ensureParentExists() {
13805+ File parent = bundleFile.getParentFile();
13806+ if (parent != null && !parent.exists()) {
13807+ parent.mkdirs();
13808+ }
13809+ }
13810+
13811+ private void persist() {
13812+ ensureParentExists();
13813+ try (OutputStream out = new FileOutputStream(bundleFile)) {
13814+ properties.store(out, "Codename One auto-generated bundle");
13815+ } catch (IOException err) {
13816+ Log.e(err);
13817+ }
13818+ dirty = false;
13819+ }
13820+
13821+ private void persistIfNeeded(boolean force) {
13822+ if (force) {
13823+ if (dirty || !bundleFile.exists()) {
13824+ persist();
13825+ } else {
13826+ ensureParentExists();
13827+ }
13828+ } else if (dirty) {
13829+ persist();
13830+ }
13831+ }
13832+
13833+ private void storeEntry(String key, String value, boolean flush) {
13834+ if (key == null || value == null) {
13835+ return;
13836+ }
13837+ String current = properties.getProperty(key);
13838+ if (current == null || !current.equals(value)) {
13839+ properties.setProperty(key, value);
13840+ dirty = true;
13841+ }
13842+ if (flush) {
13843+ persistIfNeeded(true);
13844+ }
13845+ }
13846+
13847+ private String putInternal(String key, String value) {
13848+ return (String) super.put(key, value);
13849+ }
13850+
13851+ @Override
13852+ public synchronized String get(Object key) {
13853+ String value = super.get(key);
13854+ if (key instanceof String) {
13855+ String strKey = (String) key;
13856+ if (value == null) {
13857+ String autoValue = strKey;
13858+ putInternal(strKey, autoValue);
13859+ storeEntry(strKey, autoValue, true);
13860+ value = autoValue;
13861+ }
13862+ }
13863+ return value;
13864+ }
13865+
13866+ @Override
13867+ public synchronized String put(String key, String value) {
13868+ String result = putInternal(key, value);
13869+ storeEntry(key, value, true);
13870+ return result;
13871+ }
13872+
13873+ @Override
13874+ public synchronized String remove(Object key) {
13875+ String result = super.remove(key);
13876+ if (key instanceof String) {
13877+ if (properties.containsKey(key)) {
13878+ properties.remove(key);
13879+ dirty = true;
13880+ persistIfNeeded(true);
13881+ } else {
13882+ ensureParentExists();
13883+ }
13884+ }
13885+ return result;
13886+ }
13887+
13888+ @Override
13889+ public synchronized void clear() {
13890+ super.clear();
13891+ if (!properties.isEmpty()) {
13892+ properties.clear();
13893+ dirty = true;
13894+ persistIfNeeded(true);
13895+ } else {
13896+ ensureParentExists();
13897+ }
13898+ }
13899+
13900+ boolean isForFile(File file) {
13901+ return bundleFile.equals(file);
13902+ }
13903+
13904+ void ensureFileExists() {
13905+ ensureParentExists();
13906+ if (!bundleFile.exists()) {
13907+ persist();
13908+ }
13909+ }
13910+ }
13911+
13912+
1362713913 public static File getCWD() {
1362813914 return new File(System.getProperty("user.dir"));
1362913915 }
0 commit comments