diff --git a/README.md b/README.md index 9596df1..2be2818 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ + +![Version](https://img.shields.io/github/v/tag/KelvenCassamo/java-language-system?label=Version&logo=github) +![License](https://img.shields.io/github/license/KelvenCassamo/java-language-system) - # Java Language System (JLS) + The **Java Language System (JLS)** is a Java library designed to facilitate the internationalization (i18n) of applications, enabling dynamic language management and text translation, **Swing** components, and **Widgets** on **Android**, based on XML files. With JLS, you can: @@ -13,24 +16,28 @@ With JLS, you can: - Use dynamic placeholders (`$1`, `$2`, etc.) to create personalized messages. - Easily integrate translations into both desktop and mobile applications. + +### 🎉 **Modular Language import is now available starting from version 1.0.3!** 🎉 +[Click here](#211-importing-individual-language-files-available-from-version-103) to learn more about the Modular Language Import feature! + ### **1. Installation** The **Java Language System (JLS)** can be easily integrated into your Java project, either by downloading the JAR file directly or by cloning the repository and compiling the source code. -#### **1.1 Downloading the JAR** +#### **1.1. Downloading the JAR** You can find the latest version of JLS in JAR format in the **Releases** section on GitHub. To do this, visit the releases page and download the JAR file: - **Find the latest version of the JAR here**: [JLS Releases Page](https://github.com/KelvenCassamo/java-language-system/releases) - Or, you can download the latest compiled JAR directly from the link below: - [📦 Download the latest compiled JAR](https://github.com/KelvenCassamo/java-language-system/releases/download/v1.0.1/java-language-system-1.0.1.jar) + [📦 Download the latest compiled JAR](https://github.com/KelvenCassamo/java-language-system/releases/download/v1.0.3/java-language-system-1.0.3.jar) ### 2. Main Features The **Java Language System (JLS)** offers various features to facilitate the internationalization and translation of applications. -#### **2.1 Creating the translations** +#### **2.1. Creating the translations** To configure the language system, start by creating translations in an XML file. Below is an example of a `languages.xml` file with translations in, for example **English** and **Portuguese**. ````xml @@ -53,22 +60,79 @@ To configure the language system, start by creating translations in an XML file. + + ```` - **Language keys** (e.g., `hello_world`, `presentation`) are identifiers for the text. - **Placeholders** (e.g., `$1`) can dynamically insert values into the text. + +#### **2.1.1. Importing Individual Language Files** (Available from version 1.0.3) + +Starting from version **1.0.3**, the **Java Language System (JLS)** supports importing language definitions from individual files. This feature allows you to modularize your translations by splitting each language into a separate file. + +#### Example: Importing Individual Language Files + +To use this feature, you can reference external XML files for each language using the `` tag. Here’s an example: + +```xml + + + + + + +``` +Each imported file (`languages/english.xml`, `languages/portuguese.xml`, etc.) should follow the standard format for defining translations. Below is an example of how a language file should look: + +Example: `languages/english.xml` +```xml + + + Hello, World! + + + + My name is $1! + + + + + Welcome to our platform! + We are excited to have you here, $1. + If you have any questions, feel free to reach out to our support team at $2. + Let's make this journey a great success! + + + + + Read + Read + Read + Reading + + + +``` +#### Compatibility +This feature is available starting from version **1.0.3**. Ensure you are using this version or newer to take advantage of this functionality. + + #### **2.2. Structure of a `languages.xml` File** The `languages.xml` file contains translations for various languages and their respective text values. Below is a detailed table explaining each element and attribute in the file. - +| | **Element/Attribute** | **Description** | **Attributes** | **Example** | |------------------------|----------------------------------------------------------------------------------------------------|--------------------------------------|------------------------------------------------| | `` | Root element that contains all language definitions. | None | ` ... ` | +| `` | References an external XML file that contains the definitions for a specific language. | `file` (path to the language file) | `` | | `` | Represents a specific language and contains its translations. | `value` (language code) | ` ... ` | | `` | Defines a single translation entry, identified by a unique key. | `value` (translation key) | ` ... ` | | `` | Specifies the actual translation text for a given key. | None | `Hello, World!` | +| `` | Specifies the actual translation text for a given key. Can optionally include tense information. Available from version 1.0.3. | `tense` *(optional)* (e.g., "infinitive", "past", "participle", "gerund") | `Read` +> **Note:** The `tense` attribute is available starting from **version 1.0.3**. #### **2.3. Attributes Details** @@ -78,6 +142,13 @@ The `languages.xml` file contains translations for various languages and their r #### `` Attributes - **`value`**: The unique key for the translation (e.g., "hello_world", "presentation"). This key is used to reference the translation programmatically. +#### `` Attributes +- **`tense`** *(optional, available from version 1.0.3)*: Specifies the grammatical tense of the translation. This attribute is used for verbs to define their tense. Supported values include: + - `infinitive`: Represents the base form of the verb (e.g., "to read" or "read"). + - `past`: Represents the past tense of the verb (e.g., "read" in English, "leu" in Portuguese). + - `participle`: Represents the past participle of the verb (e.g., "read", "lido"). + - `gerund`: Represents the gerund form of the verb (e.g., "reading", "lendo"). + @@ -168,25 +239,77 @@ As an alternative, you can use the `LanguageSystem.format(text_content, ...place String translatedText = LanguageSystem.format(LanguageSystem.get("presentation", "My name is $1"), "Cassamo"); ```` -#### **2.8. Support for Multiple Languages** +#### **2.8. Word Translation with Specific Forms** -JLS allows the inclusion of multiple languages in a single XML file, and switching between them can be done without altering the application’s source code. This makes it easy to add new languages and maintain translations in multilingual applications. +In addition to translating full sentences or phrases, JLS also supports the translation of specific words, taking into account different grammatical forms (such as tense). This is useful when you need to translate individual words like verbs in different tenses (e.g., "read", "reading", "read" in the past tense). -#### **Example of translation in multiple languages in XML:** +You can use the `getWord` method to get the translation of a word, optionally specifying its form (such as "infinitive", "past", "participle", or "gerund"). + +**Example of word translation with tense:** + +```java +String translatedWord = LanguageSystem.getWord("read", "participle"); +``` +In the example above, the method returns the translation for the word **"read"** in the **participle** form. This allows you to handle specific translations for different verb forms. + +Example of translation with tense in `languages.xml`: ````xml - - Hello, World! + + + Read + Read + Read + Reading +```` + +In this case, the word **"read"** has different translations depending on the tense: **infinitive**, **past**, **participle**, and **gerund**. The `getWord` method allows you to select the appropriate translation based on the tense you need. +#### Note on Usage: +- The `LanguageSystem.getWord` method provides a way to fetch the translation for specific words, considering different grammatical forms, which is especially useful for verbs. +- This method is available starting from **version 1.0.3** and supports the `tense` attribute for more accurate translations. + +#### **2.9. Support for Multiple Languages** + +JLS allows the inclusion of multiple languages in a single XML file, and switching between them can be done without altering the application’s source code. This makes it easy to add new languages and maintain translations in multilingual applications. + +Additionally, from version **1.0.3**, you can now take advantage of **importing separate language files** into your `languages.xml` file, which allows for a more modular approach. Instead of maintaining all translations in one file, you can organize them into smaller, language-specific files and import them into the main configuration file. + +This flexibility reduces the risk of a single, large file becoming overwhelming as your application grows in terms of languages and translations. + +#### **Example of translation in multiple languages in XML:** +````xml + + + + Hello, World! + + + + + + Olá, mundo! + + + - - - Olá, mundo! - - ```` +#### New in version 1.0.3: Modular Language Import +````xml + + + + + +```` + +### **Notes on Version 1.0.3 Updates:** + +1. **Modular Language Support:** Instead of placing all language translations in one file, you can now import separate language files. This modular approach allows for better scalability and easier management of language files. +2. **Improved XML Structure:** With the new `import-language` element, you can link to external language files, making it simpler to manage and update translations, especially in large projects. + ### 3. Practical Example Let's see a practical example of how to integrate the **Java Language System (JLS)** into a Java application **(Normal, Desktop and Android)**, for both configuring and switching languages, and for translating texts and displaying dynamic information with placeholders. @@ -203,6 +326,13 @@ First, let's configure the language system by loading the translations from an X My name is $1! + + + Read + Read + Read + Reading + @@ -212,8 +342,16 @@ First, let's configure the language system by loading the translations from an X O meu nome é $1! + + + Ler + Leu + Lido + Lendo + + ```` @@ -238,9 +376,16 @@ public class Example { // Displaying the translation for the "presentation" key with placeholder System.out.println(LanguageSystem.getf("presentation", "Cassamo")); // Output: My name is Cassamo! + + // Available starting from version 1.0.3: Displaying the translation for the "read" key with tense information + System.out.println(LanguageSystem.getWord("read", "participle")); // Output: Read (participle form) + + // If the tense is not specified, the default form (usually the infinitive) will be returned + System.out.println(LanguageSystem.getWord("read", null)); // Output: Read (infinitive form) } } + ```` #### **3.4. Using Placeholders** @@ -469,7 +614,11 @@ List of some public methods available in the `LanguageSystem` class. You will fi | `String get(String key)` | Retrieves the translated value for a specific key. | `key`: Translation key. | Translated string or `null`. | | `String get(String key, String default_value)` | Retrieves the translation for a key, or a default value if the key is not found. | `key`: Translation key.
`default_value`: Fallback value. | Translated string or fallback. | | `String getf(String key, String... values)` | Retrieves and formats a translation string, replacing placeholders with values. | `key`: Translation key.
`values`: Values to replace placeholders. | Formatted translated string. | - +| `String getWord(String key, String tense)` | Retrieves the translation of a word with a specific tense (e.g., infinitive, past, participle, gerund). | `key`: The translation key for the word.
`tense`: Optional. Tense to retrieve (e.g., "infinitive", "past", "participle", "gerund"). | The translated word, or null if not found. | +| +### **Note:** +- The method `getWord` is **available starting from version 1.0.3** and allows retrieving translations with a specific tense. If no tense is specified, the default (typically the infinitive) will be returned. +- This method is useful for handling words with multiple forms depending on the tense (e.g., verb conjugations). --- ### **5.4. String Formatting** @@ -485,7 +634,7 @@ List of some public methods available in the `LanguageSystem` class. You will fi | **Method** | **Description** | **Parameters** | **Returns** | |---------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------|--------------------------------| -| `void setDebugMode(boolean _debug)` | Enables or disables debug mode. | `_debug`: `true` to enable debug mode, `false` to disable it. | N/A | +| `void setDebugMode(boolean _debug)` | Enables or disables debug mode. | `_debug`: `true` to enable debug mode, `false` to disable it. | `void` | | `boolean isDebugMode()` | Checks if debug mode is currently enabled. | None | `true` if debug mode is on. | @@ -505,7 +654,7 @@ The **XMLBuilder** is a class that simplifies the creation, manipulation, and st - **Automatic file creation**: If the XML file does not exist, it will be created. - **Standardized XML format**: Ensures compatibility and readability of the generated translation file. - +**Important Note**: As of version 1.0.3, XMLBuilder does **not fully support module-based imports**. The current implementation generates a single file instead of handling separate modules. Despite this limitation, it is still efficient for managing translations, especially for smaller applications or cases where module-based imports are not required. #### **6.2. Methods** @@ -651,6 +800,5 @@ If you encounter issues using the **Java Language System (JLS)** or need assista - If you need more direct support, send an email to my address: `kelvencassamo9@gmail.com`. -**Follow me on :** -- [Instagram](https://instagram.com/kelven.cassamo) + diff --git a/languages.xml b/languages.xml index 2e600d8..7f4c7e2 100644 --- a/languages.xml +++ b/languages.xml @@ -1,71 +1,7 @@ - - - Hello, World! - - - My name is $1! - + + + - - - Welcome to our platform! - We are excited to have you here, $1. - If you have any questions, feel free to reach out to our support team at $2. - Let's make this journey a great success! - - - - - - Read - - - Read - - - Read - - - Reading - - - - - - - - - - Ler - - - Leu - - - Lido - - - Lendo - - - - - Olá, mundo! - - - O meu nome é $1! - - - - - Bem-vindo à nossa plataforma! - Estamos empolgados em tê-lo aqui, $1. - Se tiver alguma dúvida, sinta-se à vontade para entrar em contato com nossa equipe - de suporte em $2. - Vamos fazer desta jornada um grande sucesso! - - - diff --git a/languages/english.xml b/languages/english.xml new file mode 100644 index 0000000..000864d --- /dev/null +++ b/languages/english.xml @@ -0,0 +1,34 @@ + + + Hello, World! + + + + My name is $1! + + + + + Welcome to our platform! + We are excited to have you here, $1. + If you have any questions, feel free to reach out to our support team at $2. + Let's make this journey a great success! + + + + + + Read + + + Read + + + Read + + + Reading + + + + \ No newline at end of file diff --git a/languages/portuguese.xml b/languages/portuguese.xml new file mode 100644 index 0000000..03e4348 --- /dev/null +++ b/languages/portuguese.xml @@ -0,0 +1,34 @@ + + + + + Ler + + + Leu + + + Lido + + + Lendo + + + + + Olá, mundo! + + + O meu nome é $1! + + + + + Bem-vindo à nossa plataforma! + Estamos empolgados em tê-lo aqui, $1. + Se tiver alguma dúvida, sinta-se à vontade para entrar em contato com nossa equipe + de suporte em $2. + Vamos fazer desta jornada um grande sucesso! + + + \ No newline at end of file diff --git a/languages/spanish.xml b/languages/spanish.xml new file mode 100644 index 0000000..cfb785c --- /dev/null +++ b/languages/spanish.xml @@ -0,0 +1,36 @@ + + + + + Leer + + + Leyó + + + Leído + + + Leyendo + + + + + ¡Hola, mundo! + + + + ¡Mi nombre es $1! + + + + + ¡Bienvenido a nuestra plataforma! + Estamos emocionados de tenerte aquí, $1. + Si tienes alguna pregunta, no dudes en contactar a nuestro equipo + de soporte en $2. + ¡Hagamos de este viaje un gran éxito! + + + + diff --git a/src/mz/cassamo/jls/LanguageHandler.java b/src/mz/cassamo/jls/LanguageHandler.java index 742c6c5..26609f5 100644 --- a/src/mz/cassamo/jls/LanguageHandler.java +++ b/src/mz/cassamo/jls/LanguageHandler.java @@ -1,5 +1,8 @@ package mz.cassamo.jls; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.xml.sax.Attributes; @@ -57,6 +60,8 @@ class LanguageHandler extends DefaultHandler { private boolean isValueElement = false; private String tenseKey = null; + + /** * Stores translations for all languages as nested maps. */ @@ -66,9 +71,25 @@ class LanguageHandler extends DefaultHandler { */ private StringBuilder currentValueBuilder; + private String currentFilePath; + @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { - if (qName.equalsIgnoreCase("language")) { + if (qName.equalsIgnoreCase("import-language")) { + + // Processa a tag + String importFilePath = attributes.getValue("file"); + if (importFilePath != null) { + // Chama o método recursivamente para carregar e processar o arquivo de importação + try { + initFromFile(importFilePath); + } catch (IOException e) { + if(LanguageSystem.isDebugMode()){ + System.err.println("Error while importing file: " + importFilePath); + } + } + } + } else if (qName.equalsIgnoreCase("language")) { currentLanguage = attributes.getValue("value"); translations.putIfAbsent(currentLanguage, new HashMap<>()); tenseKey = null; @@ -177,4 +198,30 @@ public Map> getLanguages() { public boolean existsLanguage(String language) { return translations.containsKey(language); } + + + /** + * Inicia o parsing de um arquivo XML, incluindo seus arquivos importados. + * + * @param xmlFilePath Caminho para o arquivo XML a ser processado + * @throws IOException Se houver erro ao processar o arquivo + */ + public void initFromFile(String xmlFilePath) throws IOException { + currentFilePath = xmlFilePath; // Salva o caminho do arquivo atual + + File file = new File(xmlFilePath); + if (!file.exists()) { + throw new IOException("File not found: " + xmlFilePath); + } + + try (FileInputStream inputStream = new FileInputStream(file)) { + // Usando SAXParser para processar o XML + javax.xml.parsers.SAXParserFactory factory = javax.xml.parsers.SAXParserFactory.newInstance(); + javax.xml.parsers.SAXParser saxParser = factory.newSAXParser(); + saxParser.parse(inputStream, this); + } catch (Exception e) { + throw new IOException("Error while parsing file: " + xmlFilePath, e); + } + } } +