/** * Returns a language string with arguments by property key. * * @param property The property key * @param args The arguments * @return The formatted language string */ public static String getf(String property, Object... args) { MessageFormat format = null; LanguageEntry lang = last; if (last == null) last = languages.get(language); if (lang == null) lang = languages.get(DEFAULT); format = lang.getFormat(property); return format != null ? format.format(args) : "{" + property + "}"; }
/** * Returns a language string by property key. * * @param property The property key * @return The language string */ public static String get(String property) { if (last == null) { // We are keeping a reference to the current language // to reduce lookup time (searching the map). last = languages.get(language); } if (last != null) { String msg = last.getMessage(property); if (msg != null) return msg; } LanguageEntry fallback = languages.get(DEFAULT); if (fallback != null) { String str = fallback.getMessage(property); if (str != null) return str; } return "{" + property + "}"; }
/** * Loads a language from a {@link FileHandle} * * @param file The {@link FileHandle} of the language file to load * @return True on success, otherwise false */ protected static boolean loadFile(FileHandle file) { if (!file.isDirectory() && file.extension().equalsIgnoreCase("lang")) { try { LanguageEntry lang = languages.get(file.name()); if (lang == null) { lang = new LanguageEntry(new Properties()); languages.put(file.nameWithoutExtension(), lang); } lang.addProperties(file); } catch (Exception io) { Gdx.app.error( TAG, "Could not load language file with name " + file.nameWithoutExtension(), io); return false; } } else { Gdx.app.debug(TAG, "Ignored " + file.name() + " while loading language file"); } return true; }
/** * This method must be called in a context synchronized on {@link #translationsStatistics}. * * <p>The sorting places the default/recommended choice on top of the list, and then tried to * place other relevant choices close to the top in descending order by relevance. The rest of the * list is alphabetical by the preferred/currently selected language's language names. The sorting * is done following these rules: * * <ul> * <li>The base language (en-US) and the language closest matching <code>preferredLocale</code> * is looked up. If the closest matching language has a coverage greater or equal to {@link * #recommendedTranslatePct} or an approval greater or equal to {@link * #recommendedApprovedPct} it will be placed on top. If not, the base language will be * placed on top. Whichever of these is not placed on top is placed second. If a closely * matching language cannot be found, only the base language will be placed on top. * <li>A search for related languages is performed. Related is defined by either having the same * language code (e.g "en") or the same country code as <code>preferredLocale</code>. * Related languages are then sorted descending by coverage and put after that or those * language(s) placed on top. * <li>The rest of the languages are listed alphabetically based on their localized (from * currently chosen language) names. * </ul> * * If the localized language name differs from the English language name, the English language * name is shown in parenthesis. This is to help in case the localized names are incomprehensible * to the user. */ private static void createSortedList(Locale preferredLocale) { if (preferredLocale == null) { throw new IllegalArgumentException("preferredLocale cannot be null"); } if (lastpreferredLocale == null || !lastpreferredLocale.equals(preferredLocale)) { // Populate lastpreferredLocale = preferredLocale; sortedLanguages.clear(); populateTranslationsStatistics(); for (String tag : UMS_BCP47_CODES) { LanguageEntry entry = new LanguageEntry(); entry.tag = tag; entry.name = Messages.getString("Language." + tag, preferredLocale); if (!entry.name.equals(Messages.getRootString("Language." + tag))) { entry.name += " (" + Messages.getRootString("Language." + tag) + ")"; } entry.locale = Locale.forLanguageTag(tag); if (tag.equals("en-US")) { entry.coveragePercent = 100; entry.approvedPercent = 100; } else { TranslationStatistics stats = translationsStatistics.get(tag); if (stats != null) { if (entry.locale.getLanguage().equals("en") && stats.wordsTranslated > 0) { /* Special case for English language variants that only * overrides the strings that differ from US English. * We cannot find coverage for these */ entry.coveragePercent = 100; entry.approvedPercent = 100; } else { entry.coveragePercent = stats.translated; entry.approvedPercent = stats.approved; } } else { entry.coveragePercent = 0; entry.approvedPercent = 0; LOGGER.debug("Warning: Could not find language statistics for {}", entry.name); } } if (entry.coveragePercent >= minimumTranslatePct) { sortedLanguages.add(entry); } } // Sort Collections.sort(sortedLanguages); // Put US English first LanguageEntry baseLanguage = getSortedLanguageByTag("en-US"); if (baseLanguage == null) { throw new IllegalStateException( "Languages.createSortedList encountered an impossible situation"); } if (sortedLanguages.remove(baseLanguage)) { sortedLanguages.add(0, baseLanguage); } ; // Put matched language first or second depending on coverage LanguageEntry preferredLanguage = getSortedLanguageByLocale(preferredLocale); if (preferredLanguage != null && !preferredLanguage.tag.equals("en-US")) { if (sortedLanguages.remove(preferredLanguage) && isRecommended(preferredLanguage)) { sortedLanguages.add(0, preferredLanguage); } else { /* This could constitute a bug if sortedLanguages.remove(entry) * returned false, but that should be impossible */ sortedLanguages.add(1, preferredLanguage); } } // Put related language(s) close to top List<LanguageEntry> relatedLanguages = new ArrayList<>(); for (LanguageEntry entry : sortedLanguages) { if (entry != baseLanguage && entry != preferredLanguage && (!preferredLocale.getCountry().isEmpty() && preferredLocale.getCountry().equals(entry.locale.getCountry()) || !preferredLocale.getLanguage().isEmpty() && preferredLocale.getLanguage().equals(entry.locale.getLanguage()))) { relatedLanguages.add(entry); } } if (relatedLanguages.size() > 0) { sortedLanguages.removeAll(relatedLanguages); Collections.sort(relatedLanguages, new LanguageEntryCoverageComparator()); sortedLanguages.addAll( preferredLanguage == null || preferredLanguage.equals(baseLanguage) ? 1 : 2, relatedLanguages); } } }