diff --git a/core/src/com/unciv/UncivGame.kt b/core/src/com/unciv/UncivGame.kt index 4887e5ea88..757bc8ebc0 100644 --- a/core/src/com/unciv/UncivGame.kt +++ b/core/src/com/unciv/UncivGame.kt @@ -14,6 +14,7 @@ import com.unciv.logic.map.MapParameters import com.unciv.models.metadata.GameParameters import com.unciv.models.metadata.GameSettings import com.unciv.models.ruleset.Ruleset +import com.unciv.models.translations.Translations import com.unciv.ui.LanguagePickerScreen import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.ImageGetter @@ -38,10 +39,13 @@ class UncivGame(val version: String) : Game() { var music : Music? =null val musicLocation = "music/thatched-villagers.mp3" - var isInitialized=false + var isInitialized = false + var rewriteTranslationFiles = false lateinit var ruleset:Ruleset + val translations = Translations() + override fun create() { Gdx.input.setCatchKey(Input.Keys.BACK, true) if (Gdx.app.type != Application.ApplicationType.Desktop) @@ -58,6 +62,14 @@ class UncivGame(val version: String) : Game() { thread { ruleset = Ruleset(true) + if(rewriteTranslationFiles) { // Yes, also when running from the Jar. Sue me. + translations.readAllLanguagesTranslation() + translations.writeNewTranslationFiles() + } + else{ + translations.tryReadTranslationForCurrentLanguage() + } + if (settings.userId == "") { // assign permanent user id settings.userId = UUID.randomUUID().toString() settings.save() diff --git a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt index 08371be4de..d50b24001a 100644 --- a/core/src/com/unciv/logic/automation/NextTurnAutomation.kt +++ b/core/src/com/unciv/logic/automation/NextTurnAutomation.kt @@ -12,7 +12,7 @@ import com.unciv.logic.map.MapUnit import com.unciv.logic.trade.* import com.unciv.models.ruleset.VictoryType import com.unciv.models.ruleset.tech.Technology -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import kotlin.math.min class NextTurnAutomation{ diff --git a/core/src/com/unciv/logic/city/CityConstructions.kt b/core/src/com/unciv/logic/city/CityConstructions.kt index 14555f15b9..d11d344817 100644 --- a/core/src/com/unciv/logic/city/CityConstructions.kt +++ b/core/src/com/unciv/logic/city/CityConstructions.kt @@ -6,7 +6,7 @@ import com.unciv.logic.automation.ConstructionAutomation import com.unciv.logic.civilization.AlertType import com.unciv.logic.civilization.PopupAlert import com.unciv.models.ruleset.Building -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.stats.Stats import com.unciv.ui.utils.withItem import com.unciv.ui.utils.withoutItem diff --git a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt index 07cf3a2d67..cd688f4dfa 100644 --- a/core/src/com/unciv/logic/civilization/CivilizationInfo.kt +++ b/core/src/com/unciv/logic/civilization/CivilizationInfo.kt @@ -19,6 +19,7 @@ import com.unciv.models.ruleset.tech.TechEra import com.unciv.models.ruleset.tile.ResourceSupplyList import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.stats.Stats +import com.unciv.models.translations.tr import java.util.* import kotlin.collections.ArrayList import kotlin.collections.HashMap diff --git a/core/src/com/unciv/logic/map/TileInfo.kt b/core/src/com/unciv/logic/map/TileInfo.kt index cafa40f779..c95eb18e9b 100644 --- a/core/src/com/unciv/logic/map/TileInfo.kt +++ b/core/src/com/unciv/logic/map/TileInfo.kt @@ -7,7 +7,7 @@ import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.tile.* -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.stats.Stats import kotlin.math.abs diff --git a/core/src/com/unciv/logic/trade/TradeLogic.kt b/core/src/com/unciv/logic/trade/TradeLogic.kt index a261b2fdec..41df65a28c 100644 --- a/core/src/com/unciv/logic/trade/TradeLogic.kt +++ b/core/src/com/unciv/logic/trade/TradeLogic.kt @@ -4,7 +4,7 @@ import com.unciv.Constants import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.diplomacy.DiplomaticStatus import com.unciv.models.ruleset.tile.ResourceType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr class TradeLogic(val ourCivilization:CivilizationInfo, val otherCivilization: CivilizationInfo){ diff --git a/core/src/com/unciv/logic/trade/TradeOffer.kt b/core/src/com/unciv/logic/trade/TradeOffer.kt index 6c3cecbe68..ed709d826b 100644 --- a/core/src/com/unciv/logic/trade/TradeOffer.kt +++ b/core/src/com/unciv/logic/trade/TradeOffer.kt @@ -1,6 +1,6 @@ package com.unciv.logic.trade -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr data class TradeOffer(var name:String, var type: TradeType, /** 0 for offers that are immediate (e.g. gold transfer) */ var duration:Int, var amount:Int=1) { diff --git a/core/src/com/unciv/models/ruleset/Building.kt b/core/src/com/unciv/models/ruleset/Building.kt index dadfcda9a3..b73ec62573 100644 --- a/core/src/com/unciv/models/ruleset/Building.kt +++ b/core/src/com/unciv/models/ruleset/Building.kt @@ -7,6 +7,7 @@ import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.stats.NamedStats import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats +import com.unciv.models.translations.tr import kotlin.math.pow class Building : NamedStats(), IConstruction{ diff --git a/core/src/com/unciv/models/ruleset/Ruleset.kt b/core/src/com/unciv/models/ruleset/Ruleset.kt index f9475af45d..c425b0d573 100644 --- a/core/src/com/unciv/models/ruleset/Ruleset.kt +++ b/core/src/com/unciv/models/ruleset/Ruleset.kt @@ -1,6 +1,5 @@ package com.unciv.models.ruleset -import com.badlogic.gdx.Application import com.badlogic.gdx.Gdx import com.badlogic.gdx.utils.Json import com.unciv.models.ruleset.tech.TechColumn @@ -11,9 +10,6 @@ import com.unciv.models.ruleset.tile.TileResource import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.models.ruleset.unit.Promotion import com.unciv.models.stats.INamed -import java.util.* -import kotlin.collections.ArrayList -import kotlin.collections.LinkedHashMap import kotlin.collections.set class Ruleset { @@ -27,7 +23,6 @@ class Ruleset { val Nations = LinkedHashMap() val PolicyBranches = LinkedHashMap() val Difficulties = LinkedHashMap() - val Translations = Translations() fun getFromJson(tClass: Class, filePath:String): T { val jsonText = Gdx.files.internal(filePath).readString(Charsets.UTF_8.name()) @@ -52,7 +47,6 @@ class Ruleset { newRuleset.Terrains.putAll(Terrains) newRuleset.TileImprovements.putAll(TileImprovements) newRuleset.TileResources.putAll(TileResources) - newRuleset.Translations.putAll(Translations) newRuleset.UnitPromotions.putAll(UnitPromotions) newRuleset.Units.putAll(Units) return newRuleset @@ -107,79 +101,7 @@ class Ruleset { val gameBasicsLoadTime = System.currentTimeMillis() - gameBasicsStartTime println("Loading game basics - "+gameBasicsLoadTime+"ms") - // Apparently you can't iterate over the files in a directory when running out of a .jar... - // https://www.badlogicgames.com/forum/viewtopic.php?f=11&t=27250 - // which means we need to list everything manually =/ - - val translationStart = System.currentTimeMillis() - - - readTranslationsFromProperties() -// readTranslationsFromJson() - if(Gdx.app.type==Application.ApplicationType.Desktop) // Yes, also when running from the Jar. Sue me. - writeNewTranslationFiles() - - val translationFilesTime = System.currentTimeMillis() - translationStart - println("Loading translation files - "+translationFilesTime+"ms") } - private fun writeNewTranslationFiles() { - for (language in Translations.getLanguages()) { - val languageHashmap = HashMap() - - for (translation in Translations.values) { - if (translation.containsKey(language)) - languageHashmap[translation.entry] = translation[language]!! - } - TranslationFileReader().writeByTemplate(language, languageHashmap) - } - - } - - private fun readTranslationsFromProperties() { - - val languages = ArrayList() - // So apparently the Locales don't work for everyone, which is horrendous - // So for those players, which seem to be Android-y, we try to see what files exist directly...yeah =/ - try{ - for(file in Gdx.files.internal("jsons/translationsByLanguage").list()) - languages.add(file.nameWithoutExtension()) - } - catch (ex:Exception){} // Iterating on internal files will not work when running from a .jar - - languages.addAll(Locale.getAvailableLocales() // And this should work for Desktop, meaning from a .jar - .map { it.getDisplayName(Locale.ENGLISH) }) // Maybe THIS is the problem, that the DISPLAY locale wasn't english - // and then languages were displayed according to the player's locale... *sweatdrop* - - // These should probably ve renamed - languages.add("Simplified_Chinese") - languages.add("Traditional_Chinese") - - for (language in languages.distinct()) { - val translationFileName = "jsons/translationsByLanguage/$language.properties" - if (!Gdx.files.internal(translationFileName).exists()) continue - val languageTranslations = TranslationFileReader().read(translationFileName,Translations.keys) - - for (translation in languageTranslations) { - if (!Translations.containsKey(translation.key)) - Translations[translation.key] = TranslationEntry(translation.key) - Translations[translation.key]!![language] = translation.value - } - } - } - - private fun readTranslationsFromJson() { - - val translationFileNames = listOf("Buildings","Diplomacy,Trade,Nations", - "NewGame,SaveGame,LoadGame,Options", "Notifications","Other","Policies","Techs", - "Terrains,Resources,Improvements","Units,Promotions") - - for (fileName in translationFileNames) { - val file = Gdx.files.internal("jsons/Translations/$fileName.json") - if (file.exists()) { - Translations.add(file.readString(Charsets.UTF_8.name())) - } - } - } } diff --git a/core/src/com/unciv/models/ruleset/Translations.kt b/core/src/com/unciv/models/ruleset/Translations.kt deleted file mode 100644 index be80f9d740..0000000000 --- a/core/src/com/unciv/models/ruleset/Translations.kt +++ /dev/null @@ -1,164 +0,0 @@ -package com.unciv.models.ruleset - -import com.badlogic.gdx.Gdx -import com.badlogic.gdx.utils.JsonReader -import com.unciv.UncivGame - -class TranslationEntry(val entry: String) : HashMap() { - - /** For memory performance on .tr(), which was atrociously memory-expensive */ - var entryWithShortenedSquareBrackets ="" - - init { - if(entry.contains('[')) - entryWithShortenedSquareBrackets=entry.replace(squareBraceRegex,"[]") - } -} - -class Translations : LinkedHashMap(){ - - fun add(json:String){ - val jsonValue = JsonReader().parse(json)!! - - var currentEntry = jsonValue.child - while(currentEntry!=null){ - val currentEntryName = currentEntry.name!! - val translationEntry = TranslationEntry(currentEntryName) - this[currentEntryName]=translationEntry - - var currentLanguage = currentEntry.child - while(currentLanguage!=null){ - translationEntry[currentLanguage.name!!]=currentLanguage.asString() - currentLanguage = currentLanguage.next - } - currentEntry = currentEntry.next - } - - - } - - fun get(text:String,language:String): String { - if(!hasTranslation(text,language)) return text - return get(text)!![language]!! - } - - fun hasTranslation(text:String,language:String): Boolean { - return containsKey(text) && get(text)!!.containsKey(language) - } - - fun getLanguages(): List { - val toReturn = mutableListOf() - - for(entry in values) - for(languageName in entry.keys) - if(!toReturn.contains(languageName)) toReturn.add(languageName) - - toReturn.remove("Japanese") // These were for tests but were never actually seriously translated - toReturn.remove("Thai") - return toReturn - } - - companion object { - fun translateBonusOrPenalty(unique:String): String { - val regexResult = Regex("""(Bonus|Penalty) vs (.*) (\d*)%""").matchEntire(unique) - if(regexResult==null) return unique.tr() - else{ - var separatorCharacter = " " - if (UncivGame.Current.settings.language=="Simplified_Chinese")separatorCharacter = "" - val start = regexResult.groups[1]!!.value+" vs ["+regexResult.groups[2]!!.value+"]" - val translatedUnique = start.tr() + separatorCharacter + regexResult.groups[3]!!.value+"%" - return translatedUnique - } - } - } -} - -class TranslationFileReader(){ - fun read(translationFile: String, possibleTranslationValues: MutableSet): LinkedHashMap { - val translations = LinkedHashMap() - val text = Gdx.files.internal(translationFile) - text.reader(Charsets.UTF_8.toString()).forEachLine { - val line=it - if(!line.contains(" = ")) return@forEachLine - val splitLine = line.split(" = ") - if(splitLine[1]!="") { // the value is empty, this means this wasn't translated yet - val value = splitLine[1].replace("\\n","\n") - val key = splitLine[0].replace("\\n","\n") - translations[key] = value - } - } - return translations - } - - fun writeByTemplate(language:String, translations: HashMap){ - val templateFile = Gdx.files.internal("jsons/translationsByLanguage/template.properties") - val stringBuilder = StringBuilder() - for(line in templateFile.reader().readLines()){ - if(!line.contains(" = ")){ // copy as-is - stringBuilder.appendln(line) - continue - } - val translationKey = line.split(" = ")[0].replace("\\n","\n") - var translationValue = "" - if(translations.containsKey(translationKey)) translationValue = translations[translationKey]!! - else stringBuilder.appendln(" # Requires translation!") - val lineToWrite = translationKey.replace("\n","\\n") + - " = "+ translationValue.replace("\n","\\n") - stringBuilder.appendln(lineToWrite) - } - Gdx.files.local("jsons/translationsByLanguage/$language.properties") - .writeString(stringBuilder.toString(),false,Charsets.UTF_8.name()) - } -} - -val squareBraceRegex = Regex("\\[(.*?)\\]") // we don't need to allocate different memory for this every time we .tr() - -val eitherSquareBraceRegex=Regex("\\[|\\]") - -fun String.tr(): String { - - // THIS IS INCREDIBLY INEFFICIENT and causes loads of memory problems! - if(contains("[")){ // Placeholders! - /** - * I'm SURE there's an easier way to do this but I can't think of it =\ - * So what's all this then? - * Well, not all languages are like English. So say I want to say "work on Library has completed in Akkad", - * but in a completely different language like Japanese or German, - * It could come out "Akkad hast die worken onner Library gerfinishen" or whatever, - * basically, the order of the words in the sentence is not guaranteed. - * So to translate this, I give a sentence like "work on [building] has completed in [city]" - * and the german can put those placeholders where he wants, so "[city] hast die worken onner [building] gerfinishen" - * The string on which we call tr() will look like "work on [library] has completed in [Akkad]" - * We will find the german placeholder text, and replace the placeholders with what was filled in the text we got! - */ - - val translationStringWithSquareBracketsOnly = replace(squareBraceRegex,"[]") - - val translationEntry = UncivGame.Current.ruleset.Translations.values - .firstOrNull { translationStringWithSquareBracketsOnly == it.entryWithShortenedSquareBrackets } - - if(translationEntry==null || - !translationEntry.containsKey(UncivGame.Current.settings.language)){ - // Translation placeholder doesn't exist for this language, default to English - return this.replace(eitherSquareBraceRegex,"") - } - - val termsInMessage = squareBraceRegex.findAll(this).map { it.groups[1]!!.value }.toList() - val termsInTranslationPlaceholder = squareBraceRegex.findAll(translationEntry.entry).map { it.value }.toList() - if(termsInMessage.size!=termsInTranslationPlaceholder.size) - throw Exception("Message $this has a different number of terms than the placeholder $translationEntry!") - - var languageSpecificPlaceholder = translationEntry[UncivGame.Current.settings.language]!! - for(i in termsInMessage.indices){ - languageSpecificPlaceholder = languageSpecificPlaceholder.replace(termsInTranslationPlaceholder[i], termsInMessage[i].tr()) - } - return languageSpecificPlaceholder.tr() - } - - if(contains("{")){ // sentence - return Regex("\\{(.*?)\\}").replace(this) { it.groups[1]!!.value.tr() } - } - - val translation = UncivGame.Current.ruleset.Translations.get(this, UncivGame.Current.settings.language) // single word - return translation -} diff --git a/core/src/com/unciv/models/ruleset/tech/Technology.kt b/core/src/com/unciv/models/ruleset/tech/Technology.kt index 16242364c8..f2a04ded36 100644 --- a/core/src/com/unciv/models/ruleset/tech/Technology.kt +++ b/core/src/com/unciv/models/ruleset/tech/Technology.kt @@ -4,7 +4,7 @@ import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.ruleset.Building import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.ruleset.unit.BaseUnit import java.util.* diff --git a/core/src/com/unciv/models/ruleset/tile/Terrain.kt b/core/src/com/unciv/models/ruleset/tile/Terrain.kt index 9e98430991..b76feb546c 100644 --- a/core/src/com/unciv/models/ruleset/tile/Terrain.kt +++ b/core/src/com/unciv/models/ruleset/tile/Terrain.kt @@ -2,7 +2,7 @@ package com.unciv.models.ruleset.tile import com.badlogic.gdx.graphics.Color import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.stats.NamedStats import com.unciv.ui.utils.colorFromRGB diff --git a/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt b/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt index e82ee909fb..bc8e2d3498 100644 --- a/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt +++ b/core/src/com/unciv/models/ruleset/tile/TileImprovement.kt @@ -2,7 +2,7 @@ package com.unciv.models.ruleset.tile import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.stats.NamedStats import com.unciv.models.stats.Stats import java.util.* diff --git a/core/src/com/unciv/models/ruleset/tile/TileResource.kt b/core/src/com/unciv/models/ruleset/tile/TileResource.kt index 076eada7ee..f916337163 100644 --- a/core/src/com/unciv/models/ruleset/tile/TileResource.kt +++ b/core/src/com/unciv/models/ruleset/tile/TileResource.kt @@ -1,6 +1,6 @@ package com.unciv.models.ruleset.tile -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.stats.NamedStats import com.unciv.models.stats.Stats import java.util.* diff --git a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt index 0ca5fc2d90..b1f9500eb3 100644 --- a/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt +++ b/core/src/com/unciv/models/ruleset/unit/BaseUnit.kt @@ -7,8 +7,8 @@ import com.unciv.logic.city.IConstruction import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.map.MapUnit import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.Translations -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.Translations +import com.unciv.models.translations.tr import com.unciv.models.stats.INamed // This is BaseUnit because Unit is already a base Kotlin class and to avoid mixing the two up @@ -41,7 +41,7 @@ class BaseUnit : INamed, IConstruction { fun getShortDescription(): String { val infoList= mutableListOf() for(unique in uniques) - infoList+=Translations.translateBonusOrPenalty(unique) + infoList+= Translations.translateBonusOrPenalty(unique) for(promotion in promotions) infoList += promotion.tr() if(strength!=0) infoList += "{Strength}: $strength".tr() diff --git a/core/src/com/unciv/models/stats/Stats.kt b/core/src/com/unciv/models/stats/Stats.kt index 1cecf28dca..6c7bb16e7e 100644 --- a/core/src/com/unciv/models/stats/Stats.kt +++ b/core/src/com/unciv/models/stats/Stats.kt @@ -1,6 +1,6 @@ package com.unciv.models.stats -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr open class Stats() { diff --git a/core/src/com/unciv/models/translations/TranslationEntry.kt b/core/src/com/unciv/models/translations/TranslationEntry.kt new file mode 100644 index 0000000000..33dd94729c --- /dev/null +++ b/core/src/com/unciv/models/translations/TranslationEntry.kt @@ -0,0 +1,14 @@ +package com.unciv.models.translations + +import java.util.HashMap + +class TranslationEntry(val entry: String) : HashMap() { + + /** For memory performance on .tr(), which was atrociously memory-expensive */ + var entryWithShortenedSquareBrackets ="" + + init { + if(entry.contains('[')) + entryWithShortenedSquareBrackets=entry.replace(squareBraceRegex,"[]") + } +} \ No newline at end of file diff --git a/core/src/com/unciv/models/translations/TranslationFileReader.kt b/core/src/com/unciv/models/translations/TranslationFileReader.kt new file mode 100644 index 0000000000..084f5ebc6b --- /dev/null +++ b/core/src/com/unciv/models/translations/TranslationFileReader.kt @@ -0,0 +1,44 @@ +package com.unciv.models.translations + +import com.badlogic.gdx.Gdx +import java.util.* +import kotlin.collections.LinkedHashMap +import kotlin.collections.set + +class TranslationFileReader(){ + fun read(translationFile: String): LinkedHashMap { + val translations = LinkedHashMap() + val text = Gdx.files.internal(translationFile) + text.reader(Charsets.UTF_8.toString()).forEachLine { + val line=it + if(!line.contains(" = ")) return@forEachLine + val splitLine = line.split(" = ") + if(splitLine[1]!="") { // the value is empty, this means this wasn't translated yet + val value = splitLine[1].replace("\\n","\n") + val key = splitLine[0].replace("\\n","\n") + translations[key] = value + } + } + return translations + } + + fun writeByTemplate(language:String, translations: HashMap){ + val templateFile = Gdx.files.internal("jsons/translationsByLanguage/template.properties") + val stringBuilder = StringBuilder() + for(line in templateFile.reader().readLines()){ + if(!line.contains(" = ")){ // copy as-is + stringBuilder.appendln(line) + continue + } + val translationKey = line.split(" = ")[0].replace("\\n","\n") + var translationValue = "" + if(translations.containsKey(translationKey)) translationValue = translations[translationKey]!! + else stringBuilder.appendln(" # Requires translation!") + val lineToWrite = translationKey.replace("\n","\\n") + + " = "+ translationValue.replace("\n","\\n") + stringBuilder.appendln(lineToWrite) + } + Gdx.files.local("jsons/translationsByLanguage/$language.properties") + .writeString(stringBuilder.toString(),false,Charsets.UTF_8.name()) + } +} \ No newline at end of file diff --git a/core/src/com/unciv/models/translations/Translations.kt b/core/src/com/unciv/models/translations/Translations.kt new file mode 100644 index 0000000000..c414993d08 --- /dev/null +++ b/core/src/com/unciv/models/translations/Translations.kt @@ -0,0 +1,199 @@ +package com.unciv.models.translations + +import com.badlogic.gdx.Gdx +import com.unciv.UncivGame +import java.util.* +import kotlin.collections.ArrayList +import kotlin.collections.HashMap + +class Translations : LinkedHashMap(){ + + fun get(text:String,language:String): String { + if(!hasTranslation(text,language)) return text + return get(text)!![language]!! + } + + fun hasTranslation(text:String,language:String): Boolean { + return containsKey(text) && get(text)!!.containsKey(language) + } + + fun getLanguages(): List { + val toReturn = mutableListOf() + + for(entry in values) + for(languageName in entry.keys) + if(!toReturn.contains(languageName)) toReturn.add(languageName) + + toReturn.remove("Japanese") // These were for tests but were never actually seriously translated + toReturn.remove("Thai") + return toReturn + } + + companion object { + fun translateBonusOrPenalty(unique:String): String { + val regexResult = Regex("""(Bonus|Penalty) vs (.*) (\d*)%""").matchEntire(unique) + if(regexResult==null) return unique.tr() + else{ + var separatorCharacter = " " + if (UncivGame.Current.settings.language=="Simplified_Chinese") separatorCharacter = "" + val start = regexResult.groups[1]!!.value+" vs ["+regexResult.groups[2]!!.value+"]" + val translatedUnique = start.tr() + separatorCharacter + regexResult.groups[3]!!.value+"%" + return translatedUnique + } + } + } + + fun tryReadTranslationForLanguage(language: String){ + val translationStart = System.currentTimeMillis() + + val translationFileName = "jsons/translationsByLanguage/$language.properties" + if (!Gdx.files.internal(translationFileName).exists()) return + val languageTranslations = TranslationFileReader() + .read(translationFileName) + + for (translation in languageTranslations) { + if (!containsKey(translation.key)) + this[translation.key] = TranslationEntry(translation.key) + this[translation.key]!![language] = translation.value + } + + val translationFilesTime = System.currentTimeMillis() - translationStart + println("Loading translation file for $language - "+translationFilesTime+"ms") + } + + fun tryReadTranslationForCurrentLanguage(){ + tryReadTranslationForLanguage(UncivGame.Current.settings.language) + } + + fun getLanguagesWithTranslationFile(): List { + + val languages = ArrayList() + // So apparently the Locales don't work for everyone, which is horrendous + // So for those players, which seem to be Android-y, we try to see what files exist directly...yeah =/ + try{ + for(file in Gdx.files.internal("jsons/translationsByLanguage").list()) + languages.add(file.nameWithoutExtension()) + } + catch (ex:Exception){} // Iterating on internal files will not work when running from a .jar + + languages.addAll(Locale.getAvailableLocales() // And this should work for Desktop, meaning from a .jar + .map { it.getDisplayName(Locale.ENGLISH) }) // Maybe THIS is the problem, that the DISPLAY locale wasn't english + // and then languages were displayed according to the player's locale... *sweatdrop* + + // These should probably be renamed + languages.add("Simplified_Chinese") + languages.add("Traditional_Chinese") + + languages.remove("template") + + return languages.distinct() + .filter { Gdx.files.internal("jsons/translationsByLanguage/$it.properties").exists() } + } + + fun readAllLanguagesTranslation() { + + // Apparently you can't iterate over the files in a directory when running out of a .jar... + // https://www.badlogicgames.com/forum/viewtopic.php?f=11&t=27250 + // which means we need to list everything manually =/ + + val translationStart = System.currentTimeMillis() + + for (language in getLanguagesWithTranslationFile()) { + tryReadTranslationForLanguage(language) + } + + val translationFilesTime = System.currentTimeMillis() - translationStart + println("Loading translation files - "+translationFilesTime+"ms") + } + + + fun writeNewTranslationFiles() { + for (language in getLanguages()) { + val languageHashmap = HashMap() + + for (translation in values) { + if (translation.containsKey(language)) + languageHashmap[translation.entry] = translation[language]!! + } + TranslationFileReader().writeByTemplate(language, languageHashmap) + } + } + + fun getPercentageCompleteOfLanguages(): HashMap { + + val translationStart = System.currentTimeMillis() + + var allTranslations = 0 + Gdx.files.internal("jsons/translationsByLanguage/template.properties") + .reader().forEachLine { if(it.contains(" = ")) allTranslations+=1 } + + val languageToPercentCompleted = HashMap() + for(language in getLanguagesWithTranslationFile()){ + val translationFileName = "jsons/translationsByLanguage/$language.properties" + var translationsOfThisLanguage=0 + Gdx.files.internal(translationFileName).reader() + .forEachLine { if(it.contains(" = ") && !it.endsWith(" = ")) + translationsOfThisLanguage+=1 } + languageToPercentCompleted[language] = translationsOfThisLanguage*100/allTranslations + } + + + val translationFilesTime = System.currentTimeMillis() - translationStart + println("Loading percentage complete of languages - "+translationFilesTime+"ms") + + return languageToPercentCompleted + } +} + +val squareBraceRegex = Regex("\\[(.*?)\\]") // we don't need to allocate different memory for this every time we .tr() + +val eitherSquareBraceRegex=Regex("\\[|\\]") + +fun String.tr(): String { + + // THIS IS INCREDIBLY INEFFICIENT and causes loads of memory problems! + if(contains("[")){ // Placeholders! + /** + * I'm SURE there's an easier way to do this but I can't think of it =\ + * So what's all this then? + * Well, not all languages are like English. So say I want to say "work on Library has completed in Akkad", + * but in a completely different language like Japanese or German, + * It could come out "Akkad hast die worken onner Library gerfinishen" or whatever, + * basically, the order of the words in the sentence is not guaranteed. + * So to translate this, I give a sentence like "work on [building] has completed in [city]" + * and the german can put those placeholders where he wants, so "[city] hast die worken onner [building] gerfinishen" + * The string on which we call tr() will look like "work on [library] has completed in [Akkad]" + * We will find the german placeholder text, and replace the placeholders with what was filled in the text we got! + */ + + val translationStringWithSquareBracketsOnly = replace(squareBraceRegex,"[]") + + val translationEntry = UncivGame.Current.translations.values + .firstOrNull { translationStringWithSquareBracketsOnly == it.entryWithShortenedSquareBrackets } + + if(translationEntry==null || + !translationEntry.containsKey(UncivGame.Current.settings.language)){ + // Translation placeholder doesn't exist for this language, default to English + return this.replace(eitherSquareBraceRegex,"") + } + + val termsInMessage = squareBraceRegex.findAll(this).map { it.groups[1]!!.value }.toList() + val termsInTranslationPlaceholder = squareBraceRegex.findAll(translationEntry.entry).map { it.value }.toList() + if(termsInMessage.size!=termsInTranslationPlaceholder.size) + throw Exception("Message $this has a different number of terms than the placeholder $translationEntry!") + + var languageSpecificPlaceholder = translationEntry[UncivGame.Current.settings.language]!! + for(i in termsInMessage.indices){ + languageSpecificPlaceholder = languageSpecificPlaceholder.replace(termsInTranslationPlaceholder[i], termsInMessage[i].tr()) + } + return languageSpecificPlaceholder.tr() + } + + if(contains("{")){ // sentence + return Regex("\\{(.*?)\\}").replace(this) { it.groups[1]!!.value.tr() } + } + + val translation = UncivGame.Current.translations + .get(this, UncivGame.Current.settings.language) // single word + return translation +} diff --git a/core/src/com/unciv/ui/CivilopediaScreen.kt b/core/src/com/unciv/ui/CivilopediaScreen.kt index ba4de29284..4650598882 100644 --- a/core/src/com/unciv/ui/CivilopediaScreen.kt +++ b/core/src/com/unciv/ui/CivilopediaScreen.kt @@ -4,7 +4,7 @@ import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.ui.* import com.unciv.UncivGame import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.* import java.util.* diff --git a/core/src/com/unciv/ui/EmpireOverviewScreen.kt b/core/src/com/unciv/ui/EmpireOverviewScreen.kt index 3cb205321f..0409eb1e2c 100644 --- a/core/src/com/unciv/ui/EmpireOverviewScreen.kt +++ b/core/src/com/unciv/ui/EmpireOverviewScreen.kt @@ -12,7 +12,7 @@ import com.unciv.logic.civilization.diplomacy.DiplomaticStatus import com.unciv.logic.trade.Trade import com.unciv.logic.trade.TradeOffersList import com.unciv.models.ruleset.tile.ResourceType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.cityscreen.CityScreen import com.unciv.ui.utils.* import java.text.DecimalFormat diff --git a/core/src/com/unciv/ui/LanguagePickerScreen.kt b/core/src/com/unciv/ui/LanguagePickerScreen.kt index 2b4a939143..eca42db048 100644 --- a/core/src/com/unciv/ui/LanguagePickerScreen.kt +++ b/core/src/com/unciv/ui/LanguagePickerScreen.kt @@ -5,8 +5,8 @@ import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table import com.unciv.UncivGame -import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.Translations +import com.unciv.models.translations.tr import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.enable @@ -14,21 +14,15 @@ import com.unciv.ui.utils.onClick import com.unciv.ui.utils.toLabel -class LanguageTable(val language:String, ruleset: Ruleset):Table(){ +class LanguageTable(val language:String, val percentComplete: Int):Table(){ private val blue = ImageGetter.getBlue() private val darkBlue = blue.cpy().lerp(Color.BLACK,0.5f)!! - val percentComplete: Int init{ pad(10f) defaults().pad(10f) if(ImageGetter.imageExists("FlagIcons/$language")) add(ImageGetter.getImage("FlagIcons/$language")).size(40f) - val translations = ruleset.Translations - val availableTranslations = translations.filter { it.value.containsKey(language) } - - if(language=="English") percentComplete = 100 - else percentComplete = (availableTranslations.size*100 / translations.size) - 1 //-1 so if the user encounters anything not translated he'll be like "OK that's the 1% missing" val spaceSplitLang = language.replace("_"," ") add("$spaceSplitLang ($percentComplete%)".toLabel()) @@ -61,9 +55,10 @@ class LanguagePickerScreen: PickerScreen(){ "If you want to help translating the game into your language, \n"+ " instructions are in the Github readme! (Menu > Community > Github)",skin)).pad(10f).row() - val ruleSet = UncivGame.Current.ruleset - languageTables.addAll(ruleSet.Translations.getLanguages().map { LanguageTable(it,ruleSet) } - .sortedByDescending { it.percentComplete } ) + val languageCompletionPercentage = Translations().getPercentageCompleteOfLanguages() + languageTables.addAll(languageCompletionPercentage + .map { LanguageTable(it.key,if(it.key=="English") 100 else it.value) } + .sortedByDescending { it.percentComplete} ) languageTables.forEach { it.onClick { @@ -85,6 +80,8 @@ class LanguagePickerScreen: PickerScreen(){ fun pickLanguage(){ UncivGame.Current.settings.language = chosenLanguage UncivGame.Current.settings.save() + + UncivGame.Current.translations.tryReadTranslationForCurrentLanguage() resetFonts() UncivGame.Current.startNewGame() dispose() diff --git a/core/src/com/unciv/ui/VictoryScreen.kt b/core/src/com/unciv/ui/VictoryScreen.kt index bcd552e670..6abfc086fe 100644 --- a/core/src/com/unciv/ui/VictoryScreen.kt +++ b/core/src/com/unciv/ui/VictoryScreen.kt @@ -7,7 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.ruleset.VictoryType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.newgamescreen.NewGameScreen import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.pickerscreens.PolicyPickerScreen diff --git a/core/src/com/unciv/ui/cityscreen/CityInfoTable.kt b/core/src/com/unciv/ui/cityscreen/CityInfoTable.kt index 6b9408ae79..d75b6ff0e4 100644 --- a/core/src/com/unciv/ui/cityscreen/CityInfoTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityInfoTable.kt @@ -11,7 +11,7 @@ import com.unciv.UncivGame import com.unciv.logic.city.CityInfo import com.unciv.logic.civilization.GreatPersonManager import com.unciv.models.ruleset.Building -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.stats.Stat import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable diff --git a/core/src/com/unciv/ui/cityscreen/CityScreen.kt b/core/src/com/unciv/ui/cityscreen/CityScreen.kt index 29a91b1e57..14b288713a 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreen.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreen.kt @@ -11,7 +11,7 @@ import com.unciv.UncivGame import com.unciv.logic.HexMath import com.unciv.logic.city.CityInfo import com.unciv.logic.map.TileInfo -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.stats.Stat import com.unciv.models.stats.Stats import com.unciv.ui.tilegroups.TileSetStrings diff --git a/core/src/com/unciv/ui/cityscreen/CityScreenCityPickerTable.kt b/core/src/com/unciv/ui/cityscreen/CityScreenCityPickerTable.kt index 2f84afa3c2..d188458888 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreenCityPickerTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreenCityPickerTable.kt @@ -5,7 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.scenes.scene2d.ui.TextField import com.badlogic.gdx.utils.Align -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.onClick diff --git a/core/src/com/unciv/ui/cityscreen/CityScreenTileTable.kt b/core/src/com/unciv/ui/cityscreen/CityScreenTileTable.kt index 653c2abf2d..afc2e252fc 100644 --- a/core/src/com/unciv/ui/cityscreen/CityScreenTileTable.kt +++ b/core/src/com/unciv/ui/cityscreen/CityScreenTileTable.kt @@ -7,7 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.UncivGame import com.unciv.logic.city.CityInfo import com.unciv.logic.map.TileInfo -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.disable diff --git a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt index 774da564d5..67aa4fbc07 100644 --- a/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt +++ b/core/src/com/unciv/ui/cityscreen/ConstructionsTable.kt @@ -10,7 +10,7 @@ import com.unciv.UncivGame import com.unciv.logic.city.CityInfo import com.unciv.logic.city.SpecialConstruction import com.unciv.models.ruleset.Building -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable diff --git a/core/src/com/unciv/ui/mapeditor/LoadMapScreen.kt b/core/src/com/unciv/ui/mapeditor/LoadMapScreen.kt index 541f0e404c..d3d9c1f04b 100644 --- a/core/src/com/unciv/ui/mapeditor/LoadMapScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/LoadMapScreen.kt @@ -8,7 +8,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.UncivGame import com.unciv.logic.MapSaver import com.unciv.logic.map.TileMap -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.saves.Gzip import com.unciv.ui.utils.* diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt b/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt index d828a8dcfb..124d0784e4 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorMenuPopup.kt @@ -9,7 +9,7 @@ import com.unciv.UncivGame import com.unciv.logic.MapSaver import com.unciv.logic.map.MapType import com.unciv.logic.map.RoadStatus -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.saves.Gzip import com.unciv.ui.utils.onClick import com.unciv.ui.worldscreen.optionstable.DropBox diff --git a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt index 2d4d1f180e..af7ef9fbaf 100644 --- a/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt +++ b/core/src/com/unciv/ui/mapeditor/MapEditorScreen.kt @@ -6,7 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.UncivGame import com.unciv.logic.MapSaver import com.unciv.logic.map.TileMap -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.tilegroups.TileGroup import com.unciv.ui.tilegroups.TileSetStrings import com.unciv.ui.utils.CameraStageBaseScreen diff --git a/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt b/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt index aeac28a289..0e0015e9c6 100644 --- a/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt +++ b/core/src/com/unciv/ui/mapeditor/TileEditorOptionsTable.kt @@ -14,7 +14,7 @@ import com.unciv.models.ruleset.tile.Terrain import com.unciv.models.ruleset.tile.TerrainType import com.unciv.models.ruleset.tile.TileImprovement import com.unciv.models.ruleset.tile.TileResource -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.tilegroups.TileGroup import com.unciv.ui.tilegroups.TileSetStrings import com.unciv.ui.utils.* diff --git a/core/src/com/unciv/ui/newgamescreen/MapParametersTable.kt b/core/src/com/unciv/ui/newgamescreen/MapParametersTable.kt index 2db3cbe690..57cc8adcb2 100644 --- a/core/src/com/unciv/ui/newgamescreen/MapParametersTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/MapParametersTable.kt @@ -6,7 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener import com.unciv.logic.map.MapParameters import com.unciv.logic.map.MapType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.toLabel diff --git a/core/src/com/unciv/ui/newgamescreen/NationTable.kt b/core/src/com/unciv/ui/newgamescreen/NationTable.kt index 5cfd894b8d..89ab3f0409 100644 --- a/core/src/com/unciv/ui/newgamescreen/NationTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/NationTable.kt @@ -5,8 +5,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table import com.unciv.models.ruleset.Nation import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.Translations -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.Translations +import com.unciv.models.translations.tr import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.toLabel diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt index b64cf77e0d..053b316b79 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreen.kt @@ -10,7 +10,7 @@ import com.unciv.logic.GameInfo import com.unciv.logic.GameSaver import com.unciv.logic.GameStarter import com.unciv.logic.civilization.PlayerType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.utils.disable import com.unciv.ui.utils.enable diff --git a/core/src/com/unciv/ui/newgamescreen/NewGameScreenOptionsTable.kt b/core/src/com/unciv/ui/newgamescreen/NewGameScreenOptionsTable.kt index 9ac6d1c8d8..4493238dbf 100644 --- a/core/src/com/unciv/ui/newgamescreen/NewGameScreenOptionsTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/NewGameScreenOptionsTable.kt @@ -11,7 +11,7 @@ import com.unciv.logic.MapSaver import com.unciv.models.ruleset.Ruleset import com.unciv.models.ruleset.VictoryType import com.unciv.models.ruleset.tech.TechEra -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.metadata.GameSpeed import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.toLabel diff --git a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt index 432b862054..9a14b148f5 100644 --- a/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt +++ b/core/src/com/unciv/ui/newgamescreen/PlayerPickerTable.kt @@ -11,7 +11,7 @@ import com.badlogic.gdx.utils.Align import com.unciv.UncivGame import com.unciv.logic.civilization.PlayerType import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.metadata.GameParameters import com.unciv.models.metadata.Player import com.unciv.ui.utils.* diff --git a/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt index 48d2528a8a..43e0891108 100644 --- a/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/GreatPersonPickerScreen.kt @@ -4,7 +4,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Button import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.GreatPersonManager -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.ruleset.unit.BaseUnit import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.onClick diff --git a/core/src/com/unciv/ui/pickerscreens/ImprovementPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/ImprovementPickerScreen.kt index ed323d2b4a..0236c8c50b 100644 --- a/core/src/com/unciv/ui/pickerscreens/ImprovementPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/ImprovementPickerScreen.kt @@ -7,7 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.TileInfo import com.unciv.models.ruleset.tile.TileImprovement -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.ImageGetter import com.unciv.ui.utils.addSeparatorVertical import com.unciv.ui.utils.onClick diff --git a/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt index e81dbeaf1f..988b2ba221 100644 --- a/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PickerScreen.kt @@ -2,7 +2,7 @@ package com.unciv.ui.pickerscreens import com.badlogic.gdx.scenes.scene2d.ui.* import com.unciv.UncivGame -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.* open class PickerScreen : CameraStageBaseScreen() { diff --git a/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt index 1530b36796..f2c7e0d2de 100644 --- a/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt @@ -7,7 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.ruleset.Policy -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.WorldScreen diff --git a/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt index a153359a64..858af53718 100644 --- a/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/PromotionPickerScreen.kt @@ -8,8 +8,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup import com.badlogic.gdx.utils.Align import com.unciv.UncivGame import com.unciv.logic.map.MapUnit -import com.unciv.models.ruleset.Translations -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.Translations +import com.unciv.models.translations.tr import com.unciv.models.ruleset.unit.Promotion import com.unciv.ui.utils.* diff --git a/core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt b/core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt index e1fb3e5868..8edc003d1c 100644 --- a/core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt +++ b/core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt @@ -9,7 +9,7 @@ import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.TechManager import com.unciv.models.ruleset.tech.Technology -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.* import java.util.* diff --git a/core/src/com/unciv/ui/saves/LoadGameScreen.kt b/core/src/com/unciv/ui/saves/LoadGameScreen.kt index 15425e71b8..fec4c7544b 100644 --- a/core/src/com/unciv/ui/saves/LoadGameScreen.kt +++ b/core/src/com/unciv/ui/saves/LoadGameScreen.kt @@ -10,7 +10,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener import com.unciv.UncivGame import com.unciv.logic.GameSaver -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.utils.disable import com.unciv.ui.utils.enable diff --git a/core/src/com/unciv/ui/saves/SaveGameScreen.kt b/core/src/com/unciv/ui/saves/SaveGameScreen.kt index eb9db61541..27a53154a5 100644 --- a/core/src/com/unciv/ui/saves/SaveGameScreen.kt +++ b/core/src/com/unciv/ui/saves/SaveGameScreen.kt @@ -7,7 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener import com.badlogic.gdx.utils.Json import com.unciv.UncivGame import com.unciv.logic.GameSaver -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.pickerscreens.PickerScreen import com.unciv.ui.utils.enable import com.unciv.ui.utils.onClick diff --git a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt index 4f278d476e..11e50fd531 100644 --- a/core/src/com/unciv/ui/trade/DiplomacyScreen.kt +++ b/core/src/com/unciv/ui/trade/DiplomacyScreen.kt @@ -18,7 +18,7 @@ import com.unciv.logic.civilization.diplomacy.RelationshipLevel import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.optionstable.YesNoPopupTable import kotlin.math.roundToInt diff --git a/core/src/com/unciv/ui/trade/OfferColumnsTable.kt b/core/src/com/unciv/ui/trade/OfferColumnsTable.kt index 2ebf56e2ba..043ea50c10 100644 --- a/core/src/com/unciv/ui/trade/OfferColumnsTable.kt +++ b/core/src/com/unciv/ui/trade/OfferColumnsTable.kt @@ -6,7 +6,7 @@ import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeOffersList import com.unciv.logic.trade.TradeType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.addSeparator diff --git a/core/src/com/unciv/ui/trade/OffersListScroll.kt b/core/src/com/unciv/ui/trade/OffersListScroll.kt index b3ae5f75cb..5d37935096 100644 --- a/core/src/com/unciv/ui/trade/OffersListScroll.kt +++ b/core/src/com/unciv/ui/trade/OffersListScroll.kt @@ -8,7 +8,7 @@ import com.unciv.logic.trade.TradeOffer import com.unciv.logic.trade.TradeOffersList import com.unciv.logic.trade.TradeType import com.unciv.logic.trade.TradeType.* -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.cityscreen.ExpanderTab import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.disable diff --git a/core/src/com/unciv/ui/trade/TradeTable.kt b/core/src/com/unciv/ui/trade/TradeTable.kt index b1ed6c881d..e436edbfe4 100644 --- a/core/src/com/unciv/ui/trade/TradeTable.kt +++ b/core/src/com/unciv/ui/trade/TradeTable.kt @@ -6,7 +6,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeRequest -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.disable import com.unciv.ui.utils.enable diff --git a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt index 39a22d0cc7..11d711478e 100644 --- a/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt +++ b/core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt @@ -12,7 +12,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.* import com.badlogic.gdx.scenes.scene2d.utils.ClickListener import com.badlogic.gdx.utils.viewport.ExtendViewport import com.unciv.UncivGame -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import kotlin.concurrent.thread open class CameraStageBaseScreen : Screen { diff --git a/core/src/com/unciv/ui/utils/Fonts.kt b/core/src/com/unciv/ui/utils/Fonts.kt index 25d371233a..530056de45 100644 --- a/core/src/com/unciv/ui/utils/Fonts.kt +++ b/core/src/com/unciv/ui/utils/Fonts.kt @@ -34,7 +34,7 @@ class Fonts { if (Gdx.files.internal("jsons/Tutorials/Tutorials_$language.json").exists()) charSet.addAll(Gdx.files.internal("jsons/Tutorials/Tutorials_$language.json").readString().asIterable()) - for (entry in UncivGame.Current.ruleset.Translations.entries) { + for (entry in UncivGame.Current.translations.entries) { for (lang in entry.value) { if (lang.key == language) charSet.addAll(lang.value.asIterable()) } diff --git a/core/src/com/unciv/ui/utils/Tutorials.kt b/core/src/com/unciv/ui/utils/Tutorials.kt index 3ba4911ac6..966567029c 100644 --- a/core/src/com/unciv/ui/utils/Tutorials.kt +++ b/core/src/com/unciv/ui/utils/Tutorials.kt @@ -4,7 +4,7 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.utils.Array import com.unciv.UncivGame -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.worldscreen.optionstable.PopupTable import java.util.* import kotlin.collections.ArrayList diff --git a/core/src/com/unciv/ui/worldscreen/AlertPopup.kt b/core/src/com/unciv/ui/worldscreen/AlertPopup.kt index 3952712f1f..ec0fb5dbfd 100644 --- a/core/src/com/unciv/ui/worldscreen/AlertPopup.kt +++ b/core/src/com/unciv/ui/worldscreen/AlertPopup.kt @@ -5,7 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.logic.civilization.AlertType import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.PopupAlert -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.optionstable.PopupTable diff --git a/core/src/com/unciv/ui/worldscreen/TradePopup.kt b/core/src/com/unciv/ui/worldscreen/TradePopup.kt index c502c8c84e..82f7cf25b5 100644 --- a/core/src/com/unciv/ui/worldscreen/TradePopup.kt +++ b/core/src/com/unciv/ui/worldscreen/TradePopup.kt @@ -7,7 +7,7 @@ import com.unciv.Constants import com.unciv.logic.civilization.diplomacy.DiplomacyFlags import com.unciv.logic.trade.TradeLogic import com.unciv.logic.trade.TradeType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.trade.DiplomacyScreen import com.unciv.ui.utils.addSeparator import com.unciv.ui.utils.toLabel diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt index dc05835c8d..c56216741c 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreen.kt @@ -15,7 +15,7 @@ import com.unciv.logic.GameSaver import com.unciv.logic.civilization.CivilizationInfo import com.unciv.logic.civilization.diplomacy.DiplomaticStatus import com.unciv.models.ruleset.tile.ResourceType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.ruleset.unit.UnitType import com.unciv.ui.VictoryScreen import com.unciv.ui.cityscreen.CityScreen diff --git a/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt b/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt index 569c724ba6..d5bf6c3529 100644 --- a/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt +++ b/core/src/com/unciv/ui/worldscreen/WorldScreenTopBar.kt @@ -10,7 +10,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.UncivGame import com.unciv.logic.civilization.CivilizationInfo import com.unciv.models.ruleset.tile.ResourceType -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.stats.Stats import com.unciv.ui.EmpireOverviewScreen import com.unciv.ui.utils.* diff --git a/core/src/com/unciv/ui/worldscreen/bottombar/BattleTable.kt b/core/src/com/unciv/ui/worldscreen/bottombar/BattleTable.kt index dbdb179e57..90a9e9d038 100644 --- a/core/src/com/unciv/ui/worldscreen/bottombar/BattleTable.kt +++ b/core/src/com/unciv/ui/worldscreen/bottombar/BattleTable.kt @@ -11,7 +11,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.UncivGame import com.unciv.logic.automation.UnitAutomation import com.unciv.logic.battle.* -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.models.ruleset.unit.UnitType import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.WorldScreen diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/PopupTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/PopupTable.kt index abbba98b19..fe149438d7 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/PopupTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/PopupTable.kt @@ -7,7 +7,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.badlogic.gdx.utils.Align -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.* open class PopupTable(val screen: CameraStageBaseScreen): Table(CameraStageBaseScreen.skin) { diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenMenuTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenMenuTable.kt index 2255167581..8766156a94 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenMenuTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenMenuTable.kt @@ -4,7 +4,7 @@ import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.Color import com.unciv.UncivGame import com.unciv.logic.map.RoadStatus -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.CivilopediaScreen import com.unciv.ui.VictoryScreen import com.unciv.ui.mapeditor.MapEditorScreen diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenOptionsTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenOptionsTable.kt index 9de08bc311..7b2a12b967 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenOptionsTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/WorldScreenOptionsTable.kt @@ -7,19 +7,13 @@ import com.badlogic.gdx.scenes.scene2d.ui.* import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener import com.badlogic.gdx.utils.Array import com.unciv.UncivGame -import com.unciv.models.ruleset.Ruleset -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.Translations +import com.unciv.models.translations.tr import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.WorldScreen import kotlin.concurrent.thread -class Language(val language:String, ruleset: Ruleset){ - val percentComplete:Int - init{ - val availableTranslations = ruleset.Translations.count { it.value.containsKey(language) } - if(language=="English") percentComplete = 100 - else percentComplete = (availableTranslations*100 / ruleset.Translations.size) - } +class Language(val language:String, val percentComplete:Int){ override fun toString(): String { val spaceSplitLang = language.replace("_"," ") return "$spaceSplitLang- $percentComplete%" @@ -275,7 +269,8 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr val languageSelectBox = SelectBox(skin) val languageArray = Array() val ruleSet = worldScreen.gameInfo.ruleSet - ruleSet.Translations.getLanguages().map { Language(it, ruleSet) } + Translations().getPercentageCompleteOfLanguages() + .map { Language(it.key, if(it.key=="English") 100 else it.value) } .sortedByDescending { it.percentComplete } .forEach { languageArray.add(it) } languageSelectBox.items = languageArray @@ -298,7 +293,7 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr val missingTextSelectBox = SelectBox(skin) val missingTextArray = Array() val currentLanguage = UncivGame.Current.settings.language - ruleSet.Translations.filter { !it.value.containsKey(currentLanguage) } + UncivGame.Current.translations.filter { !it.value.containsKey(currentLanguage) } .forEach { missingTextArray.add(it.key) } missingTextSelectBox.items = missingTextArray missingTextSelectBox.selected = "Untranslated texts" @@ -310,6 +305,8 @@ class WorldScreenOptionsTable(val worldScreen:WorldScreen) : PopupTable(worldScr fun selectLanguage(){ UncivGame.Current.settings.language = selectedLanguage UncivGame.Current.settings.save() + + UncivGame.Current.translations.tryReadTranslationForCurrentLanguage() CameraStageBaseScreen.resetFonts() // to load chinese characters if necessary UncivGame.Current.worldScreen = WorldScreen(worldScreen.viewingCiv) UncivGame.Current.setWorldScreen() diff --git a/core/src/com/unciv/ui/worldscreen/optionstable/YesNoPopupTable.kt b/core/src/com/unciv/ui/worldscreen/optionstable/YesNoPopupTable.kt index 977ea78c94..8abe6b8f4d 100644 --- a/core/src/com/unciv/ui/worldscreen/optionstable/YesNoPopupTable.kt +++ b/core/src/com/unciv/ui/worldscreen/optionstable/YesNoPopupTable.kt @@ -2,7 +2,7 @@ package com.unciv.ui.worldscreen.optionstable import com.badlogic.gdx.scenes.scene2d.ui.TextButton import com.unciv.UncivGame -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.utils.CameraStageBaseScreen import com.unciv.ui.utils.onClick import com.unciv.ui.utils.toLabel diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt index 7cfb58bfd8..5134c0b541 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitActions.kt @@ -9,7 +9,7 @@ import com.unciv.logic.map.MapUnit import com.unciv.logic.map.RoadStatus import com.unciv.logic.map.TileInfo import com.unciv.models.ruleset.Building -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.pickerscreens.ImprovementPickerScreen import com.unciv.ui.pickerscreens.PromotionPickerScreen import com.unciv.ui.worldscreen.WorldScreen diff --git a/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt b/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt index a3090b6808..accbd9eb23 100644 --- a/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt +++ b/core/src/com/unciv/ui/worldscreen/unit/UnitTable.kt @@ -3,7 +3,6 @@ package com.unciv.ui.worldscreen.unit import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.scenes.scene2d.Touchable import com.badlogic.gdx.scenes.scene2d.ui.Image -import com.badlogic.gdx.scenes.scene2d.ui.Label import com.badlogic.gdx.scenes.scene2d.ui.Table import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup import com.unciv.UncivGame @@ -11,7 +10,7 @@ import com.unciv.logic.battle.CityCombatant import com.unciv.logic.city.CityInfo import com.unciv.logic.map.MapUnit import com.unciv.logic.map.TileInfo -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import com.unciv.ui.pickerscreens.PromotionPickerScreen import com.unciv.ui.utils.* import com.unciv.ui.worldscreen.WorldScreen diff --git a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt index f329ede2d2..3bd99f6100 100644 --- a/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt +++ b/desktop/src/com/unciv/app/desktop/DesktopLauncher.kt @@ -9,7 +9,7 @@ import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration import com.badlogic.gdx.graphics.Texture import com.badlogic.gdx.tools.texturepacker.TexturePacker import com.unciv.UncivGame -import com.unciv.models.ruleset.tr +import com.unciv.models.translations.tr import java.io.File import kotlin.concurrent.thread