Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internationalization (German) of the mobile app. #246

Merged
merged 26 commits into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
79d7500
Add i18n framework to mobile app and write simple translation generator
matthinc Jun 22, 2022
8ccd899
Replace all texts in login_form with i18n keys
matthinc Jun 22, 2022
b88dcaf
Localization of sharing section
matthinc Jun 22, 2022
50c0847
Localization of asset viewer section
matthinc Jun 22, 2022
067c9e3
Use JSON as base translation format
matthinc Jun 22, 2022
ca62000
Add check for missing/unused translation keys
matthinc Jun 22, 2022
2dd1df8
Add localizely
matthinc Jun 23, 2022
a249e37
Remove i18n directory in favour of localizely
matthinc Jun 23, 2022
821eca6
Backup Translation
matthinc Jun 23, 2022
f08ec52
More translations
matthinc Jun 23, 2022
cb158a0
Translate home page
matthinc Jun 27, 2022
07a4fde
Translation of search page
matthinc Jun 27, 2022
e769483
Translate new server version announcement
matthinc Jun 27, 2022
9e462ec
Merge main
matthinc Jun 27, 2022
f675b9a
Reformat code
matthinc Jun 27, 2022
e4c7223
Fix typo in german translation
matthinc Jun 27, 2022
f9bbcaf
Update englisch translations
matthinc Jun 27, 2022
842c6ab
Change translation keys to match dart filenames
matthinc Jul 5, 2022
b8dd54d
Merge main
matthinc Jul 5, 2022
715f646
Add /api to translated endpoint_urls
matthinc Jul 5, 2022
cf6c7d0
Update localizely.yml
matthinc Jul 5, 2022
409c19e
Add languages to ios plist
matthinc Jul 5, 2022
837a31a
Merge upstream
alextran1502 Jul 6, 2022
ac7a527
Remove unused keys
alextran1502 Jul 6, 2022
389794a
Added script to check outdated key in other translations
alextran1502 Jul 6, 2022
7ad7b2b
Add download key to localizely.yml
matthinc Jul 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions localizely.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
config_version: 1.0
project_id: 4fda40f2-8e20-48cf-97e8-0062c2b93ffc
file_type: flutter_arb
upload:
files:
- file: mobile/assets/i18n/en-US.json
locale_code: en
- file: mobile/assets/i18n/de-DE.json
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be in the upload section? I believe we should have just en-US in the upload section, then have all the other languages in the download section so localizely updates them for us automatically?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally I would add all existing JSON files to the upload section. That way manual JSON changes and localizely are always in-sync. Localizely seems to do a great job merging local and remote changes.

