diff --git a/README.md b/README.md index f9b6fc1f..ada577f8 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ The JSON import feature only supports JSON files created by the application. Scr > [!CAUTION] > Pre-release versions can be buggy. Some features may not work. You might even loose all your data. That's why they are only meant to be installed manually, after making a backup from the settings. -Pre-release versions of the application are available on [GitHub releases](https://github.com/maelchiotti/LocalMaterialNotes/releases). You can filter by pre-releases only by typing `prerelease:true` in the search box. +Pre-release versions of the application are available on [GitHub releases](https://github.com/maelchiotti/LocalMaterialNotes/releases?q=prerelease:true). You can filter by pre-releases only by typing `prerelease:true` in the search box. When using a pre-release version, please report any issue you encounter in the discussion linked to that pre-release. diff --git a/l10n.yaml b/l10n.yaml index 0c5f5f92..52c360f6 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -2,6 +2,7 @@ format: true use-escaping: true nullable-getter: false synthetic-package: false +required-resource-attributes: true arb-dir: lib/l10n/translations template-arb-file: app_en.arb diff --git a/lib/app.dart b/lib/app.dart index 2ab03430..0a717db6 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -5,9 +5,11 @@ import 'package:back_button_interceptor/back_button_interceptor.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; + import 'common/actions/labels/select.dart'; import 'common/actions/notes/select.dart'; import 'common/constants/constants.dart'; +import 'common/enums/localization_completion.dart'; import 'common/extensions/locale_extension.dart'; import 'common/widgets/placeholders/error_placeholder.dart'; import 'l10n/app_localizations/app_localizations.g.dart'; @@ -134,7 +136,7 @@ class _AppState extends ConsumerState with AfterLayoutMixin { darkTheme: darkTheme, themeMode: themeMode, localizationsDelegates: AppLocalizations.localizationsDelegates, - supportedLocales: AppLocalizations.supportedLocales, + supportedLocales: SupportedLanguage.locales, locale: LocaleUtils().appLocale, debugShowCheckedModeBanner: false, ), diff --git a/lib/common/enums/localization_completion.dart b/lib/common/enums/localization_completion.dart index e9ffa80b..e24bee22 100644 --- a/lib/common/enums/localization_completion.dart +++ b/lib/common/enums/localization_completion.dart @@ -1,8 +1,9 @@ import 'package:dart_helper_utils/dart_helper_utils.dart'; import 'package:flutter/material.dart'; +import 'package:locale_names/locale_names.dart'; -/// Lists the localization completion for every supported language. -enum LocalizationCompletion { +/// Languages supported by the application. +enum SupportedLanguage { /// Czech. cs(Locale('cs'), 1), @@ -38,23 +39,26 @@ enum LocalizationCompletion { /// Chinese Simplified. zh(Locale('zh'), 1), + + /// Chinese Traditional. + zhTW(Locale.fromSubtags(languageCode: 'zh', scriptCode: 'Hant'), 0), ; - /// The locale of this localization. + /// The locale completion of this language. final Locale locale; - /// The percentage of strings that are localized for this [locale]. - /// - /// The value is a double contained between 0 and 1. - final num percentage; + /// The translation completion of this language. + final num completion; + + /// A language supported by the application with its [locale] and its translation [completion]. + const SupportedLanguage(this.locale, this.completion); - /// The completion of the localization for the [locale] as a [percentage]. - const LocalizationCompletion(this.locale, this.percentage); + /// Returns the list of [locale] supported by the application. + static List locales = values.map((language) => language.locale).toList(); - /// Returns the percentage of strings that are localized for the [locale], formatted as a [String] for the [locale]. - static String getFormattedPercentage(Locale locale) { - final percentage = values.firstWhere((localizationSupport) => localizationSupport.locale == locale).percentage; + /// Returns the native name of this language. + String get nativeName => locale.nativeDisplayLanguage.capitalizeFirstLetter; - return percentage.formatAsPercentage(locale: locale.languageCode); - } + /// Returns the translation completion of this language formatted as a percentage according to the [locale]. + String get completionFormatted => completion.formatAsPercentage(locale: locale.languageCode); } diff --git a/lib/l10n/translations/app_de.arb b/lib/l10n/translations/app_de.arb index 831e0c2b..b827ec62 100644 --- a/lib/l10n/translations/app_de.arb +++ b/lib/l10n/translations/app_de.arb @@ -77,6 +77,10 @@ "@navigation_settings_appearance": { "description": "Title of the settings page regarding the application's appearance." }, + "navigation_settings_notes_tiles": "Notizkacheln", + "@navigation_settings_notes_tiles": { + "description": "Title of the settings page regarding the notes tiles appearance." + }, "navigation_settings_behavior": "Verhalten", "@navigation_settings_behavior": { "description": "Title of the settings page regarding the application's behavior." @@ -113,6 +117,10 @@ "@settings_page_appearance": { "description": "Title of the settings page regarding the application's appearance." }, + "settings_page_appearance_description": "Sprache, Aussehen, Schrift", + "@settings_page_appearance_description": { + "description": "Description of the appearance settings page." + }, "settings_language": "Sprache", "@settings_language": { "description": "Title of the language setting tile." @@ -177,6 +185,22 @@ "@settings_editor_font_description": { "description": "Description of the setting tile to choose the font of the app." }, + "settings_page_notes_tiles": "Notizkacheln", + "@settings_page_notes_tiles": { + "description": "Title of the settings page regarding the notes tiles." + }, + "settings_page_notes_tiles_description": "Aussehen, Inhalt", + "@settings_page_notes_tiles_description": { + "description": "Description of the notes tiles settings page." + }, + "settings_page_notes_tiles_appearance_section": "Aussehen", + "@settings_page_notes_tiles_appearance_section": { + "description": "Title of the section regarding the appearance under the notes tiles settings." + }, + "settings_page_notes_tiles_content_section": "Inhalt", + "@settings_page_notes_tiles_content_section": { + "description": "Title of the section regarding the content under the notes tiles settings." + }, "settings_show_tiles_background": "Hintergrund", "@settings_show_tiles_background": { "description": "Title of the setting tile to show the background of the notes tiles." @@ -209,6 +233,14 @@ "@settings_show_titles_only_disable_in_search_view_description": { "description": "Description of the setting tile to disable only showing the titles of the notes in the search view." }, + "settings_content_preview_max_lines": "Maximale Vorschauzeilen", + "@settings_content_preview_max_lines": { + "description": "Title of the setting tile to choose the maximum number of content preview lines to show." + }, + "settings_content_preview_max_lines_description": "Maximale Anzahl an Zeilen der Inhaltsvorschau", + "@settings_content_preview_max_lines_description": { + "description": "Description of the setting tile to choose the maximum number of content preview lines to show." + }, "settings_behavior": "Verhalten", "@settings_behavior": { "description": "Title of the settings page regarding the application's behavior." @@ -905,6 +937,10 @@ "@about_last_edited": { "description": "Date when the note was edited for the last time." }, + "about_type": "Typ", + "@about_type": { + "description": "Type of the note." + }, "about_created": "Erstellt", "@about_created": { "description": "Date when the note was created." @@ -992,5 +1028,13 @@ "font_system_default": "System Standard", "@font_system_default": { "description": "Name of the font settings that uses the default font of the system." + }, + "note_type_plain_text": "Unformatierter Text", + "@note_type_plain_text": { + "description": "Note with plain text." + }, + "note_type_rich_text": "Formatierter Text", + "@note_type_rich_text": { + "description": "Note with rich text." } } \ No newline at end of file diff --git a/lib/l10n/translations/app_it.arb b/lib/l10n/translations/app_it.arb index 14e2e96f..cb7a3c09 100644 --- a/lib/l10n/translations/app_it.arb +++ b/lib/l10n/translations/app_it.arb @@ -1032,5 +1032,9 @@ "note_type_plain_text": "Testo semplice", "@note_type_plain_text": { "description": "Note with plain text." + }, + "note_type_rich_text": "Rich text", + "@note_type_rich_text": { + "description": "Note with rich text." } } \ No newline at end of file diff --git a/lib/l10n/translations/app_zh-TW.arb b/lib/l10n/translations/app_zh-TW.arb new file mode 100644 index 00000000..9e26dfee --- /dev/null +++ b/lib/l10n/translations/app_zh-TW.arb @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/lib/pages/settings/pages/settings_appearance_page.dart b/lib/pages/settings/pages/settings_appearance_page.dart index 5377b969..37be8714 100644 --- a/lib/pages/settings/pages/settings_appearance_page.dart +++ b/lib/pages/settings/pages/settings_appearance_page.dart @@ -15,7 +15,6 @@ import '../../../common/navigation/top_navigation.dart'; import '../../../common/preferences/enums/font.dart'; import '../../../common/preferences/preference_key.dart'; import '../../../common/preferences/watched_preferences.dart'; -import '../../../l10n/app_localizations/app_localizations.g.dart'; import '../../../providers/preferences/preferences_provider.dart'; import '../../../utils/keys.dart'; import '../../../utils/locale_utils.dart'; @@ -122,12 +121,12 @@ class _SettingsAppearancePageState extends ConsumerState ), value: locale.nativeDisplayLanguage.capitalizeFirstLetter, dialogTitle: l.settings_language, - options: AppLocalizations.supportedLocales + options: SupportedLanguage.values .map( - (locale) => ( - value: locale, - title: locale.nativeDisplayLanguage.capitalizeFirstLetter, - subtitle: LocalizationCompletion.getFormattedPercentage(locale), + (language) => ( + value: language.locale, + title: language.nativeName, + subtitle: language.completionFormatted, ), ) .toList(), diff --git a/lib/utils/locale_utils.dart b/lib/utils/locale_utils.dart index 350d9744..265e9939 100644 --- a/lib/utils/locale_utils.dart +++ b/lib/utils/locale_utils.dart @@ -1,19 +1,38 @@ import 'dart:io'; import 'package:flutter/material.dart'; + import '../common/preferences/preference_key.dart'; import 'localizations_utils.dart'; /// Utilities for the application's locale. class LocaleUtils { /// Locale of the device. - Locale get deviceLocale => Locale(Platform.localeName.split('_').first); + Locale get deviceLocale { + final localeCodes = Platform.localeName.split('-'); + final languageCode = localeCodes.first; + String? countryCode; + if (localeCodes.length == 2) { + countryCode = localeCodes[1]; + } + + return Locale.fromSubtags(languageCode: languageCode, countryCode: countryCode); + } /// Locale of the application. Locale get appLocale { - final localePreferenceLanguageCode = PreferenceKey.locale.getPreferenceOrDefault(); + final localeCodes = PreferenceKey.locale.getPreferenceOrDefault().split('-'); + final languageCode = localeCodes.first; + String? scriptCode; + if (localeCodes.length == 2) { + scriptCode = localeCodes[1]; + } + String? countryCode; + if (localeCodes.length == 3) { + countryCode = localeCodes[2]; + } - return Locale(localePreferenceLanguageCode); + return Locale.fromSubtags(languageCode: languageCode, scriptCode: scriptCode, countryCode: countryCode); } /// Locale language code of the application. @@ -21,9 +40,9 @@ class LocaleUtils { /// Sets the application's locale to [locale]. Future setLocale(Locale locale) async { - await PreferenceKey.locale.set(locale.languageCode); + await PreferenceKey.locale.set(locale.toLanguageTag()); - // Reset the hardcoded localizations. + // Reset the hardcoded localizations await LocalizationsUtils().ensureInitialized(); } }