diff --git a/.github/workflows/crowdin-download-workflow.yml b/.github/workflows/crowdin-download-workflow.yml
index b769f5f..ddaec73 100644
--- a/.github/workflows/crowdin-download-workflow.yml
+++ b/.github/workflows/crowdin-download-workflow.yml
@@ -3,123 +3,31 @@ name: Crowdin Download Action
permissions:
contents: write
pull-requests: write
+ actions: read
on:
workflow_dispatch:
- inputs:
- localization_branch_name:
- description: 'The branch to create for the translations PR.'
- required: true
- default: 'crowdin/translations'
- pull_request_base_branch:
- description: 'The base branch for the pull request.'
- required: true
- default: 'dev'
jobs:
- download-translations:
+ crowdin:
runs-on: ubuntu-latest
steps:
- # Checkout the BASE branch first. The PR branch will be created later.
- - name: Checkout Base Branch
+ - name: Checkout
uses: actions/checkout@v4
- with:
- ref: ${{ github.event.inputs.pull_request_base_branch }}
- - name: Configure Git User
- run: |
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
-
- - name: Synchronize with Crowdin (Download Only)
+ - name: Synchronize with Crowdin
uses: crowdin/github-action@v2
with:
upload_sources: false
upload_translations: false
download_translations: true
- create_pull_request: false
- localization_branch_name: ${{ github.event.inputs.localization_branch_name }}
+ localization_branch_name: crowdin_translations
+
+ create_pull_request: true
+ pull_request_title: 'Updated Crowdin translations'
+ pull_request_body: 'New Crowdin pull request with translations'
+ pull_request_base_branch_name: 'dev'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
- CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
-
- rename-files:
- needs: download-translations
- runs-on: ubuntu-latest
- steps:
- - name: Checkout Localization Branch
- uses: actions/checkout@v4
- with:
- ref: ${{ github.event.inputs.localization_branch_name }}
-
- - name: Configure Git User
- run: |
- git config user.name "github-actions[bot]"
- git config user.email "github-actions[bot]@users.noreply.github.com"
-
- - name: Rename JSON Files to Lowercase
- env:
- TARGET_DIR: "src/main/resources/assets/sit-oth3r/lang/"
- run: |
- echo "Starting renaming process for JSON files within $TARGET_DIR..."
- if [ ! -d "$TARGET_DIR" ]; then
- echo "Warning: Target directory '$TARGET_DIR' does not exist. Skipping rename."
- exit 0
- fi
- find "$TARGET_DIR" -type f -name '*[A-Z]*.json' | while IFS= read -r file; do
- original_path="$file"
- dir_name=$(dirname "$original_path")
- base_name=$(basename "$original_path")
- new_base_name=$(echo "$base_name" | tr '[:upper:]' '[:lower:]')
- new_path="$dir_name/$new_base_name"
- if [ "$original_path" != "$new_path" ]; then
- if [ -e "$new_path" ] && [ ! "$(readlink -f "$original_path")" = "$(readlink -f "$new_path")" ]; then
- echo "::warning file=$original_path::Cannot rename '$original_path' to '$new_path' because it already exists. Skipping."
- else
- git mv "$original_path" "$new_path"
- fi
- fi
- done
- echo "JSON file renaming complete."
-
- - name: Commit Renamed Files
- run: |
- echo "Committing renamed files..."
- git add -A
- git commit -m "Rename JSON translation files to lowercase for consistency"
- echo "Renames committed."
-
- - name: Push Changes to Localization Branch
- run: |
- echo "Pushing combined changes to ${{ github.event.inputs.localization_branch_name }}..."
- git push origin ${{ github.event.inputs.localization_branch_name }}
-
- create-pr:
- needs: [ download-translations, rename-files ]
- runs-on: ubuntu-latest
- steps:
- - name: Checkout branch
- uses: actions/checkout@v4
- with:
- ref: ${{ github.event.inputs.localization_branch_name }}
-
- - name: Set up Git config
- run: |
- git config user.name "github-actions"
- git config user.email "github-actions@github.com"
-
- - name: Install GitHub CLI
- run: sudo apt-get install gh -y
-
- - name: Authenticate GitHub CLI
- run: echo "${{ secrets.GITHUB_TOKEN }}" | gh auth login --with-token
-
- - name: Create Pull Request
- run: |
- gh pr create \
- --title "Update translations from Crowdin" \
- --body "This PR includes:\n- New translations from Crowdin\n- Renamed translation files to lowercase" \
- --head ${{ github.event.inputs.localization_branch_name }} \
- --base ${{ github.event.inputs.pull_request_base_branch }} \
- --label "localization"
\ No newline at end of file
+ CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/crowdin-upload-workflow.yml b/.github/workflows/crowdin-upload-workflow.yml
index 5516194..fe9194b 100644
--- a/.github/workflows/crowdin-upload-workflow.yml
+++ b/.github/workflows/crowdin-upload-workflow.yml
@@ -2,7 +2,7 @@ name: Crowdin Upload Action
on:
push:
- paths: [ "src/main/resources/assets/sit-oth3r/lang/en_us.json"]
+ paths: [ "src/main/resources/assets/sit-oth3r/lang/en_US.json"]
branches: [ dev ]
workflow_dispatch:
diff --git a/README.md b/README.md
index 47fbea2..b851d3a 100644
--- a/README.md
+++ b/README.md
@@ -1,68 +1,46 @@
-
-
-[](https://github.com/Oth3r/Sit/releases) [](https://crowdin.com/project/oth3r-sit) [](https://www.oth3r.one/discord)
+# Sit!
+[](https://github.com/Oth3r/Sit/releases) [](https://crowdin.com/project/oth3r-sit) [](https://www.oth3r.one/discord)
[](https://modrinth.com/mod/sit!) [](https://www.curseforge.com/minecraft/mc-mods/Sit1)
-
-### **Sit!** is a vanilla+ mod that adds sitting in minecraft.
-* Sit on **stairs**, **slabs**, **carpets** by default, and sit on everything else by tweaking the config!
-* You can also customize **hand restrictions** to stop accidentally sitting down!
-* The mod also has full **Geyser** support! Enjoy sitting with everyone, whether they are on Bedrock or Java!
-* If Sit! clients join a Sit! server they can use **their own hand settings** to sit.
+**Sit!** is a minecraft mod that adds sitting in vanilla minecraft.
+Sit on **stairs**, **slabs**, **carpets** by default, and sit on everything else using the config!
+You can also customize hand restrictions to stop accidentally sitting down!
+The mod also has full Geyser support! Enjoy sitting with everyone, weather they are on Bedrock or Java!
### Where to install?
-**Sit!** works on the server, without the players needing to install the mod *(singleplayer included!)*.
-\
-[Fabric API](https://modrinth.com/mod/fabric-api) and [OtterLib](https://modrinth.com/mod/otterlib) is required to for the mod to load.
+**Sit!** works on the server (singleplayer included), also with support for clients that join in to use their own settings to sit.
-### Help localize Sit! on [Crowdin](https://crowdin.com/project/oth3r-sit)!
-Sit! is currently in English, Traditional Chinese, Italian, Brazilian Portuguese, and Turkish! Help expand this list via Crowdin so reach more people!
+## Help localize Sit! on [Crowdin](https://crowdin.com/project/oth3r-sit)!
+
## Check out my other Projects!
-
-
-
-
-
-
-
-
-
-
+[](https://modrinth.com/mod/caligo)
+[](https://modrinth.com/mod/directionhud)
+[](https://modrinth.com/plugin/directionhud-plugin)
# Features
-### 🤚 Hand Restrictions
+### Hand Restrictions
Don't want to accidentally sit down? Set custom restrictions for each hand in the config!
-\
-Use **player unique** hand restrictions when connecting to a `Sit!` server on a `Sit!` Client!
-
+* Per player hand restrictions when connecting to a `Sit!` server on a `Sit!` Client!
-### 🟩 Custom Blocks
-Want to sit on _**EVERY**_ block? With the config you can add more sitting options!
-\
-With the new config system, block tags and custom blockstates can be used to mass select blocks at ease.
+
-
+### Custom Blocks
+Want to sit on _**EVERY**_ block? With the config you can add more options to sit on! Custom block states are also supported.
-### ⌨️ Keybinds
-Don't want to sit with the **just** the hand? Use a keybind or type a command to sit instead!
+
-
+### Customizable Config
+Configure to your hearts desire with the in-game config with **[ModMenu](https://modrinth.com/mod/modmenu)** & **[YetAnotherConfigLib](https://modrinth.com/mod/yacl)**, or use the provided config file for servers!
-### 📃 Customizable Config
-Don't like the default settings? Go wild in the config for yourself or your players!
-
+
+
## Future Goals
- * NeoForge Port
- * Full config via [OtterLib](https://modrinth.com/mod/otterlib)
+ * Forge Port (probably NeoForge 1.21)
+ * Custom dismounting logic
+ * better config (coming soon!)
+ * keybindings (next update)
diff --git a/build.gradle b/build.gradle
index bc9db2d..23b4044 100644
--- a/build.gradle
+++ b/build.gradle
@@ -43,7 +43,6 @@ processResources {
min_minecraft_version : min_minecraft_version,
max_minecraft_version : max_minecraft_version,
otterlib_version : otterlib_version,
- otterlib_max_version : otterlib_max_version,
loader_version : loader_version
]
diff --git a/changelog.md b/changelog.md
index cb30a6d..f7e4244 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,11 +1,3 @@
-# v1.2.4.3
-* added a max OtterLib version as the beta will have breaking changes between major versions
-
-# v1.2.4.2
-* fixed language file not loading (reverted uppercase locales)
-* fixed block checking having a hardcoded player reach - now uses player reach (1.20.6+)
-* fixed block and item tag check logic for cases with only not(!) tags
-
# v1.2.4.1
* removed unused assets
* enabled file logging for easier debugging
diff --git a/crowdin.yml b/crowdin.yml
index bb81024..352acbc 100644
--- a/crowdin.yml
+++ b/crowdin.yml
@@ -6,7 +6,7 @@
files: [
{
- "source": "src/main/resources/assets/sit-oth3r/lang/en_us.json",
+ "source": "src/main/resources/assets/sit-oth3r/lang/en_US.json",
"translation": "src/main/resources/assets/sit-oth3r/lang/%locale_with_underscore%.json",
}
]
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 2c59928..140b7fa 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -13,7 +13,7 @@ yarn_mappings=1.21.5+build.1
loader_version=0.16.14
# Mod Properties
-mod_version=1.2.4.3+1.21.5
+mod_version=1.2.4.1+1.21.5
maven_group=one.oth3r
file_name=sit!
@@ -21,4 +21,3 @@ file_name=sit!
fabric_version=0.124.0+1.21.5
modmenu_version=14.0.0-rc.2
otterlib_version=0.1.2.1+1.21.5-fabric
-otterlib_max_version=0.2.0.0+1.21.5-fabric
diff --git a/src/main/java/one/oth3r/sit/SitClient.java b/src/main/java/one/oth3r/sit/SitClient.java
index a1796ec..c39fbba 100644
--- a/src/main/java/one/oth3r/sit/SitClient.java
+++ b/src/main/java/one/oth3r/sit/SitClient.java
@@ -7,9 +7,9 @@ import one.oth3r.otterlib.client.screen.ConfigScreen;
import one.oth3r.otterlib.client.screen.utl.CustomImage;
import one.oth3r.otterlib.client.screen.utl.SimpleButton;
import one.oth3r.sit.file.FileData;
-import one.oth3r.sit.utl.Chat;
import one.oth3r.sit.utl.Data;
import one.oth3r.sit.utl.Events;
+import one.oth3r.sit.utl.Utl;
import java.net.URI;
import java.util.List;
@@ -23,17 +23,17 @@ public class SitClient implements ClientModInitializer {
}
public static Screen getConfigScreen(Screen parent) {
- return new ConfigScreen(parent, Chat.lang("sit!.screen.config"),
+ return new ConfigScreen(parent, Utl.lang("sit!.screen.config"),
new CustomImage(Identifier.of(Data.MOD_ID, "textures/gui/banner.png"),128, 72),
List.of(
- SimpleButton.Templates.fileEditor(Chat.lang("config.server"), FileData.getServerConfig(), new CustomImage(Identifier.of(Data.MOD_ID, "server_button"),246,26)).build(),
- SimpleButton.Templates.fileEditor(Chat.lang("config.sitting"), FileData.getSittingConfig(), new CustomImage(Identifier.of(Data.MOD_ID, "sitting_button"), 246, 26)).build()
+ SimpleButton.Templates.fileEditor(Utl.lang("config.server"), FileData.getServerConfig(), new CustomImage(Identifier.of(Data.MOD_ID, "server_button"),246,26)).build(),
+ SimpleButton.Templates.fileEditor(Utl.lang("config.sitting"), FileData.getSittingConfig(), new CustomImage(Identifier.of(Data.MOD_ID, "sitting_button"), 246, 26)).build()
),
List.of(
- SimpleButton.Templates.warning(Chat.lang("sit!.gui.button.issues")).openLink("https://github.com/Oth3r/Sit/issues").build(),
- new SimpleButton.Builder(Chat.lang("sit!.gui.button.website")).openLink("https://modrinth.com/mod/sit!").build(),
- SimpleButton.Templates.done(Chat.lang("gui.done")).build(),
- SimpleButton.Templates.donate(Chat.lang("sit!.gui.button.donate")).openLink(URI.create("https://ko-fi.com/oth3r")).build()
+ SimpleButton.Templates.warning(Utl.lang("sit!.gui.button.issues")).openLink("https://github.com/Oth3r/Sit/issues").build(),
+ new SimpleButton.Builder(Utl.lang("sit!.gui.button.website")).openLink("https://modrinth.com/mod/sit!").build(),
+ SimpleButton.Templates.done(Utl.lang("gui.done")).build(),
+ SimpleButton.Templates.donate(Utl.lang("sit!.gui.button.donate")).openLink(URI.create("https://ko-fi.com/oth3r")).build()
));
}
}
diff --git a/src/main/java/one/oth3r/sit/command/SitCommand.java b/src/main/java/one/oth3r/sit/command/SitCommand.java
index ad928ed..7abd2f3 100644
--- a/src/main/java/one/oth3r/sit/command/SitCommand.java
+++ b/src/main/java/one/oth3r/sit/command/SitCommand.java
@@ -8,8 +8,8 @@ import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
+import net.minecraft.util.Formatting;
import net.minecraft.util.math.BlockPos;
-import one.oth3r.sit.utl.Chat;
import one.oth3r.sit.utl.Data;
import one.oth3r.sit.utl.Logic;
import one.oth3r.sit.utl.Utl;
@@ -50,7 +50,7 @@ public class SitCommand {
if (player == null) {
if (args[0].equalsIgnoreCase("reload")) {
Logic.reload();
- Data.LOGGER.info(Chat.lang("sit!.chat.reloaded").toString());
+ Data.LOGGER.info(Utl.lang("sit!.chat.reloaded").toString());
}
return 1;
}
@@ -76,7 +76,7 @@ public class SitCommand {
if (args[0].equalsIgnoreCase("reload")) {
Logic.reload();
- player.sendMessage(Chat.tag().append(Chat.lang("sit!.chat.reloaded").color(Color.GREEN)).b());
+ player.sendMessage(Utl.messageTag().append(Utl.lang("sit!.chat.reloaded").color(Color.GREEN)).b());
}
if (args[0].equalsIgnoreCase("purgeChairEntities")) Utl.Entity.purge(player,true);
diff --git a/src/main/java/one/oth3r/sit/file/CustomBlock.java b/src/main/java/one/oth3r/sit/file/CustomBlock.java
index 4940f70..0f17147 100644
--- a/src/main/java/one/oth3r/sit/file/CustomBlock.java
+++ b/src/main/java/one/oth3r/sit/file/CustomBlock.java
@@ -91,27 +91,19 @@ public class CustomBlock {
}
// a boolean to check if one of the blocks are in a filtered tag
- // & a switch for if there is only not(!) tags
- boolean tagCheck = false, hasPositiveTags = false;
+ boolean tagCheck = false;
+ // for all the entered tags
for (String tag : blockTags) {
// substring to remove # and if needed, !
- if (tag.startsWith("!")) {
- // if there is a match for the NOT(!) tag, return false
- Identifier id = Identifier.tryParse(tag.substring(2));
- if (id != null && blockState.isIn(TagKey.of(Registries.BLOCK.getKey(), id))) return false;
- } else {
- // flip the hasPositiveTags boolean
- hasPositiveTags = true;
- // if there is a match, return true
- Identifier id = Identifier.tryParse(tag.substring(1));
- if (id != null && blockState.isIn(TagKey.of(Registries.BLOCK.getKey(), id))) tagCheck = true;
- }
+ // if there is a math for the NOT(!) tag, return false
+ if (tag.startsWith("!") && blockState.isIn(TagKey.of(Registries.BLOCK.getKey(), Identifier.of(tag.substring(2))))) return false;
+ // if there is a match, return true
+ if (blockState.isIn(TagKey.of(Registries.BLOCK.getKey(), Identifier.tryParse(tag.substring(1))))) tagCheck = true;
}
- // if there were any required tags, return whether we matched one
- // if there were only not(!) tags, and we didn't violate any, return true
- return hasPositiveTags? tagCheck : true;
+ // not returning true in the loop because there might be a (!) not tag that the block might fall into, after the block was already in another tag
+ return tagCheck;
}
@Override
diff --git a/src/main/java/one/oth3r/sit/file/CustomItem.java b/src/main/java/one/oth3r/sit/file/CustomItem.java
index 4e4680d..325fe19 100644
--- a/src/main/java/one/oth3r/sit/file/CustomItem.java
+++ b/src/main/java/one/oth3r/sit/file/CustomItem.java
@@ -51,27 +51,22 @@ public class CustomItem {
}
// a boolean to check if one of the items are in a filtered tag
- // & a switch for if there is only not(!) tags
- boolean tagCheck = false, hasPositiveTags = false;
+ boolean tagCheck = false;
+ // check the custom item tags
for (String tag : itemTags) {
// substring to remove # and if needed, "!"
+ // if a NOT tag
if (tag.startsWith("!")) {
// if there is a math for the NOT(!) tag, return false
- Identifier id = Identifier.tryParse(tag.substring(2));
- if (id != null && itemStack.isIn(TagKey.of(Registries.ITEM.getKey(), id))) return false;
- } else {
- // flip the hasPositiveTags boolean
- hasPositiveTags = true;
- // else (normal tag), if there is a match, set tagCheck to true
- Identifier id = Identifier.tryParse(tag.substring(1));
- if (id != null && itemStack.isIn(TagKey.of(Registries.ITEM.getKey(), id))) tagCheck = true;
+ if (itemStack.isIn(TagKey.of(Registries.ITEM.getKey(), Identifier.of(tag.substring(2))))) return false;
}
+ // else (normal tag), if there is a match, set tagCheck to true
+ else if (itemStack.isIn(TagKey.of(Registries.ITEM.getKey(), Identifier.of(tag.substring(1))))) tagCheck = true;
}
- // if there were any required tags, return whether we matched one
- // if there were only not(!) tags, and we didn't violate any, return true
- return hasPositiveTags? tagCheck : true;
+ // not returning true in the loop because there might be a (!) not tag that the item might fall into, after the item was already in another tag
+ return tagCheck;
}
@Override
diff --git a/src/main/java/one/oth3r/sit/file/FileData.java b/src/main/java/one/oth3r/sit/file/FileData.java
index e64879f..4e95a66 100644
--- a/src/main/java/one/oth3r/sit/file/FileData.java
+++ b/src/main/java/one/oth3r/sit/file/FileData.java
@@ -1,15 +1,9 @@
package one.oth3r.sit.file;
import net.minecraft.server.network.ServerPlayerEntity;
-import one.oth3r.otterlib.file.LanguageReader;
-import one.oth3r.sit.Sit;
import one.oth3r.sit.utl.Data;
import one.oth3r.sit.utl.Utl;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -62,21 +56,11 @@ public class FileData {
return playerSettings.getOrDefault(player, sittingConfig);
}
- /// the language / text system for the mod
- private static final LanguageReader langReader = new LanguageReader(
- getLangPath(),Path.of(Data.CONFIG_DIR),"en_us","en_us");
-
- public static LanguageReader getLangReader() {
- return langReader;
- }
-
/**
* loads all config files to memory
*/
public static void loadFiles() {
getServerConfig().load();
- // load the language reader
- langReader.updateLanguage(getServerConfig().getLang());
getSittingConfig().load();
// if loading file and is on supported server on client, send the new settings over
@@ -93,20 +77,6 @@ public class FileData {
getServerConfig().save();
}
- private static Path getLangPath() {
- ClassLoader classLoader = Sit.class.getClassLoader();
- URL resource = classLoader.getResource("assets/sit-oth3r/lang/");
- if (resource == null) {
- throw new RuntimeException("Language file not found.");
- }
-
- try {
- return Paths.get(resource.toURI());
- } catch (URISyntaxException e) {
- throw new RuntimeException(e);
- }
- }
-
public static class Defaults {
public static final ArrayList SITTING_BLOCKS = new ArrayList<>(Arrays.asList(
new SittingBlock(new ArrayList<>(),new ArrayList<>(Arrays.asList("#minecraft:campfires")), new ArrayList<>(Arrays.asList("lit=false")),.437),
diff --git a/src/main/java/one/oth3r/sit/file/LangReader.java b/src/main/java/one/oth3r/sit/file/LangReader.java
new file mode 100644
index 0000000..d9fdaff
--- /dev/null
+++ b/src/main/java/one/oth3r/sit/file/LangReader.java
@@ -0,0 +1,124 @@
+package one.oth3r.sit.file;
+
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import net.minecraft.text.MutableText;
+import net.minecraft.text.Text;
+import one.oth3r.otterlib.chat.CTxT;
+import one.oth3r.sit.Sit;
+import one.oth3r.sit.utl.Data;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.lang.reflect.Type;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LangReader {
+ private static final Map defaultLangMap = new HashMap<>();
+ private static final Map languageMap = new HashMap<>();
+
+ private final String translationKey;
+
+ private final Object[] placeholders;
+
+ public LangReader(String translationKey, Object... placeholders) {
+ this.translationKey = translationKey;
+ this.placeholders = placeholders;
+ }
+
+ public CTxT getTxT() {
+ String translated = getLanguageValue(translationKey);
+ if (placeholders != null && placeholders.length > 0) {
+ //removed all double \\ and replaces with \
+ translated = translated.replaceAll("\\\\\\\\", "\\\\");
+ String regex = "%\\d*\\$?[dfs]";
+ Matcher anyMatch = Pattern.compile(regex).matcher(translated);
+ Matcher endMatch = Pattern.compile(regex+"$").matcher(translated);
+
+ // Arraylist with all the %(#$)[dfs]
+ ArrayList matches = new ArrayList<>();
+ while (anyMatch.find()) {
+ String match = anyMatch.group();
+ matches.add(match);
+ }
+ //SPLITS the text at each regex and remove the regex
+ String[] parts = translated.split(regex);
+ //if the last element of the array ends with regex, remove it and add an empty string to the end of the array
+ if (endMatch.find()) {
+ String[] newParts = Arrays.copyOf(parts, parts.length + 1);
+ newParts[parts.length] = "";
+ parts = newParts;
+ }
+ //if there are placeholders specified, and the split is more than 1, it will replace %(dfs) with the placeholder objects
+ if (parts.length > 1) {
+ CTxT txt = new CTxT("");
+ int i = 0;
+ for (String match : matches) {
+ int get = i;
+ //if the match is numbered, change GET to the number it wants
+ if (match.contains("$")) {
+ match = match.substring(1,match.indexOf('$'));
+ get = Integer.parseInt(match)-1;
+ }
+ if (parts.length != i) txt.append(parts[i]);
+ //convert the obj into txt
+ txt.append(getTxTFromObj(placeholders[get]));
+ i++;
+ }
+ if (parts.length != i) txt.append(parts[i]);
+ return new CTxT(txt);
+ }
+ }
+ return new CTxT(translated);
+ }
+
+ private CTxT getTxTFromObj(Object obj) {
+ if (obj instanceof CTxT) return (((CTxT) obj));
+ else if (obj instanceof Text) return new CTxT((MutableText) obj);
+ else return new CTxT(String.valueOf(obj));
+ }
+
+ public static LangReader of(String translationKey, Object... placeholders) {
+ return new LangReader(translationKey, placeholders);
+ }
+
+ public static void loadLanguageFile() {
+ Type tToken = new TypeToken