locale_code: de
download:
files:
- file: mobile/assets/i18n/en-US.json
locale_code: en
- file: mobile/assets/i18n/de-DE.json
locale_code: de
103 changes: 103 additions & 0 deletions mobile/assets/i18n/de-DE.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"asset_description": "Beschreibung hinzufügen...",
"asset_details": "DETAILS",
"asset_err_corrupted": "Fehler bei der Darstellung - Daten sind beschädigt",
"asset_location": "STANDORT",
"backup_album_excluded": "AUSGESCHLOSSEN",
"backup_album_included": "EINGESCHLOSSEN",
"backup_albums": "Gesicherte Alben",
"backup_albums_device": "Alben auf dem Gerät",
"backup_albums_tap": "Tippe um hinzuzufügen, tippe doppelt um zu entfernen",
"backup_all": "Alle",
"backup_assets": "Gesicherte Einträge: ",
"backup_backup": "Sicherung",
"backup_backup_sub": "Gesicherte Fotos und Videos",
"backup_cancel": "Abbrechen",
"backup_done": "Fertig",
"backup_err_only_album": "Kann das einzige Album nicht löschen",
"backup_excluded": "Ausgeschlossen: ",
"backup_info": "Über die Sicherung",
"backup_info_assets": "Einträge",
"backup_info_assets_scatter": "Dateien können sich über mehrere Alben verteilen.Daher können Alben während des Backup Prozesses inkludiert oder exkludiert werden.",
"backup_none_selected": "Nichts ausgewählt",
"backup_progress": "Backup Fortschritt: ",
"backup_remainder": "Übrig",
"backup_remainder_sub": "Noch nicht gesicherte Fotos und Videos aus gewählten Alben ",
"backup_select": "Auswählen",
"backup_select_albums": "Wähle Alben aus",
"backup_selected": "Ausgewählt: ",
"backup_selection_info": "Auswahl Informationen",
"backup_server_storage": "Speicherplatz auf dem Server",
"backup_status_off": "Sicherung deaktiviert",
"backup_status_on": "Sicherung aktiviert",
"backup_storage_format": "{} von {} genutzt",
"backup_to_backup": "Zu sichernde Alben",
"backup_total": "Gesamt",
"backup_total_assets": "Gesamtzahl",
"backup_total_sub": "Alle Fotos und Videos aus gewählten Alben",
"backup_turn_off": "Sicherung deaktivieren",
"backup_turn_on": "Sicherung aktivieren",
"create_shared_album": "Geteiltes Album erstellen",
"date_format": "E, LLL d, y • HH:mm",
"desc_backup": "Aktiviere automatische Sicherung auf den Server.",
"login_button_text": "Anmelden",
"login_email_hint": "deine@email.com",
"login_endpoint_hint": "http://dein-server:port",
"login_endpoint_url": "Server URL",
"login_err_http": "Muss mit http:// oder https:// starten",
"login_err_invalid_email": "Ungültige Email-Adresse",
"login_err_leading_whitespace": "Führendes Leerzeichen",
"login_err_trailing_whitespace": "Abschließendes Leerzeichen",
"login_label_email": "Email-Adresse",
"login_label_password": "Passwort",
"login_password_hint": "passwort",
"nav_photos": "Fotos",
"nav_search": "Suche",
"nav_sharing": "Freigabe",
"save_login": "Angemeldet bleiben",
"share_add": "Hinzufügen",
"share_add_assets": "EINTRÄGE HINZUFÜGEN",
"share_add_photos": "Fotos hinzufügen",
"share_add_title": "Titel hinzufügen",
"share_add_users": "Nutzer hinzufügen",
"share_album": "Geteilte Alben",
"share_create_album": "Album erstellen",
"share_delete": "Album löschen",
"share_description": "Erstelle geteilte Alben um Fotos und Videos mit Menschen aus deinem Netzwerk zu teilen.",
"share_empty_list": "LEERE LISTE",
"share_err_album": "Fehler beim Erstellen des Albums",
"share_err_delete": "Fehler beim Löschen des Albums",
"share_err_leave": "Fehler beim Verlassen des Albums",
"share_err_remove": "Einträge konnten nicht aus dem Album gelöscht werden",
"share_err_title": "Fehler beim Ändern des Titels",
"share_invite": "Zum Album einladen",
"share_leave": "Album verlassen",
"share_partner": "Mit Partner teilen",
"share_remove": "Aus Album entfernen",
"share_select_photos": "Fotos auswählen",
"share_share": "Teilen",
"share_suggestions": "Vorschläge",
"start_backup": "Starte Backup",
"home_delete": "Löschen",
"home_delete_alert_title": "Endgültig löschen",
"home_delete_alert": "Diese Elemente werden für immer von deinem Gerät und vom Server gelöscht!",
"home_delete_alert_cancel": "Abbrechen",
"home_delete_alert_ok": "Löschen",
"home_sign_out": "Abmelden",
"home_client_server_up_to_date": "Client und Server sind aktuell",
"home_date": "E, dd MMM",
"home_date_year": "E, dd MMM, yyyy",
"month_title_date_format": "MMMM y",
"search_hint": "Durchsuche deine Fotos",
"search_places": "Orte",
"search_things": "Dinge",
"search_new_search_hint": "Neue Suche",
"search_no_objects": "Keine Informationen über Dinge verfügbar",
"search_no_places": "Keine Informationen über Orte verfügbar",
"version_announcement_title": "Eine neue Server-Version ist verfügbar \uD83C\uDF89",
"version_announcement_text_1": "Hallo mein Freund, es gibt eine neue Version von",
"version_announcement_text_2": "- Bitte nehme dir Zeit und lese die ",
"version_announcement_release_notes": "Release-Notes",
"version_announcement_text_3": " und stelle sicher, dass deine docker-compose und .env Dateien aktuell sind. So kannst du Fehler vermeiden, besonders wenn du WatchTower oder einen ähnlichen Mechanismus für automatische Updates benutzt.",
"version_announcement_ack": "Ich habe verstanden"
}
103 changes: 103 additions & 0 deletions mobile/assets/i18n/en-US.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"date_format": "E, LLL d, y \u2022 h:mm a",
"home_date": "E, MMM dd",
"home_date_year": "E, MMM dd, yyyy",
"month_title_date_format": "MMMM y",
"login_button_text": "Login",
"save_login": "Stay logged in",
"login_endpoint_url": "Server Endpoint URL",
"login_endpoint_hint": "http://your-server-ip:port",
"login_err_trailing_whitespace": "Trailing whitespace",
"login_err_leading_whitespace": "Leading whitespace",
"login_err_invalid_email": "Invalid Email",
"login_err_http": "Please specify http:// or https://",
"login_label_email": "Email",
"login_email_hint": "youremail@email.com",
"login_label_password": "Password",
"login_password_hint": "password",
"share_add_title": "Add a title",
"share_err_delete": "Failed to delete album",
"share_err_leave": "Failed to leave album",
"share_err_remove": "There are problems in removing assets from album",
"share_err_title": "Failed to change album title",
"share_remove": "Remove from album",
"share_delete": "Delete album",
"share_leave": "Leave album",
"create_shared_album": "Create shared album",
"share_partner": "Share with partner",
"share_add_photos": "Add photos",
"share_add_users": "Add users",
"share_add": "Add",
"share_add_assets": "ADD ASSETS",
"share_select_photos": "Select Photos",
"share_create_album": "Create album",
"share_share": "Share",
"share_suggestions": "Suggestions",
"share_invite": "Invite to album",
"share_err_album": "Failed to create album",
"share_empty_list": "EMPTY LIST",
"share_description": "Create shared albums to share photos and videos with people in your network.",
"share_album": "Shared albums",
"asset_description": "Add Description...",
"asset_location": "LOCATION",
"asset_details": "DETAILS",
"asset_err_corrupted": "Failed To Render Image - Possibly Corrupted Data",
"backup_err_only_album": "Cannot remove the only album",
"backup_server_storage": "Server Storage",
"backup_status_on": "Backup is on",
"backup_status_off": "Backup is off",
"backup_turn_off": "Turn off Backup",
"backup_turn_on": "Turn on Backup",
"desc_backup": "Turn on backup to automatically upload new assets to the server.",
"backup_selected": "Selected: ",
"backup_all": "All",
"backup_none_selected": "None selected",
"backup_excluded": "Excluded: ",
"backup_albums": "Backup Albums",
"backup_to_backup": "Albums to be backup",
"backup_select": "Select",
"backup_backup": "Backup",
"backup_info": "Backup Information",
"backup_total": "Total",
"backup_total_sub": "All unique photos and videos from selected albums",
"backup_backup_sub": "Backed up photos and videos",
"backup_remainder": "Remainder",
"backup_remainder_sub": "Remaining photos and albums to back up from selection",
"backup_assets": "Asset that were being backup: {}",
"backup_progress": "Backup Progress:",
"backup_done": "Done",
"backup_cancel": "Cancel",
"start_backup": "Start Backup",
"backup_album_included": "INCLUDED",
"backup_album_excluded": "EXCLUDED",
"backup_info_assets": "assets",
"backup_select_albums": "Select Albums",
"backup_selection_info": "Selection Info",
"backup_total_assets": "Total unique assets",
"backup_albums_device": "Albums on device ({})",
"backup_albums_tap": "Tap to include, double tap to exclude",
"backup_info_assets_scatter": "Assets can scatter across multiple albums. Thus, albums can be included or excluded during the backup process.",
"backup_storage_format": "{} of {} used",
"nav_photos": "Photos",
"nav_search": "Search",
"nav_sharing": "Sharing",
"home_delete": "Delete",
"home_delete_alert_title": "Delete Permanently",
"home_delete_alert": "These items will be permanently deleted from Immich and from your device",
"home_delete_alert_cancel": "Cancel",
"home_delete_alert_ok": "Delete",
"home_sign_out": "Sign Out",
"home_client_server_up_to_date": "Client and Server are up-to-date",
"search_hint": "Search your photos",
"search_places": "Places",
"search_things": "Things",
"search_new_search_hint": "New Search",
"search_no_objects": "No Object Info Available",
"search_no_places": "No Places Info Available",
"version_announcement_title": "New Server Version Available \uD83C\uDF89",
"version_announcement_text_1": "Hi friend, there is a new release of",
"version_announcement_text_2": "please take your time to visit the ",
"version_announcement_release_notes": "release notes",
"version_announcement_text_3": " and ensure your docker-compose and .env setup is up-to-date to prevent any misconfigurations, especially if you use WatchTower or any mechanism that handles updating your server application automatically.",
"version_announcement_ack": "Acknowledge"
}
20 changes: 19 additions & 1 deletion mobile/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hive_flutter/hive_flutter.dart';
Expand Down Expand Up @@ -36,7 +37,21 @@ void main() async {
),
);

