diff --git a/demo-app/LOCALISATION.md b/demo-app/LOCALISATION.md
new file mode 100644
index 0000000..9836451
--- /dev/null
+++ b/demo-app/LOCALISATION.md
@@ -0,0 +1,117 @@
+# Guide de Localisation / Localization Guide
+
+## Français
+
+### Fonctionnalité ajoutée
+
+L'application Android Remote Notify Demo App supporte maintenant le français ! L'application détecte automatiquement la langue du système et affiche l'interface dans la langue appropriée.
+
+### Langues supportées
+
+- **Anglais** (par défaut) - `values/strings.xml`
+- **Français** - `values-fr/strings.xml`
+
+### Comment tester
+
+1. **Pour tester en français :**
+ - Allez dans les Paramètres de votre appareil Android
+ - Sélectionnez "Langues et entrée" ou "Language & input"
+ - Changez la langue principale vers "Français"
+ - Redémarrez l'application
+
+2. **Pour tester en anglais :**
+ - Remettez la langue de l'appareil en "English"
+ - Redémarrez l'application
+
+### Éléments traduits
+
+- Titre de l'application
+- Interface principale (enregistrement du token)
+- Écran des paramètres
+- Messages d'état et d'erreur
+- Messages toast (notifications temporaires)
+- Menu et navigation
+
+### Ajouter d'autres langues
+
+Pour ajouter une nouvelle langue (ex: espagnol) :
+
+1. Créez un nouveau dossier : `app/src/main/res/values-es/`
+2. Copiez le fichier `strings.xml` depuis `values/`
+3. Traduisez toutes les chaînes de caractères
+4. Testez avec un appareil configuré en espagnol
+
+---
+
+## English
+
+### Added Feature
+
+The Remote Notify Demo App Android application now supports French! The app automatically detects the system language and displays the interface in the appropriate language.
+
+### Supported Languages
+
+- **English** (default) - `values/strings.xml`
+- **French** - `values-fr/strings.xml`
+
+### How to Test
+
+1. **To test in French:**
+ - Go to your Android device Settings
+ - Select "Languages and input"
+ - Change the primary language to "Français" (French)
+ - Restart the application
+
+2. **To test in English:**
+ - Change device language back to "English"
+ - Restart the application
+
+### Translated Elements
+
+- Application title
+- Main interface (token registration)
+- Settings screen
+- Status and error messages
+- Toast messages (temporary notifications)
+- Menu and navigation
+
+### Adding Other Languages
+
+To add a new language (e.g., Spanish):
+
+1. Create a new folder: `app/src/main/res/values-es/`
+2. Copy the `strings.xml` file from `values/`
+3. Translate all string values
+4. Test with a device configured in Spanish
+
+---
+
+## Technical Implementation
+
+### Structure
+
+```
+app/src/main/res/
+├── values/
+│ └── strings.xml # English (default)
+├── values-fr/
+│ └── strings.xml # French
+└── layout/
+ ├── activity_main.xml # Uses @string/ references
+ └── activity_settings.xml # Uses @string/ references
+```
+
+### Code Changes
+
+- All hardcoded strings moved to resource files
+- Kotlin code updated to use `getString(R.string.resource_name)`
+- Layout files updated to use `@string/resource_name`
+- Proper parameter formatting with `%1$s`, `%1$d` for dynamic content
+
+### Best Practices
+
+- Always use string resources instead of hardcoded text
+- Use proper parameter formatting for dynamic strings
+- Test all languages on actual devices
+- Keep string keys consistent and descriptive
+- Add comments to organize string resources
diff --git a/demo-app/app/src/main/java/org/nella/rn/demo/MainActivity.kt b/demo-app/app/src/main/java/org/nella/rn/demo/MainActivity.kt
index 3978a57..8a24127 100644
--- a/demo-app/app/src/main/java/org/nella/rn/demo/MainActivity.kt
+++ b/demo-app/app/src/main/java/org/nella/rn/demo/MainActivity.kt
@@ -76,17 +76,17 @@ class MainActivity : AppCompatActivity() {
private fun updateStatusWithBackendUrl() {
val backendUrl = SettingsActivity.getBackendUrl(this)
- updateStatus("Ready to register with backend: $backendUrl")
+ updateStatus(getString(R.string.status_ready_to_register, backendUrl))
}
private fun registerDeviceToken() {
- updateStatus("Getting notification token...")
+ updateStatus(getString(R.string.status_getting_token))
registerButton.isEnabled = false
FirebaseMessaging.getInstance().token.addOnCompleteListener { task ->
if (!task.isSuccessful) {
Log.w(TAG, "Fetching Firebase registration token failed", task.exception)
- updateStatus("Failed to get notification token: ${task.exception?.message}")
+ updateStatus(getString(R.string.status_failed_get_token, task.exception?.message ?: ""))
registerButton.isEnabled = true
return@addOnCompleteListener
}
@@ -101,14 +101,14 @@ class MainActivity : AppCompatActivity() {
}
private fun sendTokenToServer(token: String) {
- updateStatus("Encrypting and sending token to server...")
+ updateStatus(getString(R.string.status_encrypting_token))
// Encrypt the token before sending
val encryptedToken = try {
encryptToken(token)
} catch (e: Exception) {
Log.e(TAG, "Failed to encrypt token", e)
- updateStatus("Failed to encrypt token: ${e.message}")
+ updateStatus(getString(R.string.status_failed_encrypt, e.message ?: ""))
registerButton.isEnabled = true
return
}
@@ -131,7 +131,7 @@ class MainActivity : AppCompatActivity() {
override fun onFailure(call: Call, e: IOException) {
Log.e(TAG, "Failed to send token to server", e)
runOnUiThread {
- updateStatus("Failed to register token: ${e.message}")
+ updateStatus(getString(R.string.status_failed_register, e.message ?: ""))
registerButton.isEnabled = true
}
}
@@ -142,9 +142,9 @@ class MainActivity : AppCompatActivity() {
runOnUiThread {
if (response.isSuccessful) {
- updateStatus("Encrypted token registered successfully!")
+ updateStatus(getString(R.string.status_success))
} else {
- updateStatus("Server error: ${response.code}\n$responseBody")
+ updateStatus(getString(R.string.status_server_error, response.code, responseBody))
}
registerButton.isEnabled = true
}
diff --git a/demo-app/app/src/main/java/org/nella/rn/demo/SettingsActivity.kt b/demo-app/app/src/main/java/org/nella/rn/demo/SettingsActivity.kt
index 63f8244..84a56e4 100644
--- a/demo-app/app/src/main/java/org/nella/rn/demo/SettingsActivity.kt
+++ b/demo-app/app/src/main/java/org/nella/rn/demo/SettingsActivity.kt
@@ -58,19 +58,19 @@ class SettingsActivity : AppCompatActivity() {
// Enable back button
supportActionBar?.setDisplayHomeAsUpEnabled(true)
- supportActionBar?.title = "Settings"
+ supportActionBar?.title = getString(R.string.settings_title)
}
private fun saveUrl() {
val url = urlEditText.text.toString().trim()
if (url.isEmpty()) {
- Toast.makeText(this, "URL cannot be empty", Toast.LENGTH_SHORT).show()
+ Toast.makeText(this, getString(R.string.toast_url_empty), Toast.LENGTH_SHORT).show()
return
}
if (!isValidUrl(url)) {
- Toast.makeText(this, "Please enter a valid URL (e.g., https://example.com)", Toast.LENGTH_LONG).show()
+ Toast.makeText(this, getString(R.string.toast_url_invalid), Toast.LENGTH_LONG).show()
return
}
@@ -78,7 +78,7 @@ class SettingsActivity : AppCompatActivity() {
val cleanUrl = url.trimEnd('/')
setBackendUrl(this, cleanUrl)
- Toast.makeText(this, "Backend URL saved successfully", Toast.LENGTH_SHORT).show()
+ Toast.makeText(this, getString(R.string.toast_url_saved), Toast.LENGTH_SHORT).show()
// Return to main activity
finish()
@@ -86,7 +86,7 @@ class SettingsActivity : AppCompatActivity() {
private fun resetToDefault() {
urlEditText.setText(DEFAULT_BACKEND_URL)
- Toast.makeText(this, "Reset to default URL", Toast.LENGTH_SHORT).show()
+ Toast.makeText(this, getString(R.string.toast_reset_default), Toast.LENGTH_SHORT).show()
}
private fun isValidUrl(url: String): Boolean {
diff --git a/demo-app/app/src/main/res/layout/activity_main.xml b/demo-app/app/src/main/res/layout/activity_main.xml
index 64bde54..cf310d1 100644
--- a/demo-app/app/src/main/res/layout/activity_main.xml
+++ b/demo-app/app/src/main/res/layout/activity_main.xml
@@ -10,7 +10,7 @@
android:id="@+id/titleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="Token Registration"
+ android:text="@string/title_token_registration"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/registerButton"
@@ -24,7 +24,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
- android:text="Register Device Token"
+ android:text="@string/button_register_device_token"
android:textSize="16sp"
app:layout_constraintBottom_toTopOf="@+id/statusText"
app:layout_constraintEnd_toEndOf="parent"
@@ -38,7 +38,7 @@
android:layout_marginTop="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
- android:text="Press the button to register your device token"
+ android:text="@string/status_press_button"
android:textAlignment="center"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
diff --git a/demo-app/app/src/main/res/layout/activity_settings.xml b/demo-app/app/src/main/res/layout/activity_settings.xml
index f1578d8..a379dfd 100644
--- a/demo-app/app/src/main/res/layout/activity_settings.xml
+++ b/demo-app/app/src/main/res/layout/activity_settings.xml
@@ -8,7 +8,7 @@
@@ -16,7 +16,7 @@
@@ -24,7 +24,7 @@
android:id="@+id/urlEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:hint="https://demo.rn.nella.org"
+ android:hint="@string/settings_url_hint"
android:inputType="textUri"
android:layout_marginBottom="16dp"
android:padding="12dp"
@@ -33,7 +33,7 @@
@@ -49,7 +49,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="Reset to Default"
+ android:text="@string/button_reset_default"
android:layout_marginEnd="8dp"
style="?android:attr/borderlessButtonStyle" />
@@ -58,7 +58,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
- android:text="Save"
+ android:text="@string/button_save"
android:layout_marginStart="8dp" />
@@ -66,7 +66,7 @@
diff --git a/demo-app/app/src/main/res/values-fr/strings.xml b/demo-app/app/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000..36761ae
--- /dev/null
+++ b/demo-app/app/src/main/res/values-fr/strings.xml
@@ -0,0 +1,37 @@
+
+
+
+ App de Démo Remote Notify
+
+
+ Enregistrement du Token
+ Enregistrer le Token d’Appareil
+ Prêt à s’enregistrer avec le backend : %1$s
+ Appuyez sur le bouton pour enregistrer votre token d’appareil
+ Récupération du token de notification...
+ Échec de la récupération du token de notification : %1$s
+ Chiffrement et envoi du token au serveur...
+ Échec du chiffrement du token : %1$s
+ Échec de l’enregistrement du token : %1$s
+ Token chiffré enregistré avec succès !
+ Erreur serveur : %1$d\n%2$s
+
+
+ Paramètres
+ Configuration du Serveur Backend
+ Entrez l’URL de votre serveur backend d’application :
+ https://demo.rn.nella.org
+ Exemples :\n• https://demo.rn.nella.org\n• https://votre-domaine.com\n• https://10.0.2.2:8443 (émulateur Android)
+ Réinitialiser par Défaut
+ Enregistrer
+ \n🔒 Note de Sécurité :\nToute communication utilise des tokens de notification chiffrés. L’URL du backend devrait utiliser HTTPS pour la sécurité.
+
+
+ L’URL ne peut pas être vide
+ Veuillez entrer une URL valide (ex: https://example.com)
+ URL du backend enregistrée avec succès
+ Réinitialisation à l’URL par défaut
+
+
+ Paramètres
+
\ No newline at end of file
diff --git a/demo-app/app/src/main/res/values/strings.xml b/demo-app/app/src/main/res/values/strings.xml
index a72acaa..9425e84 100644
--- a/demo-app/app/src/main/res/values/strings.xml
+++ b/demo-app/app/src/main/res/values/strings.xml
@@ -1,3 +1,36 @@
+
Remote Notify Demo App
+
+
+ Token Registration
+ Register Device Token
+ Ready to register with backend: %1$s
+ Press the button to register your device token
+ Getting notification token...
+ Failed to get notification token: %1$s
+ Encrypting and sending token to server...
+ Failed to encrypt token: %1$s
+ Failed to register token: %1$s
+ Encrypted token registered successfully!
+ Server error: %1$d\n%2$s
+
+
+ Settings
+ Backend Server Configuration
+ Enter the URL of your app backend server:
+ https://demo.rn.nella.org
+ Examples:\n• https://demo.rn.nella.org\n• https://your-domain.com\n• https://10.0.2.2:8443 (Android emulator)
+ Reset to Default
+ Save
+ \n🔒 Security Note:\nAll communication uses encrypted notification tokens. The backend URL should use HTTPS for security.
+
+
+ URL cannot be empty
+ Please enter a valid URL (e.g., https://example.com)
+ Backend URL saved successfully
+ Reset to default URL
+
+
+ Settings