From 823409207a5a27488cc7f227814c321d13abe145 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Tue, 10 Feb 2026 15:01:24 +0700 Subject: [PATCH 01/15] feat: contract-driven dynamic database download from API --- app/build.gradle.kts | 7 ++ app/src/main/AndroidManifest.xml | 2 + .../java/be/scri/data/model/DataResponse.kt | 31 ++++++ .../be/scri/data/model/DataVersionResponse.kt | 15 +++ .../java/be/scri/data/remote/ApiService.kt | 23 ++++ .../be/scri/data/remote/DynamicDbHelper.kt | 70 ++++++++++++ .../be/scri/data/remote/RetrofitClient.kt | 24 +++++ .../screens/download/DataDownloadViewModel.kt | 101 +++++++++++++++--- 8 files changed, 257 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/be/scri/data/model/DataResponse.kt create mode 100644 app/src/main/java/be/scri/data/model/DataVersionResponse.kt create mode 100644 app/src/main/java/be/scri/data/remote/ApiService.kt create mode 100644 app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt create mode 100644 app/src/main/java/be/scri/data/remote/RetrofitClient.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b3e548f4..badfeeca 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -233,6 +233,13 @@ dependencies { // ========================== implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.21") + // ========================== + // API + // ========================== + implementation("com.squareup.retrofit2:retrofit:2.11.0") + implementation("com.squareup.retrofit2:converter-gson:2.11.0") + implementation("com.squareup.okhttp3:logging-interceptor:4.12.0") + // ========================== // Layout and UI // ========================== diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b70ae9e9..da738c60 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -9,6 +9,8 @@ + + >>, +) + +/** + * Represents the contract details for the data response, + * including version, update timestamp, and field definitions. + */ +data class Contract( + @SerializedName("version") + val version: String, + @SerializedName("updated_at") + val updatedAt: String, + @SerializedName("fields") + val fields: Map>, +) diff --git a/app/src/main/java/be/scri/data/model/DataVersionResponse.kt b/app/src/main/java/be/scri/data/model/DataVersionResponse.kt new file mode 100644 index 00000000..d7b25243 --- /dev/null +++ b/app/src/main/java/be/scri/data/model/DataVersionResponse.kt @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.data.model + +import com.google.gson.annotations.SerializedName + +/** + * Represents the data version response for a specific language. + */ +data class DataVersionResponse( + @SerializedName("language") + val language: String, + @SerializedName("versions") + val versions: Map, +) diff --git a/app/src/main/java/be/scri/data/remote/ApiService.kt b/app/src/main/java/be/scri/data/remote/ApiService.kt new file mode 100644 index 00000000..698fc213 --- /dev/null +++ b/app/src/main/java/be/scri/data/remote/ApiService.kt @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.data.remote + +import be.scri.data.model.DataResponse +import be.scri.data.model.DataVersionResponse +import retrofit2.http.GET +import retrofit2.http.Path + +/** + * Defines the API service for fetching data and data version information. + */ +interface ApiService { + @GET("data/{lang}") + suspend fun getData( + @Path("lang") language: String, + ): DataResponse + + @GET("data-version/{lang}") + suspend fun getDataVersion( + @Path("lang") language: String, + ): DataVersionResponse +} diff --git a/app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt b/app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt new file mode 100644 index 00000000..e382ef95 --- /dev/null +++ b/app/src/main/java/be/scri/data/remote/DynamicDbHelper.kt @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.data.remote + +import android.content.ContentValues +import android.content.Context +import android.database.sqlite.SQLiteDatabase +import android.database.sqlite.SQLiteException +import android.database.sqlite.SQLiteOpenHelper +import android.util.Log +import be.scri.data.model.DataResponse + +/** + * Helper class for managing dynamic SQLite databases based on language. + * It creates tables and inserts data according to the provided DataResponse. + */ +class DynamicDbHelper( + context: Context, + language: String, +) : SQLiteOpenHelper(context, "$language.db", null, 1) { + override fun onCreate(db: SQLiteDatabase) { + // Tables are created dynamically via syncDatabase from API contract. + } + + override fun onUpgrade( + db: SQLiteDatabase, + old: Int, + new: Int, + ) { + // Dynamic schema updates are handled via syncDatabase. + } + + /** + * Synchronizes the database schema and data based on the provided DataResponse. + * @param response The data response containing the contract and data to be inserted. + */ + fun syncDatabase(response: DataResponse) { + val db = writableDatabase + + // Create Tables. + response.contract.fields.forEach { (tableName, columns) -> + val colDefinition = columns.keys.joinToString(", ") { "$it TEXT" } + db.execSQL("CREATE TABLE IF NOT EXISTS $tableName (id INTEGER PRIMARY KEY AUTOINCREMENT, $colDefinition)") + db.execSQL("DELETE FROM $tableName") // clear old data + } + + // Insert Data with Transaction. + db.beginTransaction() + try { + response.data.forEach { (tableName, rows) -> + + rows.forEach { row -> + val cv = ContentValues() + row.forEach { (key, value) -> + cv.put(key, value?.toString() ?: "") + } + val result = db.insert(tableName, null, cv) + if (result == -1L) { + Log.e("SCRIBE_DB", "Failed to insert row into $tableName") + } + } + } + db.setTransactionSuccessful() + } catch (e: SQLiteException) { + Log.e("SCRIBE_DB", "Error during insert: ${e.message}") + } finally { + db.endTransaction() + } + } +} diff --git a/app/src/main/java/be/scri/data/remote/RetrofitClient.kt b/app/src/main/java/be/scri/data/remote/RetrofitClient.kt new file mode 100644 index 00000000..9efcdad4 --- /dev/null +++ b/app/src/main/java/be/scri/data/remote/RetrofitClient.kt @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package be.scri.data.remote + +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +/** + * Singleton object to provide Retrofit client instance for API calls. + */ +object RetrofitClient { + private const val BASE_URL = "https://scribe-server.toolforge.org/api/v1/" + + val apiService: ApiService by lazy { + val retrofit = + Retrofit + .Builder() + .baseUrl(BASE_URL) + .addConverterFactory(GsonConverterFactory.create()) + .build() + + retrofit.create(ApiService::class.java) + } +} diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index e3230e5d..ad8ff578 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -2,19 +2,36 @@ package be.scri.ui.screens.download +import android.app.Application +import android.content.Context +import android.database.sqlite.SQLiteException +import android.widget.Toast import androidx.compose.runtime.mutableStateMapOf -import androidx.lifecycle.ViewModel +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import be.scri.data.remote.DynamicDbHelper +import be.scri.data.remote.RetrofitClient +import be.scri.helpers.LanguageMappingConstants +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import retrofit2.HttpException +import java.io.IOException import java.time.LocalDate -private const val PLACEBO_SERVER_UPDATED_AT = "2025-01-10" -private const val PLACEBO_LOCAL_UPDATED_AT = "2025-01-01" - /** ViewModel to manage data download states and actions. */ -class DataDownloadViewModel : ViewModel() { +class DataDownloadViewModel( + application: Application, +) : AndroidViewModel(application) { val downloadStates = mutableStateMapOf() + private val prefs = getApplication().getSharedPreferences("scribe_prefs", Context.MODE_PRIVATE) /** - * @return true if server data is newer than local data. + * Checks if an update is available by comparing local and server update timestamps. + * + * @param localUpdatedAt The last update timestamp stored locally. + * @param serverUpdatedAt The last update timestamp from the server. + * @return True if an update is available, false otherwise. */ private fun isUpdateAvailable( localUpdatedAt: String, @@ -32,19 +49,71 @@ class DataDownloadViewModel : ViewModel() { * @param key The key identifying the download item. */ fun handleDownloadAction(key: String) { + // Prevent double clicks. val currentState = downloadStates[key] ?: DownloadState.Ready - downloadStates[key] = - when (currentState) { - DownloadState.Ready -> DownloadState.Downloading - DownloadState.Downloading -> DownloadState.Completed - DownloadState.Completed -> - if (isUpdateAvailable(PLACEBO_LOCAL_UPDATED_AT, PLACEBO_SERVER_UPDATED_AT)) { - DownloadState.Update - } else { - DownloadState.Completed + if (currentState == DownloadState.Downloading || currentState == DownloadState.Completed) { + // If already up to date, tell the user and stop. + if (currentState == DownloadState.Completed) { + Toast.makeText(getApplication(), "$key data is already up to date", Toast.LENGTH_SHORT).show() + } + return + } + + // Set to downloading before hitting the network. + downloadStates[key] = DownloadState.Downloading + + val langCode = + LanguageMappingConstants + .getLanguageAlias( + key.replaceFirstChar { it.uppercase() }, + ).lowercase() + + val localLastUpdate = prefs.getString("last_update_$langCode", "1970-01-01") ?: "1970-01-01" + + viewModelScope.launch(Dispatchers.IO) { + try { + // Fetch API. + val response = RetrofitClient.apiService.getData(langCode) + val serverLastUpdate = response.contract.updatedAt + + if (isUpdateAvailable(localLastUpdate, serverLastUpdate)) { + // Sync to SQLite. + val dbHelper = DynamicDbHelper(getApplication(), langCode) + dbHelper.syncDatabase(response) + + // Save timestamp. + prefs.edit().putString("last_update_$langCode", serverLastUpdate).apply() + + withContext(Dispatchers.Main) { + downloadStates[key] = DownloadState.Completed + Toast.makeText(getApplication(), "Download finished!", Toast.LENGTH_SHORT).show() } - DownloadState.Update -> DownloadState.Downloading + } else { + // Already up to date: Skip the DB work. + withContext(Dispatchers.Main) { + downloadStates[key] = DownloadState.Completed + Toast.makeText(getApplication(), "Already up to date!", Toast.LENGTH_SHORT).show() + } + } + } catch (e: IOException) { + updateErrorState(key, "Network Error: ${e.message}") + } catch (e: SQLiteException) { + updateErrorState(key, "Database Error: ${e.message}") + } catch (e: HttpException) { + updateErrorState(key, "Server Error: ${e.code()}") } + } + } + + private suspend fun updateErrorState( + key: String, + message: String, + ) { + withContext(Dispatchers.Main) { + // Reset status so user can retry. + downloadStates[key] = DownloadState.Ready + Toast.makeText(getApplication(), message, Toast.LENGTH_LONG).show() + } } } From d49a99ccbe5033e8e97cac27e65ffc461a461834 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 11 Feb 2026 09:11:12 +0700 Subject: [PATCH 02/15] feat: persist download states across app relaunches --- app/src/main/java/be/scri/App.kt | 2 ++ .../ui/screens/download/DataDownloadScreen.kt | 10 +++++++ .../screens/download/DataDownloadViewModel.kt | 26 +++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/app/src/main/java/be/scri/App.kt b/app/src/main/java/be/scri/App.kt index ad2cda99..665362b2 100644 --- a/app/src/main/java/be/scri/App.kt +++ b/app/src/main/java/be/scri/App.kt @@ -81,6 +81,7 @@ fun ScribeApp( val navBackStackEntry by navController.currentBackStackEntryAsState() val downloadStates = downloadViewModel.downloadStates val onDownloadAction = downloadViewModel::handleDownloadAction + val inititalizeStates = downloadViewModel::initializeStates ScribeTheme( useDarkTheme = isDarkTheme, @@ -212,6 +213,7 @@ fun ScribeApp( }, downloadStates = downloadStates, onDownloadAction = onDownloadAction, + initializeStates = inititalizeStates, modifier = Modifier.padding(innerPadding), ) } diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt index e3a21942..0bfb02ee 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt @@ -18,8 +18,11 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext @@ -52,7 +55,9 @@ fun DownloadDataScreen( modifier: Modifier = Modifier, downloadStates: Map = emptyMap(), onDownloadAction: (String) -> Unit = {}, + initializeStates: (List) -> Unit = {}, ) { + val currentInitializeStates by rememberUpdatedState(initializeStates) val scrollState = rememberScrollState() val checkForNewData = remember { mutableStateOf(false) } val regularlyUpdateData = remember { mutableStateOf(true) } @@ -89,6 +94,11 @@ fun DownloadDataScreen( } } + LaunchedEffect(languages) { + val keys = languages.map { it.first } + currentInitializeStates(keys) + } + ScribeBaseScreen( pageTitle = stringResource(R.string.i18n_app__global_download_data), lastPage = stringResource(R.string.i18n_app_installation_title), diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index ad8ff578..6315dde7 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -26,6 +26,32 @@ class DataDownloadViewModel( val downloadStates = mutableStateMapOf() private val prefs = getApplication().getSharedPreferences("scribe_prefs", Context.MODE_PRIVATE) + /** + * Initializes the download states for the provided languages. + * + * @param languages A list of language keys to initialize states for. + */ + fun initializeStates(languages: List) { + languages.forEach { key -> + if (key == "all") return@forEach + + val langCode = + LanguageMappingConstants + .getLanguageAlias( + key.replaceFirstChar { it.uppercase() }, + ).lowercase() + + // Check if a timestamp exists in SharedPreferences. + val savedTimestamp = prefs.getString("last_update_$langCode", null) + + if (savedTimestamp != null) { + downloadStates[key] = DownloadState.Completed + } else { + downloadStates[key] = DownloadState.Ready + } + } + } + /** * Checks if an update is available by comparing local and server update timestamps. * From ed6e803b28234b14564b6d36929433537b9d1bac Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 11 Feb 2026 12:03:08 +0700 Subject: [PATCH 03/15] fix: fix installed keyboards not showing in Settings --- app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt b/app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt index 16258974..b47eae15 100644 --- a/app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt +++ b/app/src/main/java/be/scri/ui/screens/settings/SettingsUtil.kt @@ -26,7 +26,7 @@ object SettingsUtil { fun checkKeyboardInstallation(context: Context): Boolean { val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager - return imm.enabledInputMethodList.any { it.packageName == "be.scri.debug" } + return imm.enabledInputMethodList.any { it.packageName == context.packageName } } /** From 5e2c593027cfb408ba18f02d7928c69e877a776f Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 11 Feb 2026 16:20:43 +0700 Subject: [PATCH 04/15] feat: trigger download and "Downloading" state from Select Translation Source Language Screen --- .../scri/ui/screens/SelectLanguageScreen.kt | 4 +- .../ui/screens/download/DataDownloadScreen.kt | 6 +- .../screens/download/DataDownloadViewModel.kt | 95 ++++++++++++------- 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt b/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt index 7446a804..fad200aa 100644 --- a/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/SelectLanguageScreen.kt @@ -46,7 +46,7 @@ fun SelectTranslationSourceLanguageScreen( onBackNavigation: () -> Unit, onNavigateToDownloadData: () -> Unit, modifier: Modifier = Modifier, - onDownloadAction: (String) -> Unit = {}, + onDownloadAction: (String, Boolean) -> Unit = { _, _ -> }, ) { val context = LocalContext.current val sharedPref = context.getSharedPreferences("app_preferences", Context.MODE_PRIVATE) @@ -143,7 +143,7 @@ fun SelectTranslationSourceLanguageScreen( val downloadKey = currentLanguage.lowercase() // trigger the download action in the ViewModel. - onDownloadAction(downloadKey) + onDownloadAction(downloadKey, true) showDialog.value = false // Navigate to the download data screen. onNavigateToDownloadData() diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt index 0bfb02ee..50e985e6 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt @@ -54,7 +54,7 @@ fun DownloadDataScreen( onNavigateToTranslation: (String) -> Unit, modifier: Modifier = Modifier, downloadStates: Map = emptyMap(), - onDownloadAction: (String) -> Unit = {}, + onDownloadAction: (String, Boolean) -> Unit = { _, _ -> }, initializeStates: (List) -> Unit = {}, ) { val currentInitializeStates by rememberUpdatedState(initializeStates) @@ -178,7 +178,7 @@ fun DownloadDataScreen( if (currentStatus == DownloadState.Ready) { selectedLanguage.value = lang } else { - onDownloadAction(key) + onDownloadAction(key, false) } }, isDarkTheme = isDark, @@ -216,7 +216,7 @@ fun DownloadDataScreen( ), textChange = stringResource(R.string.i18n_app_download_menu_ui_translation_source_tooltip_change_language), onConfirm = { - onDownloadAction(key) + onDownloadAction(key, false) selectedLanguage.value = null }, onChange = { onNavigateToTranslation(languageId) }, diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index 6315dde7..fe24df32 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -13,6 +13,7 @@ import be.scri.data.remote.DynamicDbHelper import be.scri.data.remote.RetrofitClient import be.scri.helpers.LanguageMappingConstants import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import retrofit2.HttpException @@ -24,6 +25,7 @@ class DataDownloadViewModel( application: Application, ) : AndroidViewModel(application) { val downloadStates = mutableStateMapOf() + private val downloadJobs = mutableMapOf() private val prefs = getApplication().getSharedPreferences("scribe_prefs", Context.MODE_PRIVATE) /** @@ -34,6 +36,7 @@ class DataDownloadViewModel( fun initializeStates(languages: List) { languages.forEach { key -> if (key == "all") return@forEach + if (downloadStates.containsKey(key)) return@forEach val langCode = LanguageMappingConstants @@ -73,16 +76,24 @@ class DataDownloadViewModel( * Handles the download action based on the current state. * * @param key The key identifying the download item. + * @param forceDownload If true, cancels any existing download and forces a new one. */ - fun handleDownloadAction(key: String) { - // Prevent double clicks. + fun handleDownloadAction( + key: String, + forceDownload: Boolean = false, + ) { val currentState = downloadStates[key] ?: DownloadState.Ready - if (currentState == DownloadState.Downloading || currentState == DownloadState.Completed) { - // If already up to date, tell the user and stop. + if (forceDownload) { + downloadJobs[key]?.cancel() + } else { + if (currentState == DownloadState.Downloading) { + return + } + if (currentState == DownloadState.Completed) { Toast.makeText(getApplication(), "$key data is already up to date", Toast.LENGTH_SHORT).show() + return } - return } // Set to downloading before hitting the network. @@ -96,39 +107,44 @@ class DataDownloadViewModel( val localLastUpdate = prefs.getString("last_update_$langCode", "1970-01-01") ?: "1970-01-01" - viewModelScope.launch(Dispatchers.IO) { - try { - // Fetch API. - val response = RetrofitClient.apiService.getData(langCode) - val serverLastUpdate = response.contract.updatedAt - - if (isUpdateAvailable(localLastUpdate, serverLastUpdate)) { - // Sync to SQLite. - val dbHelper = DynamicDbHelper(getApplication(), langCode) - dbHelper.syncDatabase(response) - - // Save timestamp. - prefs.edit().putString("last_update_$langCode", serverLastUpdate).apply() - - withContext(Dispatchers.Main) { - downloadStates[key] = DownloadState.Completed - Toast.makeText(getApplication(), "Download finished!", Toast.LENGTH_SHORT).show() - } - } else { - // Already up to date: Skip the DB work. - withContext(Dispatchers.Main) { - downloadStates[key] = DownloadState.Completed - Toast.makeText(getApplication(), "Already up to date!", Toast.LENGTH_SHORT).show() + // Store the job so we can cancel it later if needed. + downloadJobs[key] = + viewModelScope.launch(Dispatchers.IO) { + try { + // Fetch API. + val response = RetrofitClient.apiService.getData(langCode) + val serverLastUpdate = response.contract.updatedAt + + // Always download when forcing, or when update is available. + if (forceDownload || isUpdateAvailable(localLastUpdate, serverLastUpdate)) { + val dbHelper = DynamicDbHelper(getApplication(), langCode) + dbHelper.syncDatabase(response) + + // Save timestamp. + prefs.edit().putString("last_update_$langCode", serverLastUpdate).apply() + + withContext(Dispatchers.Main) { + downloadStates[key] = DownloadState.Completed + Toast.makeText(getApplication(), "Download finished!", Toast.LENGTH_SHORT).show() + } + } else { + // Already up to date: Skip the DB work. + withContext(Dispatchers.Main) { + downloadStates[key] = DownloadState.Completed + Toast.makeText(getApplication(), "Already up to date!", Toast.LENGTH_SHORT).show() + } } + } catch (e: IOException) { + updateErrorState(key, "Network Error: ${e.message}") + } catch (e: SQLiteException) { + updateErrorState(key, "Database Error: ${e.message}") + } catch (e: HttpException) { + updateErrorState(key, "Server Error: ${e.code()}") + } finally { + // Clean up the job reference when done. + downloadJobs.remove(key) } - } catch (e: IOException) { - updateErrorState(key, "Network Error: ${e.message}") - } catch (e: SQLiteException) { - updateErrorState(key, "Database Error: ${e.message}") - } catch (e: HttpException) { - updateErrorState(key, "Server Error: ${e.code()}") } - } } private suspend fun updateErrorState( @@ -141,6 +157,15 @@ class DataDownloadViewModel( Toast.makeText(getApplication(), message, Toast.LENGTH_LONG).show() } } + + /** + * Cancels all ongoing downloads. Useful for cleanup. + */ + override fun onCleared() { + super.onCleared() + downloadJobs.values.forEach { it.cancel() } + downloadJobs.clear() + } } /** From 88f81484faa99839ff1ae49bf54f7d91aaed69cc Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Wed, 11 Feb 2026 17:48:06 +0700 Subject: [PATCH 05/15] redirect to Download Screen on confirming translation source change --- app/src/main/java/be/scri/App.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/be/scri/App.kt b/app/src/main/java/be/scri/App.kt index 665362b2..538021d9 100644 --- a/app/src/main/java/be/scri/App.kt +++ b/app/src/main/java/be/scri/App.kt @@ -245,7 +245,7 @@ fun ScribeApp( navController.popBackStack() }, onNavigateToDownloadData = { - navController.popBackStack() + navController.navigate("download_data") }, onDownloadAction = onDownloadAction, modifier = Modifier.padding(innerPadding), From cf24823686ace8d1ce3ce2da0cc6683bbf0a1f16 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Thu, 12 Feb 2026 15:37:34 +0700 Subject: [PATCH 06/15] feat: set Update state for download button using data version endpoint --- app/src/main/java/be/scri/App.kt | 2 + .../ui/screens/download/DataDownloadScreen.kt | 10 ++- .../screens/download/DataDownloadViewModel.kt | 67 ++++++++++++++++++- 3 files changed, 75 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/be/scri/App.kt b/app/src/main/java/be/scri/App.kt index 538021d9..632f0c43 100644 --- a/app/src/main/java/be/scri/App.kt +++ b/app/src/main/java/be/scri/App.kt @@ -82,6 +82,7 @@ fun ScribeApp( val downloadStates = downloadViewModel.downloadStates val onDownloadAction = downloadViewModel::handleDownloadAction val inititalizeStates = downloadViewModel::initializeStates + val checkAllForUpdates = downloadViewModel::checkAllForUpdates ScribeTheme( useDarkTheme = isDarkTheme, @@ -214,6 +215,7 @@ fun ScribeApp( downloadStates = downloadStates, onDownloadAction = onDownloadAction, initializeStates = inititalizeStates, + checkAllForUpdates = checkAllForUpdates, modifier = Modifier.padding(innerPadding), ) } diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt index 50e985e6..0ca440bc 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadScreen.kt @@ -47,6 +47,8 @@ import be.scri.ui.screens.settings.SettingsUtil * @param modifier Modifier for layout and styling. * @param downloadStates Map of language keys to their download states. * @param onDownloadAction Callback for download action when a language is selected and confirmed. + * @param initializeStates Callback to initialize download states for given languages. + * @param checkAllForUpdates Callback to check all languages for available updates. */ @Composable fun DownloadDataScreen( @@ -56,6 +58,7 @@ fun DownloadDataScreen( downloadStates: Map = emptyMap(), onDownloadAction: (String, Boolean) -> Unit = { _, _ -> }, initializeStates: (List) -> Unit = {}, + checkAllForUpdates: () -> Unit, ) { val currentInitializeStates by rememberUpdatedState(initializeStates) val scrollState = rememberScrollState() @@ -131,7 +134,12 @@ fun DownloadDataScreen( Column(Modifier.padding(vertical = 10.dp, horizontal = 4.dp)) { CircleClickableItemComp( title = stringResource(R.string.i18n_app_download_menu_ui_update_data_check_new), - onClick = { checkForNewData.value = !checkForNewData.value }, + onClick = { + checkForNewData.value = !checkForNewData.value + if (checkForNewData.value) { + checkAllForUpdates() + } + }, isSelected = checkForNewData.value, ) diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index fe24df32..80b5a7c8 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -5,6 +5,7 @@ package be.scri.ui.screens.download import android.app.Application import android.content.Context import android.database.sqlite.SQLiteException +import android.util.Log import android.widget.Toast import androidx.compose.runtime.mutableStateMapOf import androidx.lifecycle.AndroidViewModel @@ -53,6 +54,9 @@ class DataDownloadViewModel( downloadStates[key] = DownloadState.Ready } } + + // After initializing, check for updates on all Completed languages. + checkAllForUpdates() } /** @@ -66,8 +70,8 @@ class DataDownloadViewModel( localUpdatedAt: String, serverUpdatedAt: String, ): Boolean { - val localDate = LocalDate.parse(localUpdatedAt) - val serverDate = LocalDate.parse(serverUpdatedAt) + val localDate = LocalDate.parse(localUpdatedAt.take(10)) + val serverDate = LocalDate.parse(serverUpdatedAt.take(10)) return serverDate.isAfter(localDate) } @@ -147,6 +151,63 @@ class DataDownloadViewModel( } } + /** + * Checks for available updates using the data version API. + * Sets state to Update if server has newer data. + * + * @param key The key identifying the download item. + */ + fun checkForUpdates(key: String) { + val currentState = downloadStates[key] ?: DownloadState.Ready + if (currentState == DownloadState.Downloading) return + + val langCode = + LanguageMappingConstants + .getLanguageAlias(key.replaceFirstChar { it.uppercase() }) + .lowercase() + + val localLastUpdate = prefs.getString("last_update_$langCode", "1970-01-01") ?: "1970-01-01" + + viewModelScope.launch(Dispatchers.IO) { + try { + val response = RetrofitClient.apiService.getDataVersion(langCode) + + val hasUpdate = + response.versions.values.any { serverDate -> + isUpdateAvailable(localLastUpdate, serverDate) + } + + withContext(Dispatchers.Main) { + downloadStates[key] = + if (hasUpdate) { + DownloadState.Update + } else { + DownloadState.Completed + } + } + } catch (e: IOException) { + Log.w("DownloadVM", "Network error while checking updates for $key: ${e.message}") + } catch (e: HttpException) { + Log.w("DownloadVM", "Server error while checking updates for $key: ${e.code()}") + } catch (e: SQLiteException) { + Log.w("DownloadVM", "Database error while checking updates for $key: ${e.message}") + } + } + } + + /** + * Checks all languages for updates. + */ + fun checkAllForUpdates() { + downloadStates.keys.forEach { key -> + if (key == "all") return@forEach + // Only check languages that have been downloaded before. + if (downloadStates[key] == DownloadState.Completed) { + checkForUpdates(key) + } + } + } + private suspend fun updateErrorState( key: String, message: String, @@ -159,7 +220,7 @@ class DataDownloadViewModel( } /** - * Cancels all ongoing downloads. Useful for cleanup. + * Cancels all ongoing downloads. */ override fun onCleared() { super.onCleared() From d645f8376a83b7e5d6c08720a369bfef43f4b589 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Fri, 13 Feb 2026 13:50:00 +0700 Subject: [PATCH 07/15] fix download Toast display message --- .../be/scri/ui/screens/download/DataDownloadViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt index 80b5a7c8..38e09082 100644 --- a/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt +++ b/app/src/main/java/be/scri/ui/screens/download/DataDownloadViewModel.kt @@ -87,6 +87,7 @@ class DataDownloadViewModel( forceDownload: Boolean = false, ) { val currentState = downloadStates[key] ?: DownloadState.Ready + val displayLang = key.replaceFirstChar { it.uppercase() } if (forceDownload) { downloadJobs[key]?.cancel() } else { @@ -95,7 +96,7 @@ class DataDownloadViewModel( } if (currentState == DownloadState.Completed) { - Toast.makeText(getApplication(), "$key data is already up to date", Toast.LENGTH_SHORT).show() + Toast.makeText(getApplication(), "$displayLang data is already up to date", Toast.LENGTH_SHORT).show() return } } @@ -129,7 +130,7 @@ class DataDownloadViewModel( withContext(Dispatchers.Main) { downloadStates[key] = DownloadState.Completed - Toast.makeText(getApplication(), "Download finished!", Toast.LENGTH_SHORT).show() + Toast.makeText(getApplication(), "Download $displayLang data finished!", Toast.LENGTH_SHORT).show() } } else { // Already up to date: Skip the DB work. From 14f2ebb462038445d05f8a60e615b02317ccbf2c Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 13:24:16 +0100 Subject: [PATCH 08/15] Add new YAML based contract files --- app/src/main/assets/data-contracts/de.yaml | 46 +++++++ app/src/main/assets/data-contracts/en.yaml | 136 +++++++++++++++++++++ app/src/main/assets/data-contracts/es.yaml | 66 ++++++++++ app/src/main/assets/data-contracts/fr.yaml | 78 ++++++++++++ app/src/main/assets/data-contracts/it.yaml | 64 ++++++++++ app/src/main/assets/data-contracts/pt.yaml | 80 ++++++++++++ app/src/main/assets/data-contracts/ru.yaml | 44 +++++++ app/src/main/assets/data-contracts/sv.yaml | 43 +++++++ 8 files changed, 557 insertions(+) create mode 100644 app/src/main/assets/data-contracts/de.yaml create mode 100644 app/src/main/assets/data-contracts/en.yaml create mode 100644 app/src/main/assets/data-contracts/es.yaml create mode 100644 app/src/main/assets/data-contracts/fr.yaml create mode 100644 app/src/main/assets/data-contracts/it.yaml create mode 100644 app/src/main/assets/data-contracts/pt.yaml create mode 100644 app/src/main/assets/data-contracts/ru.yaml create mode 100644 app/src/main/assets/data-contracts/sv.yaml diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml new file mode 100644 index 00000000..980cc075 --- /dev/null +++ b/app/src/main/assets/data-contracts/de.yaml @@ -0,0 +1,46 @@ + +numbers: + nominativeSingular: nominativePlural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + "1": + title: Präsens + conjugationTypes: + "1": + title: Präsens + conjugationForms: + ich: indicativePresentFirstPersonSingular + du: indicativePresentSecondPersonSingular + er/sie/es: indicativePresentThirdPersonSingular + wir: indicativePresentFirstPersonPlural + ihr: indicativePresentSecondPersonPlural + sie/Sie: indicativePresentThirdPersonPlural + "2": + title: Preterite + conjugationTypes: + "1": + title: Preterite + conjugationForms: + ich: indicativePreteriteFirstPersonSingular + du: indicativePreteriteFirstPersonPlural + er/sie/es: indicativePreteriteSecondPersonSingular + wir: indicativePreteriteSecondPersonPlural + ihr: indicativePreteriteThirdPersonSingular + sie/Sie: indicativePreteriteThirdPersonPlural + "3": + title: Perfekt + conjugationTypes: + "1": + title: Perfekt + conjugationForms: + ich: "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple" + du: "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple" + er/sie/es: "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple" + wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" + ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" + sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml new file mode 100644 index 00000000..2eaa5946 --- /dev/null +++ b/app/src/main/assets/data-contracts/en.yaml @@ -0,0 +1,136 @@ +{ + "numbers": { + "singular": "plural" + }, + "genders": { + "canonical": [], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Present", + "conjugationTypes": { + "1": { + "title": "Pr. Simple", + "conjugationForms": { + "I/you/plural": "simplePresent", + "he/she/it": "simplePresentThirdPersonSingular" + } + }, + "2": { + "title": "Pr. Perfect", + "conjugationForms": { + "I/you/plural": "[have] pastParticiple", + "he/she/it": "[has] pastParticiple" + } + }, + "3": { + "title": "Pr. Continuous", + "conjugationForms": { + "I": "[am] presentParticiple", + "you/plural": "[are] presentParticiple", + "he/she/it": "[is] presentParticiple" + } + }, + "4": { + "title": "Pr. Perf. Continuous", + "conjugationForms": { + "I/you/plural": "[have been] presentParticiple", + "he/she/it": "[has been] presentParticiple" + } + } + } + }, + "2": { + "title": "Past", + "conjugationTypes": { + "1": { + "title": "Past Simple", + "conjugationForms": { + "all": "simplePast" + } + }, + "2": { + "title": "Past Perfect", + "conjugationForms": { + "all": "[had] pastParticiple" + } + }, + "3": { + "title": "Past Continuous", + "conjugationForms": { + "I/he/she/it": "[was] presentParticiple", + "you/plural": "[were] presentParticiple" + } + }, + "4": { + "title": "Past Perf. Continuous", + "conjugationForms": { + "all": "[had been] presentParticiple" + } + } + } + }, + "3": { + "title": "Future", + "conjugationTypes": { + "1": { + "title": "Fut. Simple", + "conjugationForms": { + "all": "[will] infinitive" + } + }, + "2": { + "title": "Fut. Perfect", + "conjugationForms": { + "all": "[will have] pastParticiple" + } + }, + "3": { + "title": "Fut. Continuous", + "conjugationForms": { + "all": "[will be] presentParticiple" + } + }, + "4": { + "title": "Fut. Perf. Continuous", + "conjugationForms": { + "all": "[will have been] presentParticiple" + } + } + } + }, + "4": { + "title": "Conditional", + "conjugationTypes": { + "1": { + "title": "Cond. Simple", + "conjugationForms": { + "all": "[would] infinitive" + } + }, + "2": { + "title": "Cond. Perfect", + "conjugationForms": { + "all": "[would have] pastParticiple" + } + }, + "3": { + "title": "Cond. Continuous", + "conjugationForms": { + "all": "[would be] presentParticiple" + } + }, + "4": { + "title": "Cond. Perf. Continuous", + "conjugationForms": { + "all": "[would have been] presentParticiple" + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml new file mode 100644 index 00000000..63ec1131 --- /dev/null +++ b/app/src/main/assets/data-contracts/es.yaml @@ -0,0 +1,66 @@ +{ + "numbers": { + "feminineSingular": "femininePlural", + "masculineSingular": "masculinePlural" + }, + "genders": { + "canonical": [], + "feminines": ["feminineSingular"], + "masculines": ["masculineSingular"], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Presente", + "conjugationTypes": { + "1": { + "title": "Presente", + "conjugationForms": { + "yo": "indicativePresentFirstPersonSingular", + "tú": "indicativePresentFirstPersonPlural", + "él/ella/Ud.": "indicativePresentSecondPersonSingular", + "nosotros": "indicativePresentSecondPersonPlural", + "vosotros": "indicativePresentThirdPersonSingular", + "ellos/ellas/Uds.": "indicativePresentThirdPersonPlural" + } + } + } + }, + "2": { + "title": "Pretérito", + "conjugationTypes": { + "1": { + "title": "Pretérito", + "conjugationForms": { + "yo": "preteriteFirstPersonSingular", + "tú": "preteriteFirstPersonPlural", + "él/ella/Ud.": "preteriteSecondPersonSingular", + "nosotros": "preteriteSecondPersonPlural", + "vosotros": "preteriteThirdPersonSingular", + "ellos/ellas/Uds.": "preteriteThirdPersonPlural" + } + } + } + + }, + "3": { + "title": "Imperfecto", + "conjugationTypes" : { + "1": { + "title": "Imperfecto", + "conjugationForms": { + "yo": "pastImperfectFirstPersonSingular", + "tú": "pastImperfectFirstPersonPlural", + "él/ella/Ud.": "pastImperfectSecondPersonSingular", + "nosotros": "pastImperfectSecondPersonPlural", + "vosotros": "pastImperfectThirdPersonSingular", + "ellos/ellas/Uds.": "pastImperfectThirdPersonPlural" + } + } + } + + } + } + } + \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml new file mode 100644 index 00000000..44833124 --- /dev/null +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -0,0 +1,78 @@ +{ + "numbers": { "singular": "plural" }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Présent", + "conjugationTypes": { + "1": { + "title": "Présent", + "conjugationForms": { + "je": "indicativePresentFirstPersonSingular", + "tu": "indicativePresentFirstPersonPlural", + "il/elle": "indicativePresentSecondPersonSingular", + "nous": "indicativePresentSecondPersonPlural", + "vous": "indicativePresentThirdPersonSingular", + "ils/elles": "indicativePresentThirdPersonPlural" + } + } + } + }, + "2": { + "title": "Passé simple", + "conjugationTypes": { + "1": { + "title": "Passé simple", + "conjugationForms": { + "je": "indicativePreteriteFirstPersonSingular", + "tu": "indicativePreteriteFirstPersonPlural", + "il/elle": "indicativePreteriteSecondPersonSingular", + "nous": "indicativePreteriteSecondPersonPlural", + "vous": "indicativePreteriteThirdPersonSingular", + "ils/elles": "indicativePreteriteThirdPersonPlural" + } + } + } + }, + "3": { + "title": "Imparfait", + "conjugationTypes": { + "1": { + "title": "Imparfait", + "conjugationForms": { + "je": "indicativeImperfectFirstPersonSingular", + "tu": "indicativeImperfectFirstPersonPlural", + "il/elle": "indicativeImperfectSecondPersonSingular", + "nous": "indicativeImperfectSecondPersonPlural", + "vous": "indicativeImperfectThirdPersonSingular", + "ils/elles": "indicativeImperfectThirdPersonPlural" + } + } + } + + }, + "4": { + "title": "Futur", + "conjugationTypes":{ + "1": { + "title": "Futur", + "conjugationForms": { + "je": "indicativeSimpleFutureFirstPersonSingular", + "tu": "indicativeSimpleFutureFirstPersonPlural", + "il/elle": "indicativeSimpleFutureSecondPersonSingular", + "nous": "indicativeSimpleFutureSecondPersonPlural", + "vous": "indicativeSimpleFutureThirdPersonSingular", + "ils/elles": "indicativeSimpleFutureThirdPersonPlural" + } + } + } + } + } + } + \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml new file mode 100644 index 00000000..f30709b0 --- /dev/null +++ b/app/src/main/assets/data-contracts/it.yaml @@ -0,0 +1,64 @@ +{ + "numbers": { "singular": "plural" }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Presente", + "conjugationTypes": { + "1": { + "title": "Presente", + "conjugationForms": { + "io": "presentIndicativeFirstPersonSingular", + "tu": "presentIndicativeFirstPersonPlural", + "lei/lui": "presentIndicativeSecondPersonSingular", + "noi": "presentIndicativeSecondPersonPlural", + "voi": "presentIndicativeThirdPersonSingular", + "loro": "presentIndicativeThirdPersonPlural" + } + } + } + + }, + "2": { + "title": "Preterito", + "conjugationTypes": { + "1": { + "title": "Preterito", + "conjugationForms": { + "io": "preteriteFirstPersonSingular", + "tu": "preteriteFirstPersonPlural", + "lei/lui": "preteriteSecondPersonSingular", + "noi": "preteriteSecondPersonPlural", + "voi": "preteriteThirdPersonSingular", + "loro": "preteriteThirdPersonPlural" + } + } + } + + }, + "3": { + "title": "Imperfetto", + "conjugationTypes": { + "1": { + "title": "Imperfetto", + "conjugationForms": { + "io": "pastImperfectFirstPersonSingular", + "tu": "pastImperfectFirstPersonPlural", + "lei/lui": "pastImperfectSecondPersonSingular", + "noi": "pastImperfectSecondPersonPlural", + "voi": "pastImperfectThirdPersonSingular", + "loro": "pastImperfectThirdPersonPlural" + } + } + } + + } + } + } + \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml new file mode 100644 index 00000000..7a3b55f3 --- /dev/null +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -0,0 +1,80 @@ +{ + "numbers": { "singular": "plural" }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Presente", + "conjugationTypes": { + "1": { + "title": "Presente", + "conjugationForms": { + "eu": "indicativePresentFirstPersonSingular", + "tu": "indicativePresentFirstPersonPlural", + "ele/ela/você": "indicativePresentSecondPersonSingular", + "nós": "indicativePresentSecondPersonPlural", + "vós": "indicativePresentThirdPersonSingular", + "eles/elas/vocês": "indicativePresentThirdPersonPlural" + } + } + } + }, + "2": { + "title": "Pretérito Perfeito", + "conjugationTypes": { +"1": { + "title": "Pretérito Perfeito", + "conjugationForms": { + "eu": "indicativePastPerfectFirstPersonSingular", + "tu": "indicativePastPerfectFirstPersonPlural", + "ele/ela/você": "indicativePastPerfectSecondPersonSingular", + "nós": "indicativePastPerfectSecondPersonPlural", + "vós": "indicativePastPerfectThirdPersonSingular", + "eles/elas/vocês": "indicativePastPerfectThirdPersonPlural" + } + } + } + + }, + "3": { + "title": "Pretérito Imperfeito", + "conjugationTypes": { +"1": { + "title": "Pretérito Imperfeito", + "conjugationForms": { + "eu": "indicativePastImperfectFirstPersonSingular", + "tu": "indicativePastImperfectFirstPersonPlural", + "ele/ela/você": "indicativePastImperfectSecondPersonSingular", + "nós": "indicativePastImperfectSecondPersonPlural", + "vós": "indicativePastImperfectThirdPersonSingular", + "eles/elas/vocês": "indicativePastImperfectThirdPersonPlural" + } + } + } + + }, + "4": { + "title": "Futuro Simples", + "conjugationTypes": { +"1": { + "title": "Futuro Simples", + "conjugationForms": { + "eu": "indicativePluperfectFirstPersonSingular", + "tu": "indicativePluperfectFirstPersonPlural", + "ele/ela/você": "indicativePluperfectSecondPersonSingular", + "nós": "indicativePluperfectSecondPersonPlural", + "vós": "indicativePluperfectThirdPersonSingular", + "eles/elas/vocês": "indicativePluperfectThirdPersonPlural" + } + } + } + + } + } + } + \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml new file mode 100644 index 00000000..1742fb91 --- /dev/null +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -0,0 +1,44 @@ +{ + "numbers": { + "nominativeSingular": "nominativePlural" + }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Настоящее (Present)", + "conjugationTypes": { + "1": { + "title": "Indicative Present", + "conjugationForms": { + "я (I)": "indicativePresentFirstPersonSingular", + "ты (you, sing.)": "indicativePresentSecondPersonSingular", + "он/она/оно (he/she/it)": "indicativePresentThirdPersonSingular", + "мы (we)": "indicativePresentFirstPersonPlural", + "вы (you, pl.)": "indicativePresentSecondPersonPlural", + "они (they)": "indicativePresentThirdPersonPlural" + } + } + } + }, + "2": { + "title": "Прошедшее (Past)", + "conjugationTypes": { + "1": { + "title": "Indicative Past", + "conjugationForms": { + "я/ты/она (I/you/she, fem.)": "feminineIndicativePast", + "я/ты/он (I/you/he, masc.)": "masculineIndicativePast", + "оно (it, neut.)": "neuterIndicativePast", + "мы/вы/они (we/you/they)": "indicativePastPlural" + } + } + } + } + } +} diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml new file mode 100644 index 00000000..6bdb2e62 --- /dev/null +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -0,0 +1,43 @@ +{ + "numbers": { + "nominativeIndefiniteSingular": "nominativeIndefinitePlural", + "nominativeDefiniteSingular": "nominativeDefinitePlural" + }, + "genders": { + "canonical": ["gender"], + "feminines": [], + "masculines": [], + "commons": [], + "neuters": [] + }, + "conjugations": { + "1": { + "title": "Aktiv", + "conjugationTypes": { + "1": { + "title": "Aktiv", + "conjugationForms": { + "infinitiv": "activeInfinitive", + "presens": "activePresent", + "preteritum": "activePreterite", + "supinum": "activeSupine" + } + } + } + }, + "2": { + "title": "Passiv", + "conjugationTypes": { + "1": { + "title": "Passiv", + "conjugationForms": { + "infinitiv": "passiveInfinitive", + "presens": "passivePresent", + "preteritum": "passivePreterite", + "supinum": "passiveSupine" + } + } + } + } + } +} From f23e677b3a133be9eebbead142465e17f381992c Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 14:28:33 +0100 Subject: [PATCH 09/15] Finalize form of YAML contracts --- app/src/main/assets/data-contracts/de.yaml | 85 ++++---- app/src/main/assets/data-contracts/en.yaml | 227 +++++++++------------ app/src/main/assets/data-contracts/es.yaml | 112 +++++----- app/src/main/assets/data-contracts/fr.yaml | 135 ++++++------ app/src/main/assets/data-contracts/it.yaml | 109 ++++------ app/src/main/assets/data-contracts/pt.yaml | 138 ++++++------- app/src/main/assets/data-contracts/ru.yaml | 75 +++---- app/src/main/assets/data-contracts/sv.yaml | 73 +++---- 8 files changed, 400 insertions(+), 554 deletions(-) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index 980cc075..b4aac3a6 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -1,46 +1,45 @@ - numbers: - nominativeSingular: nominativePlural + nominativeSingular: nominativePlural genders: - canonical: [gender] - feminines: [] - masculines: [] - commons: [] - neuters: [] + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] conjugations: - "1": - title: Präsens - conjugationTypes: - "1": - title: Präsens - conjugationForms: - ich: indicativePresentFirstPersonSingular - du: indicativePresentSecondPersonSingular - er/sie/es: indicativePresentThirdPersonSingular - wir: indicativePresentFirstPersonPlural - ihr: indicativePresentSecondPersonPlural - sie/Sie: indicativePresentThirdPersonPlural - "2": - title: Preterite - conjugationTypes: - "1": - title: Preterite - conjugationForms: - ich: indicativePreteriteFirstPersonSingular - du: indicativePreteriteFirstPersonPlural - er/sie/es: indicativePreteriteSecondPersonSingular - wir: indicativePreteriteSecondPersonPlural - ihr: indicativePreteriteThirdPersonSingular - sie/Sie: indicativePreteriteThirdPersonPlural - "3": - title: Perfekt - conjugationTypes: - "1": - title: Perfekt - conjugationForms: - ich: "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple" - du: "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple" - er/sie/es: "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple" - wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" - ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" - sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" + 1: + sectionTitle: Präsens + tenses: + 1: + tenseTitle: Präsens + tenseForms: + ich: indicativePresentFirstPersonSingular + du: indicativePresentSecondPersonSingular + er/sie/es: indicativePresentThirdPersonSingular + wir: indicativePresentFirstPersonPlural + ihr: indicativePresentSecondPersonPlural + sie/Sie: indicativePresentThirdPersonPlural + 2: + sectionTitle: Preterite + tenses: + 1: + tenseTitle: Preterite + tenseForms: + ich: indicativePreteriteFirstPersonSingular + du: indicativePreteriteFirstPersonPlural + er/sie/es: indicativePreteriteSecondPersonSingular + wir: indicativePreteriteSecondPersonPlural + ihr: indicativePreteriteThirdPersonSingular + sie/Sie: indicativePreteriteThirdPersonPlural + 3: + sectionTitle: Perfekt + tenses: + 1: + tenseTitle: Perfekt + tenseForms: + ich: "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple" + du: "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple" + er/sie/es: "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple" + wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" + ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" + sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index 2eaa5946..2b10f075 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -1,136 +1,91 @@ -{ - "numbers": { - "singular": "plural" - }, - "genders": { - "canonical": [], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Present", - "conjugationTypes": { - "1": { - "title": "Pr. Simple", - "conjugationForms": { - "I/you/plural": "simplePresent", - "he/she/it": "simplePresentThirdPersonSingular" - } - }, - "2": { - "title": "Pr. Perfect", - "conjugationForms": { - "I/you/plural": "[have] pastParticiple", - "he/she/it": "[has] pastParticiple" - } - }, - "3": { - "title": "Pr. Continuous", - "conjugationForms": { - "I": "[am] presentParticiple", - "you/plural": "[are] presentParticiple", - "he/she/it": "[is] presentParticiple" - } - }, - "4": { - "title": "Pr. Perf. Continuous", - "conjugationForms": { - "I/you/plural": "[have been] presentParticiple", - "he/she/it": "[has been] presentParticiple" - } - } - } - }, - "2": { - "title": "Past", - "conjugationTypes": { - "1": { - "title": "Past Simple", - "conjugationForms": { - "all": "simplePast" - } - }, - "2": { - "title": "Past Perfect", - "conjugationForms": { - "all": "[had] pastParticiple" - } - }, - "3": { - "title": "Past Continuous", - "conjugationForms": { - "I/he/she/it": "[was] presentParticiple", - "you/plural": "[were] presentParticiple" - } - }, - "4": { - "title": "Past Perf. Continuous", - "conjugationForms": { - "all": "[had been] presentParticiple" - } - } - } - }, - "3": { - "title": "Future", - "conjugationTypes": { - "1": { - "title": "Fut. Simple", - "conjugationForms": { - "all": "[will] infinitive" - } - }, - "2": { - "title": "Fut. Perfect", - "conjugationForms": { - "all": "[will have] pastParticiple" - } - }, - "3": { - "title": "Fut. Continuous", - "conjugationForms": { - "all": "[will be] presentParticiple" - } - }, - "4": { - "title": "Fut. Perf. Continuous", - "conjugationForms": { - "all": "[will have been] presentParticiple" - } - } - } - }, - "4": { - "title": "Conditional", - "conjugationTypes": { - "1": { - "title": "Cond. Simple", - "conjugationForms": { - "all": "[would] infinitive" - } - }, - "2": { - "title": "Cond. Perfect", - "conjugationForms": { - "all": "[would have] pastParticiple" - } - }, - "3": { - "title": "Cond. Continuous", - "conjugationForms": { - "all": "[would be] presentParticiple" - } - }, - "4": { - "title": "Cond. Perf. Continuous", - "conjugationForms": { - "all": "[would have been] presentParticiple" - } - } - } - } - } -} \ No newline at end of file +numbers: + singular: plural +genders: + canonical: [] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Present + tenses: + 1: + tenseTitle: Pr. Simple + tenseForms: + I/you/plural: simplePresent + he/she/it: simplePresentThirdPersonSingular + 2: + tenseTitle: Pr. Perfect + tenseForms: + I/you/plural: "[have] pastParticiple" + he/she/it: "[has] pastParticiple" + 3: + tenseTitle: Pr. Continuous + tenseForms: + I: "[am] presentParticiple" + you/plural: "[are] presentParticiple" + he/she/it: "[is] presentParticiple" + 4: + tenseTitle: Pr. Perf. Continuous + tenseForms: + I/you/plural: "[have been] presentParticiple" + he/she/it: "[has been] presentParticiple" + 2: + sectionTitle: Past + tenses: + 1: + tenseTitle: Past Simple + tenseForms: + all: simplePast + 2: + tenseTitle: Past Perfect + tenseForms: + all: "[had] pastParticiple" + 3: + tenseTitle: Past Continuous + tenseForms: + I/he/she/it: "[was] presentParticiple" + you/plural: "[were] presentParticiple" + 4: + tenseTitle: Past Perf. Continuous + tenseForms: + all: "[had been] presentParticiple" + 3: + sectionTitle: Future + tenses: + 1: + tenseTitle": Fut. Simple + tenseForms: + all: "[will] infinitive" + 2: + tenseTitle: Fut. Perfect + tenseForms: + all: "[will have] pastParticiple" + 3: + tenseTitle: Fut. Continuous + tenseForms: + all: "[will be] presentParticiple" + 4: + tenseTitle: Fut. Perf. Continuous + tenseForms: + all: "[will have been] presentParticiple" + 4: + sectionTitle: Conditional + tenses: + 1: + tenseTitle: Cond. Simple + tenseForms: + all: "[would] infinitive" + 2: + tenseTitle: Cond. Perfect + tenseForms: + all: "[would have] pastParticiple" + 3: + tenseTitle: Cond. Continuous + tenseForms: + all: "[would be] presentParticiple" + 4: + tenseTitle: Cond. Perf. Continuous + tenseForms: + all: "[would have been] presentParticiple" diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml index 63ec1131..40de86ec 100644 --- a/app/src/main/assets/data-contracts/es.yaml +++ b/app/src/main/assets/data-contracts/es.yaml @@ -1,66 +1,46 @@ -{ - "numbers": { - "feminineSingular": "femininePlural", - "masculineSingular": "masculinePlural" - }, - "genders": { - "canonical": [], - "feminines": ["feminineSingular"], - "masculines": ["masculineSingular"], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "yo": "indicativePresentFirstPersonSingular", - "tú": "indicativePresentFirstPersonPlural", - "él/ella/Ud.": "indicativePresentSecondPersonSingular", - "nosotros": "indicativePresentSecondPersonPlural", - "vosotros": "indicativePresentThirdPersonSingular", - "ellos/ellas/Uds.": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Pretérito", - "conjugationTypes": { - "1": { - "title": "Pretérito", - "conjugationForms": { - "yo": "preteriteFirstPersonSingular", - "tú": "preteriteFirstPersonPlural", - "él/ella/Ud.": "preteriteSecondPersonSingular", - "nosotros": "preteriteSecondPersonPlural", - "vosotros": "preteriteThirdPersonSingular", - "ellos/ellas/Uds.": "preteriteThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Imperfecto", - "conjugationTypes" : { - "1": { - "title": "Imperfecto", - "conjugationForms": { - "yo": "pastImperfectFirstPersonSingular", - "tú": "pastImperfectFirstPersonPlural", - "él/ella/Ud.": "pastImperfectSecondPersonSingular", - "nosotros": "pastImperfectSecondPersonPlural", - "vosotros": "pastImperfectThirdPersonSingular", - "ellos/ellas/Uds.": "pastImperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file +numbers: + feminineSingular: femininePlural + masculineSingular: masculinePlural +genders: + canonical: [] + feminines: [feminineSingular] + masculines: [masculineSingular] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Presente + tenses: + 1: + tenseTitle: Presente + tenseForms: + yo: indicativePresentFirstPersonSingular + tú: indicativePresentFirstPersonPlural + él/ella/Ud.: indicativePresentSecondPersonSingular + nosotros: indicativePresentSecondPersonPlural + vosotros: indicativePresentThirdPersonSingular + ellos/ellas/Uds.: indicativePresentThirdPersonPlural + 2: + sectionTitle: Pretérito + tenses: + 1: + tenseTitle: Pretérito + tenseForms: + yo: preteriteFirstPersonSingular + tú: preteriteFirstPersonPlural + él/ella/Ud.: preteriteSecondPersonSingular + nosotros: preteriteSecondPersonPlural + vosotros: preteriteThirdPersonSingular + ellos/ellas/Uds.: preteriteThirdPersonPlural + 3: + sectionTitle: Imperfecto + tenses: + 1: + tenseTitle: Imperfecto + tenseForms: + yo: pastImperfectFirstPersonSingular + tú: pastImperfectFirstPersonPlural + él/ella/Ud.: pastImperfectSecondPersonSingular + nosotros: pastImperfectSecondPersonPlural + vosotros: pastImperfectThirdPersonSingular + ellos/ellas/Uds.: pastImperfectThirdPersonPlural diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml index 44833124..704148f5 100644 --- a/app/src/main/assets/data-contracts/fr.yaml +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -1,78 +1,57 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Présent", - "conjugationTypes": { - "1": { - "title": "Présent", - "conjugationForms": { - "je": "indicativePresentFirstPersonSingular", - "tu": "indicativePresentFirstPersonPlural", - "il/elle": "indicativePresentSecondPersonSingular", - "nous": "indicativePresentSecondPersonPlural", - "vous": "indicativePresentThirdPersonSingular", - "ils/elles": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Passé simple", - "conjugationTypes": { - "1": { - "title": "Passé simple", - "conjugationForms": { - "je": "indicativePreteriteFirstPersonSingular", - "tu": "indicativePreteriteFirstPersonPlural", - "il/elle": "indicativePreteriteSecondPersonSingular", - "nous": "indicativePreteriteSecondPersonPlural", - "vous": "indicativePreteriteThirdPersonSingular", - "ils/elles": "indicativePreteriteThirdPersonPlural" - } - } - } - }, - "3": { - "title": "Imparfait", - "conjugationTypes": { - "1": { - "title": "Imparfait", - "conjugationForms": { - "je": "indicativeImperfectFirstPersonSingular", - "tu": "indicativeImperfectFirstPersonPlural", - "il/elle": "indicativeImperfectSecondPersonSingular", - "nous": "indicativeImperfectSecondPersonPlural", - "vous": "indicativeImperfectThirdPersonSingular", - "ils/elles": "indicativeImperfectThirdPersonPlural" - } - } - } - - }, - "4": { - "title": "Futur", - "conjugationTypes":{ - "1": { - "title": "Futur", - "conjugationForms": { - "je": "indicativeSimpleFutureFirstPersonSingular", - "tu": "indicativeSimpleFutureFirstPersonPlural", - "il/elle": "indicativeSimpleFutureSecondPersonSingular", - "nous": "indicativeSimpleFutureSecondPersonPlural", - "vous": "indicativeSimpleFutureThirdPersonSingular", - "ils/elles": "indicativeSimpleFutureThirdPersonPlural" - } - } - } - } - } - } - \ No newline at end of file +numbers: + singular: plural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Présent + tenses: + 1: + tenseTitle: Présent + tenseForms: + je: indicativePresentFirstPersonSingular + tu: indicativePresentFirstPersonPlural + il/elle: indicativePresentSecondPersonSingular + nous: indicativePresentSecondPersonPlural + vous: indicativePresentThirdPersonSingular + ils/elles: indicativePresentThirdPersonPlural + 2: + sectionTitle: Passé simple + tenses: + 1: + tenseTitle: Passé simple + tenseForms: + je: indicativePreteriteFirstPersonSingular + tu: indicativePreteriteFirstPersonPlural + il/elle: indicativePreteriteSecondPersonSingular + nous: indicativePreteriteSecondPersonPlural + vous: indicativePreteriteThirdPersonSingular + ils/elles: indicativePreteriteThirdPersonPlural + 3: + sectionTitle: Imparfait + tenses: + 1: + tenseTitle: Imparfait + tenseForms: + je: indicativeImperfectFirstPersonSingular + tu: indicativeImperfectFirstPersonPlural + il/elle: indicativeImperfectSecondPersonSingular + nous: indicativeImperfectSecondPersonPlural + vous: indicativeImperfectThirdPersonSingular + ils/elles: indicativeImperfectThirdPersonPlural + 4: + sectionTitle: Futur + tenses: + 1: + tenseTitle: Futur + tenseForms: + je: indicativeSimpleFutureFirstPersonSingular + tu: indicativeSimpleFutureFirstPersonPlural + il/elle: indicativeSimpleFutureSecondPersonSingular + nous: indicativeSimpleFutureSecondPersonPlural + vous: indicativeSimpleFutureThirdPersonSingular + ils/elles: indicativeSimpleFutureThirdPersonPlural diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml index f30709b0..3a002283 100644 --- a/app/src/main/assets/data-contracts/it.yaml +++ b/app/src/main/assets/data-contracts/it.yaml @@ -1,64 +1,45 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "io": "presentIndicativeFirstPersonSingular", - "tu": "presentIndicativeFirstPersonPlural", - "lei/lui": "presentIndicativeSecondPersonSingular", - "noi": "presentIndicativeSecondPersonPlural", - "voi": "presentIndicativeThirdPersonSingular", - "loro": "presentIndicativeThirdPersonPlural" - } - } - } - - }, - "2": { - "title": "Preterito", - "conjugationTypes": { - "1": { - "title": "Preterito", - "conjugationForms": { - "io": "preteriteFirstPersonSingular", - "tu": "preteriteFirstPersonPlural", - "lei/lui": "preteriteSecondPersonSingular", - "noi": "preteriteSecondPersonPlural", - "voi": "preteriteThirdPersonSingular", - "loro": "preteriteThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Imperfetto", - "conjugationTypes": { - "1": { - "title": "Imperfetto", - "conjugationForms": { - "io": "pastImperfectFirstPersonSingular", - "tu": "pastImperfectFirstPersonPlural", - "lei/lui": "pastImperfectSecondPersonSingular", - "noi": "pastImperfectSecondPersonPlural", - "voi": "pastImperfectThirdPersonSingular", - "loro": "pastImperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file +numbers: + singular: plural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Presente + tenses: + 1: + tenseTitle: Presente + tenseForms: + io: presentIndicativeFirstPersonSingular + tu: presentIndicativeFirstPersonPlural + lei/lui: presentIndicativeSecondPersonSingular + noi: presentIndicativeSecondPersonPlural + voi: presentIndicativeThirdPersonSingular + loro: presentIndicativeThirdPersonPlural + 2: + sectionTitle: Preterito + tenses: + 1: + tenseTitle: Preterito + tenseForms: + io: preteriteFirstPersonSingular + tu: preteriteFirstPersonPlural + lei/lui: preteriteSecondPersonSingular + noi: preteriteSecondPersonPlural + voi: preteriteThirdPersonSingular + loro: preteriteThirdPersonPlural + 3: + sectionTitle: Imperfetto + tenses: + 1: + tenseTitle: Imperfetto + tenseForms: + io: pastImperfectFirstPersonSingular + tu: pastImperfectFirstPersonPlural + lei/lui: pastImperfectSecondPersonSingular + noi: pastImperfectSecondPersonPlural + voi: pastImperfectThirdPersonSingular + loro: pastImperfectThirdPersonPlural diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml index 7a3b55f3..71be56f7 100644 --- a/app/src/main/assets/data-contracts/pt.yaml +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -1,80 +1,58 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "eu": "indicativePresentFirstPersonSingular", - "tu": "indicativePresentFirstPersonPlural", - "ele/ela/você": "indicativePresentSecondPersonSingular", - "nós": "indicativePresentSecondPersonPlural", - "vós": "indicativePresentThirdPersonSingular", - "eles/elas/vocês": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Pretérito Perfeito", - "conjugationTypes": { -"1": { - "title": "Pretérito Perfeito", - "conjugationForms": { - "eu": "indicativePastPerfectFirstPersonSingular", - "tu": "indicativePastPerfectFirstPersonPlural", - "ele/ela/você": "indicativePastPerfectSecondPersonSingular", - "nós": "indicativePastPerfectSecondPersonPlural", - "vós": "indicativePastPerfectThirdPersonSingular", - "eles/elas/vocês": "indicativePastPerfectThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Pretérito Imperfeito", - "conjugationTypes": { -"1": { - "title": "Pretérito Imperfeito", - "conjugationForms": { - "eu": "indicativePastImperfectFirstPersonSingular", - "tu": "indicativePastImperfectFirstPersonPlural", - "ele/ela/você": "indicativePastImperfectSecondPersonSingular", - "nós": "indicativePastImperfectSecondPersonPlural", - "vós": "indicativePastImperfectThirdPersonSingular", - "eles/elas/vocês": "indicativePastImperfectThirdPersonPlural" - } - } - } - - }, - "4": { - "title": "Futuro Simples", - "conjugationTypes": { -"1": { - "title": "Futuro Simples", - "conjugationForms": { - "eu": "indicativePluperfectFirstPersonSingular", - "tu": "indicativePluperfectFirstPersonPlural", - "ele/ela/você": "indicativePluperfectSecondPersonSingular", - "nós": "indicativePluperfectSecondPersonPlural", - "vós": "indicativePluperfectThirdPersonSingular", - "eles/elas/vocês": "indicativePluperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file + +numbers: + singular: plural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Presente + tenses: + 1: + tenseTitle: Presente + tenseForms: + eu: indicativePresentFirstPersonSingular + tu: indicativePresentFirstPersonPlural + ele/ela/você: indicativePresentSecondPersonSingular + nós: indicativePresentSecondPersonPlural + vós: indicativePresentThirdPersonSingular + eles/elas/vocês: indicativePresentThirdPersonPlural + 2: + sectionTitle: Pretérito Perfeito + tenses: + 1: + tenseTitle: Pretérito Perfeito + tenseForms: + eu: indicativePastPerfectFirstPersonSingular + tu: indicativePastPerfectFirstPersonPlural + ele/ela/você: indicativePastPerfectSecondPersonSingular + nós: indicativePastPerfectSecondPersonPlural + vós: indicativePastPerfectThirdPersonSingular + eles/elas/vocês: indicativePastPerfectThirdPersonPlural + 3: + sectionTitle: Pretérito Imperfeito + tenses: + 1: + tenseTitle: Pretérito Imperfeito + tenseForms: + eu: indicativePastImperfectFirstPersonSingular + tu: indicativePastImperfectFirstPersonPlural + ele/ela/você: indicativePastImperfectSecondPersonSingular + nós: indicativePastImperfectSecondPersonPlural + vós: indicativePastImperfectThirdPersonSingular + eles/elas/vocês: indicativePastImperfectThirdPersonPlural + 4: + sectionTitle: Futuro Simples + tenses: + 1: + tenseTitle: Futuro Simples + tenseForms: + eu: indicativePluperfectFirstPersonSingular + tu: indicativePluperfectFirstPersonPlural + ele/ela/você: indicativePluperfectSecondPersonSingular + nós: indicativePluperfectSecondPersonPlural + vós: indicativePluperfectThirdPersonSingular + eles/elas/vocês: indicativePluperfectThirdPersonPlural diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 1742fb91..065dcffc 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -1,44 +1,31 @@ -{ - "numbers": { - "nominativeSingular": "nominativePlural" - }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Настоящее (Present)", - "conjugationTypes": { - "1": { - "title": "Indicative Present", - "conjugationForms": { - "я (I)": "indicativePresentFirstPersonSingular", - "ты (you, sing.)": "indicativePresentSecondPersonSingular", - "он/она/оно (he/she/it)": "indicativePresentThirdPersonSingular", - "мы (we)": "indicativePresentFirstPersonPlural", - "вы (you, pl.)": "indicativePresentSecondPersonPlural", - "они (they)": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Прошедшее (Past)", - "conjugationTypes": { - "1": { - "title": "Indicative Past", - "conjugationForms": { - "я/ты/она (I/you/she, fem.)": "feminineIndicativePast", - "я/ты/он (I/you/he, masc.)": "masculineIndicativePast", - "оно (it, neut.)": "neuterIndicativePast", - "мы/вы/они (we/you/they)": "indicativePastPlural" - } - } - } - } - } -} +numbers: + nominativeSingular: nominativePlural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Настоящее + tenses: + 1: + tenseTitle: Indicative Present + tenseForms: + я: indicativePresentFirstPersonSingular + ты: indicativePresentSecondPersonSingular + он/она/оно: indicativePresentThirdPersonSingular + мы: indicativePresentFirstPersonPlural + вы: indicativePresentSecondPersonPlural + они: indicativePresentThirdPersonPlural + 2: + sectionTitle: Прошедшее + tenses: + 1: + tenseTitle: Indicative Past + tenseForms: + я/ты/она: feminineIndicativePast + я/ты/он: masculineIndicativePast + оно: neuterIndicativePast + мы/вы/они: indicativePastPlural diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml index 6bdb2e62..44075b1e 100644 --- a/app/src/main/assets/data-contracts/sv.yaml +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -1,43 +1,30 @@ -{ - "numbers": { - "nominativeIndefiniteSingular": "nominativeIndefinitePlural", - "nominativeDefiniteSingular": "nominativeDefinitePlural" - }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Aktiv", - "conjugationTypes": { - "1": { - "title": "Aktiv", - "conjugationForms": { - "infinitiv": "activeInfinitive", - "presens": "activePresent", - "preteritum": "activePreterite", - "supinum": "activeSupine" - } - } - } - }, - "2": { - "title": "Passiv", - "conjugationTypes": { - "1": { - "title": "Passiv", - "conjugationForms": { - "infinitiv": "passiveInfinitive", - "presens": "passivePresent", - "preteritum": "passivePreterite", - "supinum": "passiveSupine" - } - } - } - } - } -} +numbers: + nominativeIndefiniteSingular: nominativeIndefinitePlural + nominativeDefiniteSingular: nominativeDefinitePlural +genders: + canonical: [gender] + feminines: [] + masculines: [] + commons: [] + neuters: [] +conjugations: + 1: + sectionTitle: Aktiv + tenses: + 1: + tenseTitle: Aktiv + tenseForms: + infinitiv: activeInfinitive + presens: activePresent + preteritum: activePreterite + supinum: activeSupine + 2: + sectionTitle: Passiv + tenses: + 1: + tenseTitle: Passiv + tenseForms: + infinitiv: passiveInfinitive + presens: passivePresent + preteritum: passivePreterite + supinum: passiveSupine From 3af7f7a5ed2e8535e98ff5421b6735f1749943d3 Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 15:34:01 +0100 Subject: [PATCH 10/15] Fix included double quote in en.yaml --- app/src/main/assets/data-contracts/en.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index 2b10f075..5c886bbe 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -55,7 +55,7 @@ conjugations: sectionTitle: Future tenses: 1: - tenseTitle": Fut. Simple + tenseTitle: Fut. Simple tenseForms: all: "[will] infinitive" 2: From 8dad75876ac76e94184da9bc6226fa136999a01e Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 23:11:50 +0100 Subject: [PATCH 11/15] Update version of data contracts with necessary fields --- app/src/main/assets/data-contracts/de.yaml | 494 ++++++++++++++++++++- app/src/main/assets/data-contracts/en.yaml | 83 +++- app/src/main/assets/data-contracts/es.yaml | 72 ++- app/src/main/assets/data-contracts/fr.yaml | 71 ++- app/src/main/assets/data-contracts/it.yaml | 70 ++- app/src/main/assets/data-contracts/pt.yaml | 70 ++- app/src/main/assets/data-contracts/ru.yaml | 153 ++++++- app/src/main/assets/data-contracts/sv.yaml | 71 ++- 8 files changed, 1066 insertions(+), 18 deletions(-) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index b4aac3a6..b47ffbe3 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -1,11 +1,26 @@ -numbers: - nominativeSingular: nominativePlural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + nominativeSingular: nominativePlural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Präsens @@ -19,6 +34,7 @@ conjugations: wir: indicativePresentFirstPersonPlural ihr: indicativePresentSecondPersonPlural sie/Sie: indicativePresentThirdPersonPlural + 2: sectionTitle: Preterite tenses: @@ -31,6 +47,7 @@ conjugations: wir: indicativePreteriteSecondPersonPlural ihr: indicativePreteriteThirdPersonSingular sie/Sie: indicativePreteriteThirdPersonPlural + 3: sectionTitle: Perfekt tenses: @@ -43,3 +60,476 @@ conjugations: wir: "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple" ihr: "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple" sie/Sie: "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Übersetzungsworttyp auswählen + + adjective: + displayValue: Adjektiv + sectionTitle: Adjektiv Übersetzung auswählen + + adverb: + displayValue: Adverb + sectionTitle: Adjektiv Übersetzung auswählen + + article: + displayValue: Artikel + sectionTitle: Artikel Übersetzung auswählen + + conjunction: + displayValue: Konjunktion + sectionTitle: Konjunktion Übersetzung auswählen + + noun: + displayValue: Nomen + sectionTitle: Nomen Übersetzung auswählen + + postposition: + displayValue: Postposition + sectionTitle: Postposition Übersetzung auswählen + + preposition: + displayValue: Preposition + sectionTitle: Preposition Übersetzung auswählen + + proper_noun: + displayValue: Eigenname + sectionTitle: Eigenname Übersetzung auswählen + + pronoun: + displayValue: Pronomen + sectionTitle: Pronomen Übersetzung auswählen + + verb: + displayValue: Verb + sectionTitle: Verb Übersetzung auswählen + +# MARK: Decline + +# Map of pronoun declensions given cases. +declensions: + 1: + sectionTitle: Akkusativ Definitpronomen + declensionForms: + M: den + F: die + N: das + PL: die + + 2: + sectionTitle: Akkusativ Indefinitpronomen + declensionForms: + M: einen + F: eine + N: ein + PL: welche + + 3: + sectionTitle: Akkusativ Personalpronomen + declensionForms: + ich: mich + + du/Sie: + title: Formalität des Subjekts? + declensionForms: + informell: dich + formell: Sie + + er/sie/es: + title: Geschlecht des Subjekts? + declensionForms: + er: ihn + sie: sie + es: es + + wir: uns + + ihr: euch + + sie: sie + + 4: + sectionTitle: Akkusativ Possessivpronomen + declensionForms: + ich: + displayValue: mein* + title: Geschlecht des Objekts? + declensionForms: + M: meinen + F: meine + N: mein + PL: meine + + du/Sie: + displayValue: dein*/Ihr* + title: Formalität des Subjekts? + declensionForms: + informell: + displayValue: dein* + title: Geschlecht des Objekts? + declensionForms: + M: deinen + F: deine + N: dein + PL: deine + + formell: + displayValue: Ihr* + title: Geschlecht des Objekts? + declensionForms: + M: Ihren + F: Ihre + N: Ihr + PL: Ihre + + er/sie/es: + displayValue: sein*/ihr*/sein* + title: Geschlecht des Subjekts? + declensionForms: + er: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seinen + F: seine + N: sein + PL: seine + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihren + F: ihre + N: ihr + PL: ihre + + es: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seinen + F: seine + N: sein + PL: seine + + wir: + displayValue: unser* + title: Geschlecht des Objekts? + declensionForms: + M: unsren + F: unsre + N: unser + PL: unsre + + ihr: + displayValue: euer* + title: Geschlecht des Objekts? + declensionForms: + M: euren + F: eure + N: euer + PL: eure + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihren + F: ihre + N: ihr + PL: ihre + + 5: + sectionTitle: Akkusativ Demonstrativpronomen + declensionForms: + M: diesen + F: diese + N: dieses + PL: diese + + 6: + sectionTitle: Dativ Definitpronomen + declensionForms: + M: dem + F: der + N: dem + PL: den + + 7: + sectionTitle: Dativ Indefinitpronomen + declensionForms: + M: einem + F: einer + N: einem + PL: welchen + + 8: + sectionTitle: Dativ Personalpronomen + declensionForms: + ich: mir + + du/Sie: + title: Formalität des Subjekts? + declensionForms: + informell: dir + formell: Ihnen + + er/sie/es: + title: Geschlecht des Subjekts? + declensionForms: + er: ihm + sie: ihr + es: ihm + + wir: uns + + ihr: euch + + sie: ihnen + + 9: + sectionTitle: Dativ Possessivpronomen + declensionForms: + ich: + displayValue: mein* + title: Geschlecht des Objekts? + declensionForms: + M: meinem + F: meiner + N: meinem + PL: meinen + + du/Sie: + displayValue: dein*/Ihr* + title: Formalität des Subjekts? + declensionForms: + informell: + displayValue: dein* + title: Geschlecht des Objekts? + declensionForms: + M: deinem + F: deiner + N: deinem + PL: deinen + + formell: + displayValue: Ihr* + title: Geschlecht des Objekts? + declensionForms: + M: Ihrem + F: Ihrer + N: Ihrem + PL: Ihren + + er/sie/es: + displayValue: sein*/ihr*/sein* + title: Geschlecht des Subjekts? + declensionForms: + er: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seinem + F: seiner + N: seinem + PL: seinen + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihrem + F: ihrer + N: ihrem + PL: ihren + + es: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seinem + F: seiner + N: seinem + PL: seinen + + wir: + displayValue: unser* + title: Geschlecht des Objekts? + declensionForms: + M: unsrem + F: unsrer + N: unsrem + PL: unsren + + ihr: + displayValue: euer* + title: Geschlecht des Objekts? + declensionForms: + M: eurem + F: eurer + N: eurem + PL: euren + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihrem + F: ihrer + N: ihrem + PL: ihren + + 10: + sectionTitle: Dativ Demonstrativpronomen + declensionForms: + M: diesem + F: dieser + N: diesem + PL: diesen + + 11: + sectionTitle: Genitiv Definitpronomen + declensionForms: + M: des + F: der + N: des + PL: der + + 12: + sectionTitle: Genitiv Indefinitpronomen + declensionForms: + M: eines + F: einer + N: eines + PL: welcher + + 13: + sectionTitle: Genitiv Personalpronomen + declensionForms: + ich: meiner + + du/Sie: + title: Formalität des Subjekts? + declensionForms: + informell: deiner + formell: Ihrer + + er/sie/es: + title: Geschlecht des Subjekts? + declensionForms: + er: seiner + sie: ihrer + es: seiner + + wir: unser + + ihr: euer + + sie: ihrer + + 14: + sectionTitle: Genitiv Possessivpronomen + declensionForms: + ich: + displayValue: mein* + title: Geschlecht des Objekts? + declensionForms: + M: meines + F: meiner + N: meines + PL: meiner + + du/Sie: + displayValue: dein*/Ihr* + title: Formalität des Subjekts? + declensionForms: + informell: + displayValue: dein* + title: Geschlecht des Objekts? + declensionForms: + M: deines + F: deiner + N: deines + PL: deiner + + formell: + displayValue: Ihr* + title: Geschlecht des Objekts? + declensionForms: + M: Ihres + F: Ihrer + N: Ihres + PL: Ihrer + + er/sie/es: + displayValue: sein*/ihr*/sein* + title: Geschlecht des Subjekts? + declensionForms: + er: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seines + F: seiner + N: seines + PL: seiner + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihres + F: ihr + N: ihres + PL: ihr + + es: + displayValue: sein* + title: Geschlecht des Objekts? + declensionForms: + M: seines + F: seiner + N: seines + PL: seiner + + wir: + displayValue: unser* + title: Geschlecht des Objekts? + declensionForms: + M: unsres + F: unsrer + N: unsres + PL: unsrer + + ihr: + displayValue: euer* + title: Geschlecht des Objekts? + declensionForms: + M: eures + F: eurer + N: eures + PL: eurer + + sie: + displayValue: ihr* + title: Geschlecht des Objekts? + declensionForms: + M: ihres + F: ihrer + N: ihres + PL: ihrer + + 15: + sectionTitle: Genitiv Demonstrativpronomen + declensionForms: + M: dieses + F: dieser + N: dieses + PL: dieser diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index 5c886bbe..9e281174 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -1,11 +1,26 @@ -numbers: - singular: plural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + singular: plural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Present @@ -15,22 +30,26 @@ conjugations: tenseForms: I/you/plural: simplePresent he/she/it: simplePresentThirdPersonSingular + 2: tenseTitle: Pr. Perfect tenseForms: I/you/plural: "[have] pastParticiple" he/she/it: "[has] pastParticiple" + 3: tenseTitle: Pr. Continuous tenseForms: I: "[am] presentParticiple" you/plural: "[are] presentParticiple" he/she/it: "[is] presentParticiple" + 4: tenseTitle: Pr. Perf. Continuous tenseForms: I/you/plural: "[have been] presentParticiple" he/she/it: "[has been] presentParticiple" + 2: sectionTitle: Past tenses: @@ -38,19 +57,23 @@ conjugations: tenseTitle: Past Simple tenseForms: all: simplePast + 2: tenseTitle: Past Perfect tenseForms: all: "[had] pastParticiple" + 3: tenseTitle: Past Continuous tenseForms: I/he/she/it: "[was] presentParticiple" you/plural: "[were] presentParticiple" + 4: tenseTitle: Past Perf. Continuous tenseForms: all: "[had been] presentParticiple" + 3: sectionTitle: Future tenses: @@ -58,18 +81,22 @@ conjugations: tenseTitle: Fut. Simple tenseForms: all: "[will] infinitive" + 2: tenseTitle: Fut. Perfect tenseForms: all: "[will have] pastParticiple" + 3: tenseTitle: Fut. Continuous tenseForms: all: "[will be] presentParticiple" + 4: tenseTitle: Fut. Perf. Continuous tenseForms: all: "[will have been] presentParticiple" + 4: sectionTitle: Conditional tenses: @@ -77,15 +104,67 @@ conjugations: tenseTitle: Cond. Simple tenseForms: all: "[would] infinitive" + 2: tenseTitle: Cond. Perfect tenseForms: all: "[would have] pastParticiple" + 3: tenseTitle: Cond. Continuous tenseForms: all: "[would be] presentParticiple" + 4: tenseTitle: Cond. Perf. Continuous tenseForms: all: "[would have been] presentParticiple" + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Select translation word type + + adjective: + displayValue: adjective + sectionTitle: Select adjective translation + + adverb: + displayValue: adverb + sectionTitle: Select adverb translation + + article: + displayValue: article + sectionTitle: Select article translation + + conjunction: + displayValue: conjunction + sectionTitle: Select conjunction translation + + noun: + displayValue: noun + sectionTitle: Select noun translation + + postposition: + displayValue: postposition + sectionTitle: Select postposition translation + + preposition: + displayValue: preposition + sectionTitle: Select preposition translation + + proper_noun: + displayValue: proper noun + sectionTitle: Select proper noun translation + + pronoun: + displayValue: pronoun + sectionTitle: Select pronoun translation + + verb: + displayValue: verb + sectionTitle: Select verb infinitive diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml index 40de86ec..8634c04c 100644 --- a/app/src/main/assets/data-contracts/es.yaml +++ b/app/src/main/assets/data-contracts/es.yaml @@ -1,12 +1,27 @@ -numbers: - feminineSingular: femininePlural - masculineSingular: masculinePlural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [] feminines: [feminineSingular] masculines: [masculineSingular] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + feminineSingular: femininePlural + masculineSingular: masculinePlural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Presente @@ -20,6 +35,7 @@ conjugations: nosotros: indicativePresentSecondPersonPlural vosotros: indicativePresentThirdPersonSingular ellos/ellas/Uds.: indicativePresentThirdPersonPlural + 2: sectionTitle: Pretérito tenses: @@ -32,6 +48,7 @@ conjugations: nosotros: preteriteSecondPersonPlural vosotros: preteriteThirdPersonSingular ellos/ellas/Uds.: preteriteThirdPersonPlural + 3: sectionTitle: Imperfecto tenses: @@ -44,3 +61,52 @@ conjugations: nosotros: pastImperfectSecondPersonPlural vosotros: pastImperfectThirdPersonSingular ellos/ellas/Uds.: pastImperfectThirdPersonPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Seleccione el tipo de traducción + + adjective: + displayValue: adjetivo + sectionTitle: Seleccione traducción de adjetivo + + adverb: + displayValue: adverbio + sectionTitle: Seleccione traducción de adverbio + + article: + displayValue: artículo + sectionTitle: Seleccione traducción de artículo + + conjunction: + displayValue: conjunción + sectionTitle: Seleccione traducción de conjunción + + noun: + displayValue: sustantivo + sectionTitle: Seleccione traducción de sustantivo + + postposition: + displayValue: posposición + sectionTitle: Seleccione traducción de posposición + + preposition: + displayValue: preposición + sectionTitle: Seleccione traducción de preposición + + proper_noun: + displayValue: nombre propio + sectionTitle: Seleccione traducción de nombre propio + + pronoun: + displayValue: pronombre + sectionTitle: Seleccione traducción de pronombre + + verb: + displayValue: verbo + sectionTitle: Seleccionar verbo infinitivo diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml index 704148f5..d03529ad 100644 --- a/app/src/main/assets/data-contracts/fr.yaml +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -1,11 +1,26 @@ -numbers: - singular: plural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + singular: plural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Présent @@ -19,6 +34,7 @@ conjugations: nous: indicativePresentSecondPersonPlural vous: indicativePresentThirdPersonSingular ils/elles: indicativePresentThirdPersonPlural + 2: sectionTitle: Passé simple tenses: @@ -31,6 +47,7 @@ conjugations: nous: indicativePreteriteSecondPersonPlural vous: indicativePreteriteThirdPersonSingular ils/elles: indicativePreteriteThirdPersonPlural + 3: sectionTitle: Imparfait tenses: @@ -43,6 +60,7 @@ conjugations: nous: indicativeImperfectSecondPersonPlural vous: indicativeImperfectThirdPersonSingular ils/elles: indicativeImperfectThirdPersonPlural + 4: sectionTitle: Futur tenses: @@ -55,3 +73,52 @@ conjugations: nous: indicativeSimpleFutureSecondPersonPlural vous: indicativeSimpleFutureThirdPersonSingular ils/elles: indicativeSimpleFutureThirdPersonPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Sélectionnez le type à traduire + + adjective: + displayValue: adjectif + sectionTitle: Sélectionner la traduction de l'adjectif + + adverb: + displayValue: adverbe + sectionTitle: Sélectionner la traduction de l'adverbe + + article: + displayValue: article + sectionTitle: Sélectionner la traduction de l'article + + conjunction: + displayValue: conjonction + sectionTitle: Sélectionner la traduction de conjonction + + noun: + displayValue: nom + sectionTitle: Sélectionner la traduction du nom + + postposition: + displayValue: postposition + sectionTitle: Sélectionnez la traduction de la postposition + + preposition: + displayValue: préposition + sectionTitle: Sélectionnez la traduction de la préposition + + proper_noun: + displayValue: nom propre + sectionTitle: Sélectionnez la traduction du nom propre + + pronoun: + displayValue: pronom + sectionTitle: Sélectionner la traduction des pronoms + + verb: + displayValue: verbe + sectionTitle: Sélectionnez l'infinitif du verbe diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml index 3a002283..cabe3463 100644 --- a/app/src/main/assets/data-contracts/it.yaml +++ b/app/src/main/assets/data-contracts/it.yaml @@ -1,11 +1,26 @@ -numbers: - singular: plural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + singular: plural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Presente @@ -19,6 +34,7 @@ conjugations: noi: presentIndicativeSecondPersonPlural voi: presentIndicativeThirdPersonSingular loro: presentIndicativeThirdPersonPlural + 2: sectionTitle: Preterito tenses: @@ -31,6 +47,7 @@ conjugations: noi: preteriteSecondPersonPlural voi: preteriteThirdPersonSingular loro: preteriteThirdPersonPlural + 3: sectionTitle: Imperfetto tenses: @@ -43,3 +60,52 @@ conjugations: noi: pastImperfectSecondPersonPlural voi: pastImperfectThirdPersonSingular loro: pastImperfectThirdPersonPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Seleziona il tipo da tradurre + + adjective: + displayValue: aggettivo + sectionTitle: Seleziona la traduzione dell'aggettivo + + adverb: + displayValue: avverbio + sectionTitle: Seleziona la traduzione dell'avverbio + + article: + displayValue: articolo + sectionTitle: Seleziona la traduzione dell'articolo + + conjunction: + displayValue: congiunzione + sectionTitle: Seleziona la traduzione della congiunzione + + noun: + displayValue: nome + sectionTitle: Seleziona la traduzione del nome + + postposition: + displayValue: posposizione + sectionTitle: Seleziona la traduzione della posposizione + + preposition: + displayValue: preposizione + sectionTitle: Seleziona la traduzione della preposizione + + proper_noun: + displayValue: nome proprio + sectionTitle: Seleziona la traduzione del nome proprio + + pronoun: + displayValue: pronome + sectionTitle: Seleziona la traduzione del pronome + + verb: + displayValue: verbo + sectionTitle: Seleziona il verbo infinito diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml index 71be56f7..cfedac96 100644 --- a/app/src/main/assets/data-contracts/pt.yaml +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -1,12 +1,26 @@ +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). -numbers: - singular: plural +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + singular: plural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Presente @@ -20,6 +34,7 @@ conjugations: nós: indicativePresentSecondPersonPlural vós: indicativePresentThirdPersonSingular eles/elas/vocês: indicativePresentThirdPersonPlural + 2: sectionTitle: Pretérito Perfeito tenses: @@ -32,6 +47,7 @@ conjugations: nós: indicativePastPerfectSecondPersonPlural vós: indicativePastPerfectThirdPersonSingular eles/elas/vocês: indicativePastPerfectThirdPersonPlural + 3: sectionTitle: Pretérito Imperfeito tenses: @@ -44,6 +60,7 @@ conjugations: nós: indicativePastImperfectSecondPersonPlural vós: indicativePastImperfectThirdPersonSingular eles/elas/vocês: indicativePastImperfectThirdPersonPlural + 4: sectionTitle: Futuro Simples tenses: @@ -56,3 +73,52 @@ conjugations: nós: indicativePluperfectSecondPersonPlural vós: indicativePluperfectThirdPersonSingular eles/elas/vocês: indicativePluperfectThirdPersonPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Selecione o tipo a ser traduzida + + adjective: + displayValue: adjetivo + sectionTitle: Selecione a tradução do adjetivo + + adverb: + displayValue: advérbio + sectionTitle: Selecione a tradução do advérbio + + article: + displayValue: artigo + sectionTitle: Selecione a tradução do artigo + + conjunction: + displayValue: conjunção + sectionTitle: Selecione a tradução da conjunção + + noun: + displayValue: nome + sectionTitle: Selecione a tradução do substantivo + + postposition: + displayValue: posposição + sectionTitle: Selecione a tradução de posposição + + preposition: + displayValue: preposição + sectionTitle: Selecione a tradução da preposiçãon + + proper_noun: + displayValue: nome próprio + sectionTitle: Selecione a tradução do nome próprio + + pronoun: + displayValue: pronome + sectionTitle: Selecione a tradução do pronome + + verb: + displayValue: verbo + sectionTitle: Selecione o verbo no infinitivo diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 065dcffc..75f4c229 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -1,11 +1,26 @@ -numbers: - nominativeSingular: nominativePlural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + nominativeSingular: nominativePlural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Настоящее @@ -19,6 +34,7 @@ conjugations: мы: indicativePresentFirstPersonPlural вы: indicativePresentSecondPersonPlural они: indicativePresentThirdPersonPlural + 2: sectionTitle: Прошедшее tenses: @@ -29,3 +45,136 @@ conjugations: я/ты/он: masculineIndicativePast оно: neuterIndicativePast мы/вы/они: indicativePastPlural + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Выберите тип переводимого слова + + adjective: + displayValue: прилагательное + sectionTitle: Выберите перевод прилагательного + + adverb: + displayValue: наречие + sectionTitle: Выберите перевод наречия + + article: + displayValue: статья + sectionTitle: Выберите перевод статьи + + conjunction: + displayValue: соединение + sectionTitle: Выберите перевод союза + + noun: + displayValue: существительное + sectionTitle: Выберите перевод существительного + + postposition: + displayValue: послелог + sectionTitle: Выберите перевод послелога + + preposition: + displayValue: предлог + sectionTitle: Выберите перевод предлога + + proper_noun: + displayValue: имя собственное + sectionTitle: Выберите перевод имени собственного. + + pronoun: + displayValue: местоимение + sectionTitle: Выберите перевод местоимения + + verb: + displayValue: глагол + sectionTitle: Выберите инфинитив глагола + +# MARK: Decline + +# Map of pronoun declensions given cases. +declensions: + 1: + title: Винительные местоимения + declensionForms: + я: меня + ты: тебя + он/она/оно: + displayValue: его/её/его + title: Пол объекта? + declensionForms: + он: его + она: её + оно: его + мы: нас + вы: вас + они: их + + 2: + title: Дательные местоимения + declensionForms: + я: мне + ты: тебе + он/она/оно: + displayValue: ему/ей/ему + title: Пол объекта? + declensionForms: + он: ему + она: ей + оно: ему + мы: нам + вы: вам + они: им + + 3: + title: Родительные местоимения + declensionForms: + я: меня + ты: тебя + он/она/оно: + displayValue: его/её/его + title: Пол объекта? + declensionForms: + он: его + она: её + оно: его + мы: нас + вы: вас + они: их + + 4: + title: Творительные местоимения + declensionForms": + я: мной + ты: тобой + он/она/оно: + displayValue: им/ей/им + title: Пол объекта? + declensionForms: + он: им + она: ей + оно: им + мы: нами + вы: вами + они: ими + + 5: + title: Предложные местоимения + declensionForms: + я: мне + ты": тебе + он/она/оно: + displayValue: нём/ней/нём + title: Пол объекта? + declensionForms: + он: нём + она: ней + оно: нём + мы: нас + вы: вас + они: них diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml index 44075b1e..179e62a3 100644 --- a/app/src/main/assets/data-contracts/sv.yaml +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -1,12 +1,27 @@ -numbers: - nominativeIndefiniteSingular: nominativeIndefinitePlural - nominativeDefiniteSingular: nominativeDefinitePlural +# Database column mappings that are read by Scribe applications to structure how data is displayed to the user. +# Includes interface titles and the order that values should be presented (chronological or alphabetical). + +# MARK: Noun Gender + +# A map of which columns in the nouns table depict its gender. genders: canonical: [gender] feminines: [] masculines: [] commons: [] neuters: [] + +# MARK: Plural + +# Key-value pairs that link the key of a noun singular to its plural for the Plural command. +numbers: + nominativeIndefiniteSingular: nominativeIndefinitePlural + nominativeDefiniteSingular: nominativeDefinitePlural + +# MARK: Conjugate + +# Map of verb tenses to their conjugations for the Conjugate command. +# Sections provide meta tense selections if there is more than one tense included. conjugations: 1: sectionTitle: Aktiv @@ -18,6 +33,7 @@ conjugations: presens: activePresent preteritum: activePreterite supinum: activeSupine + 2: sectionTitle: Passiv tenses: @@ -28,3 +44,52 @@ conjugations: presens: passivePresent preteritum: passivePreterite supinum: passiveSupine + +# MARK: Translate + +# Map of interface titles to display for the Translate command. +# Needed database columns are the same across languages (descriptions are labels for values). +# Note: Descriptions for article and pronoun translations are their genders. +translations: + wordType: + sectionTitle: Välj översättningsordtyp + + adjective: + displayValue: adjektiv + sectionTitle: Välj adjektivöversättning + + adverb: + displayValue: adverb + sectionTitle: Välj adverböversättning + + article: + displayValue: artikel + sectionTitle: Välj artikelöversättning + + conjunction: + displayValue: konjunktion + sectionTitle: Välj konjunktionsöversättning + + noun: + displayValue: substantiv + sectionTitle: Välj substantivöversättning + + postposition: + displayValue: postposition + sectionTitle: Välj postpositionsöversättning + + preposition: + displayValue: preposition + sectionTitle: Välj prepositionsöversättning + + proper_noun: + displayValue: egennamn + sectionTitle: Välj egennamnöversättning + + pronoun: + displayValue: pronomen + sectionTitle: Välj pronomenöversättning + + verb: + displayValue: verb + sectionTitle: Välj verbinfinitiv From 17626a2c3f5e0718c600dd30ab32d028615b9974 Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 15 Feb 2026 23:40:47 +0100 Subject: [PATCH 12/15] Minor fix in comment in contracts --- app/src/main/assets/data-contracts/de.yaml | 2 +- app/src/main/assets/data-contracts/en.yaml | 2 +- app/src/main/assets/data-contracts/es.yaml | 2 +- app/src/main/assets/data-contracts/fr.yaml | 2 +- app/src/main/assets/data-contracts/it.yaml | 2 +- app/src/main/assets/data-contracts/pt.yaml | 2 +- app/src/main/assets/data-contracts/ru.yaml | 2 +- app/src/main/assets/data-contracts/sv.yaml | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/assets/data-contracts/de.yaml b/app/src/main/assets/data-contracts/de.yaml index b47ffbe3..efd00ac1 100644 --- a/app/src/main/assets/data-contracts/de.yaml +++ b/app/src/main/assets/data-contracts/de.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/en.yaml b/app/src/main/assets/data-contracts/en.yaml index 9e281174..ca4ce817 100644 --- a/app/src/main/assets/data-contracts/en.yaml +++ b/app/src/main/assets/data-contracts/en.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [] feminines: [] diff --git a/app/src/main/assets/data-contracts/es.yaml b/app/src/main/assets/data-contracts/es.yaml index 8634c04c..735a2bad 100644 --- a/app/src/main/assets/data-contracts/es.yaml +++ b/app/src/main/assets/data-contracts/es.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [] feminines: [feminineSingular] diff --git a/app/src/main/assets/data-contracts/fr.yaml b/app/src/main/assets/data-contracts/fr.yaml index d03529ad..69efd0c2 100644 --- a/app/src/main/assets/data-contracts/fr.yaml +++ b/app/src/main/assets/data-contracts/fr.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/it.yaml b/app/src/main/assets/data-contracts/it.yaml index cabe3463..42db0996 100644 --- a/app/src/main/assets/data-contracts/it.yaml +++ b/app/src/main/assets/data-contracts/it.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/pt.yaml b/app/src/main/assets/data-contracts/pt.yaml index cfedac96..2f6db0ba 100644 --- a/app/src/main/assets/data-contracts/pt.yaml +++ b/app/src/main/assets/data-contracts/pt.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 75f4c229..43694e7f 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] diff --git a/app/src/main/assets/data-contracts/sv.yaml b/app/src/main/assets/data-contracts/sv.yaml index 179e62a3..c37972ef 100644 --- a/app/src/main/assets/data-contracts/sv.yaml +++ b/app/src/main/assets/data-contracts/sv.yaml @@ -3,7 +3,7 @@ # MARK: Noun Gender -# A map of which columns in the nouns table depict its gender. +# A map of which columns in the nouns table contain gender information. genders: canonical: [gender] feminines: [] From 430c0583d93f33299efeb85cefb326cc5a011f63 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Mon, 16 Feb 2026 14:57:19 +0700 Subject: [PATCH 13/15] feat: change to using YAML for data contract --- app/build.gradle.kts | 1 + .../scri/helpers/data/ConjugateDataManager.kt | 24 +++++----- .../scri/helpers/data/ContractDataLoader.kt | 24 ++++++---- .../scri/helpers/data/PluralFormsManager.kt | 12 ++--- .../main/java/be/scri/models/DataContract.kt | 47 +++++++++++++++++-- 5 files changed, 75 insertions(+), 33 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index badfeeca..40876295 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -325,6 +325,7 @@ dependencies { ksp("com.github.bumptech.glide:ksp:4.16.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") + implementation("com.charleskorn.kaml:kaml:0.57.0") } tasks.register("moveFromi18n") { diff --git a/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt b/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt index d0678fba..159f344f 100644 --- a/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt +++ b/app/src/main/java/be/scri/helpers/data/ConjugateDataManager.kt @@ -20,7 +20,7 @@ class ConjugateDataManager( * The returned map is structured by tense/mood, then by conjugation type (e.g., "Indicative Present"). * * @param language The language code (e.g., "EN", "SV") to determine the correct database. - * @param jsonData The data contract for the language, which defines the structure of conjugations. + * @param yamlData The data contract for the language, which defines the structure of conjugations. * @param word The specific verb to look up conjugations for. * * @return A nested map where the outer key is the tense group title @@ -29,20 +29,20 @@ class ConjugateDataManager( */ fun getTheConjugateLabels( language: String, - jsonData: DataContract?, + yamlData: DataContract?, word: String, ): MutableMap>>? { val finalOutput: MutableMap>> = mutableMapOf() - jsonData?.conjugations?.values?.forEach { tenseGroup -> + yamlData?.conjugations?.values?.forEach { tenseGroup -> val conjugateForms: MutableMap> = mutableMapOf() - tenseGroup.conjugationTypes.values.forEach { conjugationCategory -> + tenseGroup.tenses.values.forEach { conjugationCategory -> val forms = - conjugationCategory.conjugationForms.values.map { form -> + conjugationCategory.tenseForms.values.map { form -> getTheValueForTheConjugateWord(word.lowercase(), form, language) } - conjugateForms[conjugationCategory.title] = forms + conjugateForms[conjugationCategory.tenseTitle] = forms } - finalOutput[tenseGroup.title] = conjugateForms + finalOutput[tenseGroup.sectionTitle] = conjugateForms } return if (finalOutput.isEmpty() || finalOutput.values.all { it.isEmpty() || it.values.all { forms -> forms.all { it.isEmpty() } } }) { null @@ -55,19 +55,19 @@ class ConjugateDataManager( * Extracts a unique set of all conjugation form keys (e.g., "1ps", "2ps", "participle") * from the data contract. * - * @param jsonData The data contract containing the conjugation structure. + * @param yamlData The data contract containing the conjugation structure. * @param word The base word, which is also added to the set. * * @return A `Set` of unique strings representing all possible conjugation form identifiers. */ fun extractConjugateHeadings( - jsonData: DataContract?, + yamlData: DataContract?, word: String, ): Set { val allFormKeys = mutableSetOf() - jsonData?.conjugations?.values?.forEach { tenseGroup -> - tenseGroup.conjugationTypes.values.forEach { conjugationCategory -> - allFormKeys.addAll(conjugationCategory.conjugationForms.keys) + yamlData?.conjugations?.values?.forEach { tenseGroup -> + tenseGroup.tenses.values.forEach { conjugationCategory -> + allFormKeys.addAll(conjugationCategory.tenseForms.keys) } } allFormKeys.add(word) diff --git a/app/src/main/java/be/scri/helpers/data/ContractDataLoader.kt b/app/src/main/java/be/scri/helpers/data/ContractDataLoader.kt index 085abc8b..9f6e3886 100644 --- a/app/src/main/java/be/scri/helpers/data/ContractDataLoader.kt +++ b/app/src/main/java/be/scri/helpers/data/ContractDataLoader.kt @@ -4,8 +4,9 @@ package be.scri.helpers.data import DataContract import android.content.Context import android.util.Log -import kotlinx.serialization.SerializationException -import kotlinx.serialization.json.Json +import com.charleskorn.kaml.Yaml +import com.charleskorn.kaml.YamlConfiguration +import com.charleskorn.kaml.YamlException import java.io.IOException /** @@ -16,29 +17,32 @@ class ContractDataLoader( private val context: Context, ) { /** - * Loads and deserializes a data contract from a JSON file in the assets folder. - * It gracefully handles file-not-found and JSON parsing errors by returning null. + * Loads and deserializes a data contract from a YAML file in the assets folder. + * It gracefully handles file-not-found and YAML parsing errors by returning null. * - * @param language The language code (e.g., "DE", "EN") used to determine the filename (e.g., "de.json"). + * @param language The language code (e.g., "DE", "EN") used to determine the filename (e.g., "de.yaml"). * * @return The decoded [DataContract] object if successful, or `null` * if the file does not exist or cannot be parsed. */ fun loadContract(language: String): DataContract? { - val contractName = "${language.lowercase()}.json" + val contractName = "${language.lowercase()}.yaml" Log.i("ContractDataLoader", "Attempting to load contract: $contractName") return try { - val jsonParser = Json { ignoreUnknownKeys = true } context.assets.open("data-contracts/$contractName").use { contractFile -> val content = contractFile.bufferedReader().readText() - jsonParser.decodeFromString(content) + val yaml = + Yaml( + configuration = YamlConfiguration(strictMode = false), + ) + yaml.decodeFromString(DataContract.serializer(), content) } } catch (e: IOException) { Log.e("ContractDataLoader", "Error loading contract file: $contractName. It may not exist.", e) null - } catch (e: SerializationException) { - Log.e("ContractDataLoader", "Error parsing JSON for contract: $contractName", e) + } catch (e: YamlException) { + Log.e("ContractDataLoader", "Error parsing YAML for contract: $contractName", e) null } } diff --git a/app/src/main/java/be/scri/helpers/data/PluralFormsManager.kt b/app/src/main/java/be/scri/helpers/data/PluralFormsManager.kt index eb1c4d0a..0d4b84f2 100644 --- a/app/src/main/java/be/scri/helpers/data/PluralFormsManager.kt +++ b/app/src/main/java/be/scri/helpers/data/PluralFormsManager.kt @@ -17,16 +17,16 @@ class PluralFormsManager( * Retrieves a list of all known plural forms for a given language from the database. * * @param language The language code (e.g., "EN", "DE") to select the correct database. - * @param jsonData The data contract, which specifies the names of the columns containing plural forms. + * @param yamlData The data contract, which specifies the names of the columns containing plural forms. * * @return A [List] of all plural word forms, or `null` * if the operation fails or no plural columns are defined. */ fun getAllPluralForms( language: String, - jsonData: DataContract?, + yamlData: DataContract?, ): List? = - jsonData?.numbers?.values?.toList()?.takeIf { it.isNotEmpty() }?.let { pluralForms -> + yamlData?.numbers?.values?.toList()?.takeIf { it.isNotEmpty() }?.let { pluralForms -> fileManager.getLanguageDatabase(language)?.use { db -> queryAllPluralForms(db, pluralForms) } @@ -36,7 +36,7 @@ class PluralFormsManager( * Retrieves the specific plural representation for a single noun. * * @param language The language code to select the correct database. - * @param jsonData The data contract, which specifies the singular and plural column names. + * @param yamlData The data contract, which specifies the singular and plural column names. * @param noun The singular noun to find the plural for. * * @return A [Map] containing the singular noun as the key and @@ -44,10 +44,10 @@ class PluralFormsManager( */ fun getPluralRepresentation( language: String, - jsonData: DataContract?, + yamlData: DataContract?, noun: String, ): Map = - jsonData?.numbers?.let { numbers -> + yamlData?.numbers?.let { numbers -> val singularCol = numbers.keys.firstOrNull() val pluralCol = numbers.values.firstOrNull() diff --git a/app/src/main/java/be/scri/models/DataContract.kt b/app/src/main/java/be/scri/models/DataContract.kt index 6a4015d8..2241026f 100644 --- a/app/src/main/java/be/scri/models/DataContract.kt +++ b/app/src/main/java/be/scri/models/DataContract.kt @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later @file:Suppress("ktlint:standard:kdoc") +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable /** @@ -13,7 +14,8 @@ import kotlinx.serialization.Serializable data class DataContract( val numbers: Map, val genders: Genders, - val conjugations: Map, + val conjugations: Map, + val translations: Translations, ) /** @@ -33,8 +35,8 @@ data class Genders( */ @Serializable data class TenseGroup( - val title: String = "", - val conjugationTypes: Map, + val sectionTitle: String = "", + val tenses: Map, ) /** @@ -42,6 +44,41 @@ data class TenseGroup( */ @Serializable data class ConjugationCategory( - val title: String = "", - val conjugationForms: Map = emptyMap(), + val tenseTitle: String = "", + val tenseForms: Map = emptyMap(), +) + +/** + * Represents the structure of translations for different word types. + */ +@Serializable +data class Translations( + val wordType: WordType, +) + +/** + * Represents the various parts of speech and their associated display values and section titles. + */ +@Serializable +data class WordType( + val sectionTitle: String, + val adjective: WordTypeEntry, + val adverb: WordTypeEntry, + val article: WordTypeEntry, + val conjunction: WordTypeEntry, + val noun: WordTypeEntry, + val postposition: WordTypeEntry, + val preposition: WordTypeEntry, + @SerialName("proper_noun") val properNoun: WordTypeEntry, + val pronoun: WordTypeEntry, + val verb: WordTypeEntry, +) + +/** + * Represents the display value and section title for a specific part of speech. + */ +@Serializable +data class WordTypeEntry( + val displayValue: String, + val sectionTitle: String, ) From 8d0d37038c24b3ba226a27a0438a0caddf1ddca1 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Mon, 16 Feb 2026 15:16:39 +0700 Subject: [PATCH 14/15] remove json contracts --- app/build.gradle.kts | 1 - app/src/main/assets/data-contracts/de.json | 64 ---------- app/src/main/assets/data-contracts/en.json | 136 --------------------- app/src/main/assets/data-contracts/es.json | 66 ---------- app/src/main/assets/data-contracts/fr.json | 78 ------------ app/src/main/assets/data-contracts/it.json | 64 ---------- app/src/main/assets/data-contracts/pt.json | 80 ------------ app/src/main/assets/data-contracts/ru.json | 44 ------- app/src/main/assets/data-contracts/sv.json | 43 ------- 9 files changed, 576 deletions(-) delete mode 100644 app/src/main/assets/data-contracts/de.json delete mode 100644 app/src/main/assets/data-contracts/en.json delete mode 100644 app/src/main/assets/data-contracts/es.json delete mode 100644 app/src/main/assets/data-contracts/fr.json delete mode 100644 app/src/main/assets/data-contracts/it.json delete mode 100644 app/src/main/assets/data-contracts/pt.json delete mode 100644 app/src/main/assets/data-contracts/ru.json delete mode 100644 app/src/main/assets/data-contracts/sv.json diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 40876295..ede0a79c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -323,7 +323,6 @@ dependencies { api("com.google.code.gson:gson:2.13.1") api("com.github.bumptech.glide:glide:4.16.0") ksp("com.github.bumptech.glide:ksp:4.16.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.1") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2") implementation("com.charleskorn.kaml:kaml:0.57.0") } diff --git a/app/src/main/assets/data-contracts/de.json b/app/src/main/assets/data-contracts/de.json deleted file mode 100644 index 05180f58..00000000 --- a/app/src/main/assets/data-contracts/de.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "numbers": { - "nominativeSingular": "nominativePlural" - }, - "genders": { - "canonical": [ - "gender" - ], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Präsens", - "conjugationTypes": { - "1": { - "title": "Präsens", - "conjugationForms": { - "ich": "indicativePresentFirstPersonSingular", - "du": "indicativePresentSecondPersonSingular", - "er/sie/es": "indicativePresentThirdPersonSingular", - "wir": "indicativePresentFirstPersonPlural", - "ihr": "indicativePresentSecondPersonPlural", - "sie/Sie": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Preterite", - "conjugationTypes": { - "1": { - "title": "Preterite", - "conjugationForms": { - "ich": "indicativePreteriteFirstPersonSingular", - "du": "indicativePreteriteFirstPersonPlural", - "er/sie/es": "indicativePreteriteSecondPersonSingular", - "wir": "indicativePreteriteSecondPersonPlural", - "ihr": "indicativePreteriteThirdPersonSingular", - "sie/Sie": "indicativePreteriteThirdPersonPlural" - } - } - } - }, - "3": { - "title": "Perfekt", - "conjugationTypes": { - "1": { - "title": "Perfekt", - "conjugationForms": { - "ich": "[indicativePresentFirstPersonSingular auxiliaryVerb] pastParticiple", - "du": "[indicativePresentSecondPersonSingular auxiliaryVerb] pastParticiple", - "er/sie/es": "[indicativePresentThirdPersonSingular auxiliaryVerb] pastParticiple", - "wir": "[indicativePresentFirstPersonPlural auxiliaryVerb] pastParticiple", - "ihr": "[indicativePresentSecondPersonPlural auxiliaryVerb] pastParticiple", - "sie/Sie": "[indicativePresentThirdPersonPlural auxiliaryVerb] pastParticiple" - } - } - } - } - } -} diff --git a/app/src/main/assets/data-contracts/en.json b/app/src/main/assets/data-contracts/en.json deleted file mode 100644 index 2eaa5946..00000000 --- a/app/src/main/assets/data-contracts/en.json +++ /dev/null @@ -1,136 +0,0 @@ -{ - "numbers": { - "singular": "plural" - }, - "genders": { - "canonical": [], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Present", - "conjugationTypes": { - "1": { - "title": "Pr. Simple", - "conjugationForms": { - "I/you/plural": "simplePresent", - "he/she/it": "simplePresentThirdPersonSingular" - } - }, - "2": { - "title": "Pr. Perfect", - "conjugationForms": { - "I/you/plural": "[have] pastParticiple", - "he/she/it": "[has] pastParticiple" - } - }, - "3": { - "title": "Pr. Continuous", - "conjugationForms": { - "I": "[am] presentParticiple", - "you/plural": "[are] presentParticiple", - "he/she/it": "[is] presentParticiple" - } - }, - "4": { - "title": "Pr. Perf. Continuous", - "conjugationForms": { - "I/you/plural": "[have been] presentParticiple", - "he/she/it": "[has been] presentParticiple" - } - } - } - }, - "2": { - "title": "Past", - "conjugationTypes": { - "1": { - "title": "Past Simple", - "conjugationForms": { - "all": "simplePast" - } - }, - "2": { - "title": "Past Perfect", - "conjugationForms": { - "all": "[had] pastParticiple" - } - }, - "3": { - "title": "Past Continuous", - "conjugationForms": { - "I/he/she/it": "[was] presentParticiple", - "you/plural": "[were] presentParticiple" - } - }, - "4": { - "title": "Past Perf. Continuous", - "conjugationForms": { - "all": "[had been] presentParticiple" - } - } - } - }, - "3": { - "title": "Future", - "conjugationTypes": { - "1": { - "title": "Fut. Simple", - "conjugationForms": { - "all": "[will] infinitive" - } - }, - "2": { - "title": "Fut. Perfect", - "conjugationForms": { - "all": "[will have] pastParticiple" - } - }, - "3": { - "title": "Fut. Continuous", - "conjugationForms": { - "all": "[will be] presentParticiple" - } - }, - "4": { - "title": "Fut. Perf. Continuous", - "conjugationForms": { - "all": "[will have been] presentParticiple" - } - } - } - }, - "4": { - "title": "Conditional", - "conjugationTypes": { - "1": { - "title": "Cond. Simple", - "conjugationForms": { - "all": "[would] infinitive" - } - }, - "2": { - "title": "Cond. Perfect", - "conjugationForms": { - "all": "[would have] pastParticiple" - } - }, - "3": { - "title": "Cond. Continuous", - "conjugationForms": { - "all": "[would be] presentParticiple" - } - }, - "4": { - "title": "Cond. Perf. Continuous", - "conjugationForms": { - "all": "[would have been] presentParticiple" - } - } - } - } - } -} \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/es.json b/app/src/main/assets/data-contracts/es.json deleted file mode 100644 index 63ec1131..00000000 --- a/app/src/main/assets/data-contracts/es.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "numbers": { - "feminineSingular": "femininePlural", - "masculineSingular": "masculinePlural" - }, - "genders": { - "canonical": [], - "feminines": ["feminineSingular"], - "masculines": ["masculineSingular"], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "yo": "indicativePresentFirstPersonSingular", - "tú": "indicativePresentFirstPersonPlural", - "él/ella/Ud.": "indicativePresentSecondPersonSingular", - "nosotros": "indicativePresentSecondPersonPlural", - "vosotros": "indicativePresentThirdPersonSingular", - "ellos/ellas/Uds.": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Pretérito", - "conjugationTypes": { - "1": { - "title": "Pretérito", - "conjugationForms": { - "yo": "preteriteFirstPersonSingular", - "tú": "preteriteFirstPersonPlural", - "él/ella/Ud.": "preteriteSecondPersonSingular", - "nosotros": "preteriteSecondPersonPlural", - "vosotros": "preteriteThirdPersonSingular", - "ellos/ellas/Uds.": "preteriteThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Imperfecto", - "conjugationTypes" : { - "1": { - "title": "Imperfecto", - "conjugationForms": { - "yo": "pastImperfectFirstPersonSingular", - "tú": "pastImperfectFirstPersonPlural", - "él/ella/Ud.": "pastImperfectSecondPersonSingular", - "nosotros": "pastImperfectSecondPersonPlural", - "vosotros": "pastImperfectThirdPersonSingular", - "ellos/ellas/Uds.": "pastImperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/fr.json b/app/src/main/assets/data-contracts/fr.json deleted file mode 100644 index 44833124..00000000 --- a/app/src/main/assets/data-contracts/fr.json +++ /dev/null @@ -1,78 +0,0 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Présent", - "conjugationTypes": { - "1": { - "title": "Présent", - "conjugationForms": { - "je": "indicativePresentFirstPersonSingular", - "tu": "indicativePresentFirstPersonPlural", - "il/elle": "indicativePresentSecondPersonSingular", - "nous": "indicativePresentSecondPersonPlural", - "vous": "indicativePresentThirdPersonSingular", - "ils/elles": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Passé simple", - "conjugationTypes": { - "1": { - "title": "Passé simple", - "conjugationForms": { - "je": "indicativePreteriteFirstPersonSingular", - "tu": "indicativePreteriteFirstPersonPlural", - "il/elle": "indicativePreteriteSecondPersonSingular", - "nous": "indicativePreteriteSecondPersonPlural", - "vous": "indicativePreteriteThirdPersonSingular", - "ils/elles": "indicativePreteriteThirdPersonPlural" - } - } - } - }, - "3": { - "title": "Imparfait", - "conjugationTypes": { - "1": { - "title": "Imparfait", - "conjugationForms": { - "je": "indicativeImperfectFirstPersonSingular", - "tu": "indicativeImperfectFirstPersonPlural", - "il/elle": "indicativeImperfectSecondPersonSingular", - "nous": "indicativeImperfectSecondPersonPlural", - "vous": "indicativeImperfectThirdPersonSingular", - "ils/elles": "indicativeImperfectThirdPersonPlural" - } - } - } - - }, - "4": { - "title": "Futur", - "conjugationTypes":{ - "1": { - "title": "Futur", - "conjugationForms": { - "je": "indicativeSimpleFutureFirstPersonSingular", - "tu": "indicativeSimpleFutureFirstPersonPlural", - "il/elle": "indicativeSimpleFutureSecondPersonSingular", - "nous": "indicativeSimpleFutureSecondPersonPlural", - "vous": "indicativeSimpleFutureThirdPersonSingular", - "ils/elles": "indicativeSimpleFutureThirdPersonPlural" - } - } - } - } - } - } - \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/it.json b/app/src/main/assets/data-contracts/it.json deleted file mode 100644 index f30709b0..00000000 --- a/app/src/main/assets/data-contracts/it.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "io": "presentIndicativeFirstPersonSingular", - "tu": "presentIndicativeFirstPersonPlural", - "lei/lui": "presentIndicativeSecondPersonSingular", - "noi": "presentIndicativeSecondPersonPlural", - "voi": "presentIndicativeThirdPersonSingular", - "loro": "presentIndicativeThirdPersonPlural" - } - } - } - - }, - "2": { - "title": "Preterito", - "conjugationTypes": { - "1": { - "title": "Preterito", - "conjugationForms": { - "io": "preteriteFirstPersonSingular", - "tu": "preteriteFirstPersonPlural", - "lei/lui": "preteriteSecondPersonSingular", - "noi": "preteriteSecondPersonPlural", - "voi": "preteriteThirdPersonSingular", - "loro": "preteriteThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Imperfetto", - "conjugationTypes": { - "1": { - "title": "Imperfetto", - "conjugationForms": { - "io": "pastImperfectFirstPersonSingular", - "tu": "pastImperfectFirstPersonPlural", - "lei/lui": "pastImperfectSecondPersonSingular", - "noi": "pastImperfectSecondPersonPlural", - "voi": "pastImperfectThirdPersonSingular", - "loro": "pastImperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/pt.json b/app/src/main/assets/data-contracts/pt.json deleted file mode 100644 index 7a3b55f3..00000000 --- a/app/src/main/assets/data-contracts/pt.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "numbers": { "singular": "plural" }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Presente", - "conjugationTypes": { - "1": { - "title": "Presente", - "conjugationForms": { - "eu": "indicativePresentFirstPersonSingular", - "tu": "indicativePresentFirstPersonPlural", - "ele/ela/você": "indicativePresentSecondPersonSingular", - "nós": "indicativePresentSecondPersonPlural", - "vós": "indicativePresentThirdPersonSingular", - "eles/elas/vocês": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Pretérito Perfeito", - "conjugationTypes": { -"1": { - "title": "Pretérito Perfeito", - "conjugationForms": { - "eu": "indicativePastPerfectFirstPersonSingular", - "tu": "indicativePastPerfectFirstPersonPlural", - "ele/ela/você": "indicativePastPerfectSecondPersonSingular", - "nós": "indicativePastPerfectSecondPersonPlural", - "vós": "indicativePastPerfectThirdPersonSingular", - "eles/elas/vocês": "indicativePastPerfectThirdPersonPlural" - } - } - } - - }, - "3": { - "title": "Pretérito Imperfeito", - "conjugationTypes": { -"1": { - "title": "Pretérito Imperfeito", - "conjugationForms": { - "eu": "indicativePastImperfectFirstPersonSingular", - "tu": "indicativePastImperfectFirstPersonPlural", - "ele/ela/você": "indicativePastImperfectSecondPersonSingular", - "nós": "indicativePastImperfectSecondPersonPlural", - "vós": "indicativePastImperfectThirdPersonSingular", - "eles/elas/vocês": "indicativePastImperfectThirdPersonPlural" - } - } - } - - }, - "4": { - "title": "Futuro Simples", - "conjugationTypes": { -"1": { - "title": "Futuro Simples", - "conjugationForms": { - "eu": "indicativePluperfectFirstPersonSingular", - "tu": "indicativePluperfectFirstPersonPlural", - "ele/ela/você": "indicativePluperfectSecondPersonSingular", - "nós": "indicativePluperfectSecondPersonPlural", - "vós": "indicativePluperfectThirdPersonSingular", - "eles/elas/vocês": "indicativePluperfectThirdPersonPlural" - } - } - } - - } - } - } - \ No newline at end of file diff --git a/app/src/main/assets/data-contracts/ru.json b/app/src/main/assets/data-contracts/ru.json deleted file mode 100644 index 1742fb91..00000000 --- a/app/src/main/assets/data-contracts/ru.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "numbers": { - "nominativeSingular": "nominativePlural" - }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Настоящее (Present)", - "conjugationTypes": { - "1": { - "title": "Indicative Present", - "conjugationForms": { - "я (I)": "indicativePresentFirstPersonSingular", - "ты (you, sing.)": "indicativePresentSecondPersonSingular", - "он/она/оно (he/she/it)": "indicativePresentThirdPersonSingular", - "мы (we)": "indicativePresentFirstPersonPlural", - "вы (you, pl.)": "indicativePresentSecondPersonPlural", - "они (they)": "indicativePresentThirdPersonPlural" - } - } - } - }, - "2": { - "title": "Прошедшее (Past)", - "conjugationTypes": { - "1": { - "title": "Indicative Past", - "conjugationForms": { - "я/ты/она (I/you/she, fem.)": "feminineIndicativePast", - "я/ты/он (I/you/he, masc.)": "masculineIndicativePast", - "оно (it, neut.)": "neuterIndicativePast", - "мы/вы/они (we/you/they)": "indicativePastPlural" - } - } - } - } - } -} diff --git a/app/src/main/assets/data-contracts/sv.json b/app/src/main/assets/data-contracts/sv.json deleted file mode 100644 index 6bdb2e62..00000000 --- a/app/src/main/assets/data-contracts/sv.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "numbers": { - "nominativeIndefiniteSingular": "nominativeIndefinitePlural", - "nominativeDefiniteSingular": "nominativeDefinitePlural" - }, - "genders": { - "canonical": ["gender"], - "feminines": [], - "masculines": [], - "commons": [], - "neuters": [] - }, - "conjugations": { - "1": { - "title": "Aktiv", - "conjugationTypes": { - "1": { - "title": "Aktiv", - "conjugationForms": { - "infinitiv": "activeInfinitive", - "presens": "activePresent", - "preteritum": "activePreterite", - "supinum": "activeSupine" - } - } - } - }, - "2": { - "title": "Passiv", - "conjugationTypes": { - "1": { - "title": "Passiv", - "conjugationForms": { - "infinitiv": "passiveInfinitive", - "presens": "passivePresent", - "preteritum": "passivePreterite", - "supinum": "passiveSupine" - } - } - } - } - } -} From 19e6fc755b63f56e8e9c2d8869e601429a10a483 Mon Sep 17 00:00:00 2001 From: Purnama S Rahayu Date: Mon, 16 Feb 2026 19:04:44 +0700 Subject: [PATCH 15/15] fix minor typo --- app/src/main/assets/data-contracts/ru.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/assets/data-contracts/ru.yaml b/app/src/main/assets/data-contracts/ru.yaml index 43694e7f..0677a4c4 100644 --- a/app/src/main/assets/data-contracts/ru.yaml +++ b/app/src/main/assets/data-contracts/ru.yaml @@ -149,7 +149,7 @@ declensions: 4: title: Творительные местоимения - declensionForms": + declensionForms: я: мной ты: тобой он/она/оно: @@ -167,7 +167,7 @@ declensions: title: Предложные местоимения declensionForms: я: мне - ты": тебе + ты: тебе он/она/оно: displayValue: нём/ней/нём title: Пол объекта?