runApp(const ProviderScope(child: ImmichApp()));
await EasyLocalization.ensureInitialized();

var locales = const [
// Default locale
Locale('en', 'US'),
// Additional locales
Locale('de', 'DE')
];

runApp(EasyLocalization(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see an option to choose the language, is it based on the phone settings? Do you have any link to the resource that I can read about this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It uses the target platform's locale. That's described here: https://docs.flutter.dev/development/accessibility-and-localization/internationalization (Easy localization uses flutter's localization infrastructure internally)

supportedLocales: locales,
path: 'assets/i18n',
useFallbackTranslations: true,
fallbackLocale: locales.first,
child: const ProviderScope(child: ImmichApp())));
}

class ImmichApp extends ConsumerStatefulWidget {
Expand Down Expand Up @@ -112,6 +127,9 @@ class ImmichAppState extends ConsumerState<ImmichApp>
ref.watch(releaseInfoProvider.notifier).checkGithubReleaseInfo();

return MaterialApp(
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
debugShowCheckedModeBanner: false,
home: Stack(
children: [
Expand Down
15 changes: 8 additions & 7 deletions mobile/lib/modules/asset_viewer/ui/exif_bottom_sheet.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
Expand Down Expand Up @@ -80,7 +81,7 @@ class ExifBottomSheet extends ConsumerWidget {
children: [
assetDetail.exifInfo?.dateTimeOriginal != null
? Text(
DateFormat('E, LLL d, y • h:mm a').format(
DateFormat('date_format'.tr()).format(
DateTime.parse(assetDetail.exifInfo!.dateTimeOriginal!),
),
style: TextStyle(
Expand All @@ -93,12 +94,12 @@ class ExifBottomSheet extends ConsumerWidget {
Padding(
padding: const EdgeInsets.only(top: 16.0),
child: Text(
"Add Description...",
"asset_description",
matthinc marked this conversation as resolved.
Show resolved Hide resolved
style: TextStyle(
color: Colors.grey[500],
fontSize: 11,
),
),
).tr(),
),

// Location
Expand All @@ -113,9 +114,9 @@ class ExifBottomSheet extends ConsumerWidget {
color: Colors.grey[600],
),
Text(
"LOCATION",
"asset_location",
style: TextStyle(fontSize: 11, color: Colors.grey[400]),
),
).tr(),
_buildMap(),
_buildLocationText(),
Text(
Expand All @@ -140,10 +141,10 @@ class ExifBottomSheet extends ConsumerWidget {
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Text(
"DETAILS",
"asset_details",
style:
TextStyle(fontSize: 11, color: Colors.grey[400]),
),
).tr(),
),
ListTile(
contentPadding: const EdgeInsets.all(0),
Expand Down
17 changes: 10 additions & 7 deletions mobile/lib/modules/backup/ui/album_info_card.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'dart:typed_data';

import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
Expand Down Expand Up @@ -37,21 +38,21 @@ class AlbumInfoCard extends HookConsumerWidget {
visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
label: const Text(
"INCLUDED",
"backup_album_included",
style: TextStyle(
fontSize: 10, color: Colors.white, fontWeight: FontWeight.bold),
),
).tr(),
backgroundColor: Theme.of(context).primaryColor,
);
} else if (isExcluded) {
return Chip(
visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
label: const Text(
"EXCLUDED",
"backup_album_excluded",
style: TextStyle(
fontSize: 10, color: Colors.white, fontWeight: FontWeight.bold),
),
).tr(),
backgroundColor: Colors.red[300],
);
}
Expand All @@ -77,7 +78,7 @@ class AlbumInfoCard extends HookConsumerWidget {
if (ref.watch(backupProvider).selectedBackupAlbums.length == 1) {
ImmichToast.show(
context: context,
msg: "Cannot remove the only album",
msg: "backup_err_only_album".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
Expand All @@ -104,7 +105,7 @@ class AlbumInfoCard extends HookConsumerWidget {
.contains(albumInfo)) {
ImmichToast.show(
context: context,
msg: "Cannot exclude the only album",
msg: "backup_err_only_album".tr(),
toastType: ToastType.error,
gravity: ToastGravity.BOTTOM,
);
Expand Down Expand Up @@ -177,7 +178,9 @@ class AlbumInfoCard extends HookConsumerWidget {
padding: const EdgeInsets.only(top: 2.0),
child: Text(
albumInfo.assetCount.toString() +
(albumInfo.isAll ? " (ALL)" : ""),
(albumInfo.isAll
? " (${'backup_all'.tr()})"
: ""),
style: TextStyle(
fontSize: 12, color: Colors.grey[600]),
),
Expand Down
3 changes: 2 additions & 1 deletion mobile/lib/modules/backup/ui/backup_info_card.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';

class BackupInfoCard extends StatelessWidget {
Expand Down Expand Up @@ -44,7 +45,7 @@ class BackupInfoCard extends StatelessWidget {
info,
style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const Text("assets"),
const Text("backup_info_assets").tr(),
],
),
),
Expand Down
Loading