mirror of
https://github.com/localsend/localsend.git
synced 2026-08-07 07:14:52 +00:00
i18n: improve Hebrew translations (#3236)
This commit is contained in:
@@ -4,74 +4,58 @@
|
||||
"After editing this file, you can run 'dart run slang apply --locale=he' to quickly apply the newly added translations."
|
||||
],
|
||||
"receiveTab": {
|
||||
"link": "Receive via link"
|
||||
"link": "קבלה באמצעות קישור"
|
||||
},
|
||||
"settingsTab": {
|
||||
"general": {
|
||||
"colorOptions": {
|
||||
"custom": "Custom"
|
||||
"custom": "מותאם אישית"
|
||||
}
|
||||
},
|
||||
"receive": {
|
||||
"verifyChecksums": "Verify checksums when receiving files"
|
||||
"verifyChecksums": "אימות שלמות קבצים בעת קבלה"
|
||||
},
|
||||
"send": {
|
||||
"createChecksums": "Create checksums when sending files"
|
||||
"createChecksums": "צור סכומי שלמות קבצים בעת שליחה"
|
||||
}
|
||||
},
|
||||
"deviceDetailsPage": {
|
||||
"title": "Device Details",
|
||||
"favorite": "Favorite",
|
||||
"verify": "Verify",
|
||||
"title": "פרטי מכשיר",
|
||||
"favorite": "מועדף",
|
||||
"verify": "אימות",
|
||||
"info": {
|
||||
"name": "Name",
|
||||
"address": "Address",
|
||||
"version": "Version",
|
||||
"protocol": "Protocol v{version}"
|
||||
"name": "שם",
|
||||
"address": "כתובת",
|
||||
"version": "גרסה",
|
||||
"protocol": "פרוטוקול גרסה {version}"
|
||||
},
|
||||
"logs": {
|
||||
"title": "Logs",
|
||||
"empty": "No logs available.",
|
||||
"discovered": "Discovered via {protocol} ({host})",
|
||||
"updated": "Updated via {protocol} ({host})"
|
||||
"title": "יומני רישום",
|
||||
"empty": "אין יומנים זמינים",
|
||||
"discovered": "התגלה באמצעות {protocol} ({host})",
|
||||
"updated": "עודכן באמצעות {protocol} ({host})"
|
||||
}
|
||||
},
|
||||
"verifyPage": {
|
||||
"title": "Verify",
|
||||
"icons": "Icons",
|
||||
"raw": "Raw",
|
||||
"question": "Does it look the same on the other device?"
|
||||
"title": "אימות",
|
||||
"icons": "סמלים",
|
||||
"raw": "גולמי",
|
||||
"question": "האם זה נראה אותו דבר במכשיר השני?"
|
||||
},
|
||||
"sendPage": {
|
||||
"calculatingChecksum": "Calculating checksum ({curr} / {n})"
|
||||
},
|
||||
"progressPage": {
|
||||
"remainingTime": {
|
||||
"minutesUnit(plural, param=m)": {
|
||||
"other": "{m}m"
|
||||
},
|
||||
"hoursUnit(plural, param=h)": {
|
||||
"other": "{h}h"
|
||||
},
|
||||
"daysUnit(plural, param=d)": {
|
||||
"other": "{d}d"
|
||||
},
|
||||
"minutes": "{n}:{ss}",
|
||||
"hours": "@:progressPage.remainingTime.hoursUnit @:progressPage.remainingTime.minutesUnit",
|
||||
"days": "@:progressPage.remainingTime.daysUnit @:progressPage.remainingTime.hoursUnit @:progressPage.remainingTime.minutesUnit"
|
||||
}
|
||||
"calculatingChecksum": "מאמת שלמות ({curr} / {n})"
|
||||
},
|
||||
"webReceivePage": {
|
||||
"title": "Receive via link"
|
||||
"title": "קבלה באמצעות קישור"
|
||||
},
|
||||
"whatsNewPage": {
|
||||
"title": "What's new in {version}",
|
||||
"title": "מה חדש בגרסה {version}?",
|
||||
"changes(interface=WhatsNewStrings)": {
|
||||
"v1_18_0": {
|
||||
"changes": [
|
||||
"Encryption no longer slows down transfers. It has been re-enabled on this device if you turned it off before.",
|
||||
"Requests from favorites are now accepted automatically. This is turned on by default and can be disabled in the settings.",
|
||||
"On Android, transfers continue while the app is in the background or the screen is off. On iOS, the app must still stay in the foreground."
|
||||
"הצפנה כבר לא מאטה את ההעברות! הפעלנו אותה מחדש אם כיבית אותה בעבר",
|
||||
"מהיום העברות ממכשירים מועדפים יתקבלו באופן אוטומטי. ניתן לבטל זאת בהגדרות האפליקציה",
|
||||
"באנדרואיד, ההעברות נמשכות גם כשהאפליקציה ברקע או שהמסך כבוי (ב-iOS כרגע האפליקציה עדיין חייבת להישאר פתוחה והמסך דולק)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,6 +274,9 @@
|
||||
"hoursUnit(plural, param=h)": {
|
||||
"other": "{h}h"
|
||||
},
|
||||
"hoursUnitWithAnd(plural, param=h)": {
|
||||
"other": "{h}h"
|
||||
},
|
||||
"daysUnit(plural, param=d)": {
|
||||
"other": "{d}d"
|
||||
},
|
||||
|
||||
+24
-1
@@ -196,7 +196,7 @@
|
||||
"apkPickerPage": {
|
||||
"title": "אפליקציות (APK)",
|
||||
"excludeSystemApps": "אל תכלול אפליקציות מערכת",
|
||||
"excludeAppsWithoutLaunchIntent": "אל תכלול אפליקציות שאינן ניתנות להפעלה",
|
||||
"excludeAppsWithoutLaunchIntent": "אל תכלול אפליקציות שאינן ניתנות לפתיחה",
|
||||
"apps": "{n} אפליקציות"
|
||||
},
|
||||
"selectedFilesPage": {
|
||||
@@ -238,6 +238,29 @@
|
||||
"count": "קבצים: {curr}/{n}",
|
||||
"size": "גודל: {curr}/{n}",
|
||||
"speed": "מהירות: {speed}/שניה"
|
||||
},
|
||||
"remainingTime": {
|
||||
"minutesUnit(plural, param=m)": {
|
||||
"one": "ודקה",
|
||||
"other": "ו־{m} דקות"
|
||||
},
|
||||
"hoursUnit(plural, param=h)": {
|
||||
"one": "שעה",
|
||||
"two": "שעתיים",
|
||||
"other": "{h} שעות"
|
||||
},
|
||||
"hoursUnitWithAnd(plural, param=h)": {
|
||||
"one": "ושעה",
|
||||
"two": "ושעתיים",
|
||||
"other": "ו־{h} שעות"
|
||||
},
|
||||
"daysUnit(plural, param=d)": {
|
||||
"one": "יום",
|
||||
"two": "יומיים",
|
||||
"other": "{d} ימים"
|
||||
},
|
||||
"hours": "@:progressPage.remainingTime.hoursUnit @:progressPage.remainingTime.minutesUnit",
|
||||
"days": "@:progressPage.remainingTime.daysUnit, @:progressPage.remainingTime.hoursUnit @:progressPage.remainingTime.minutesUnit"
|
||||
}
|
||||
},
|
||||
"webSharePage": {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 55
|
||||
/// Strings: 18438 (335 per locale)
|
||||
/// Strings: 18452 (335 per locale)
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
|
||||
@@ -1390,6 +1390,12 @@ class Translations$progressPage$remainingTime$en {
|
||||
other: '${h}h',
|
||||
);
|
||||
|
||||
/// en: '(other) {{h}h}'
|
||||
String hoursUnitWithAnd({required num h}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(
|
||||
h,
|
||||
other: '${h}h',
|
||||
);
|
||||
|
||||
/// en: '(other) {{d}d}'
|
||||
String daysUnit({required num d}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('en'))(
|
||||
d,
|
||||
|
||||
@@ -319,7 +319,7 @@ class _Translations$apkPickerPage$he extends Translations$apkPickerPage$en {
|
||||
@override
|
||||
String get excludeSystemApps => 'אל תכלול אפליקציות מערכת';
|
||||
@override
|
||||
String get excludeAppsWithoutLaunchIntent => 'אל תכלול אפליקציות שאינן ניתנות להפעלה';
|
||||
String get excludeAppsWithoutLaunchIntent => 'אל תכלול אפליקציות שאינן ניתנות לפתיחה';
|
||||
@override
|
||||
String apps({required Object n}) => '${n} אפליקציות';
|
||||
}
|
||||
@@ -407,6 +407,8 @@ class _Translations$progressPage$he extends Translations$progressPage$en {
|
||||
String get savedToGallery => 'נשמר בתמונות';
|
||||
@override
|
||||
late final _Translations$progressPage$total$he total = _Translations$progressPage$total$he._(_root);
|
||||
@override
|
||||
late final _Translations$progressPage$remainingTime$he remainingTime = _Translations$progressPage$remainingTime$he._(_root);
|
||||
}
|
||||
|
||||
// Path: webSharePage
|
||||
@@ -980,6 +982,48 @@ class _Translations$progressPage$total$he extends Translations$progressPage$tota
|
||||
String speed({required Object speed}) => 'מהירות: ${speed}/שניה';
|
||||
}
|
||||
|
||||
// Path: progressPage.remainingTime
|
||||
class _Translations$progressPage$remainingTime$he extends Translations$progressPage$remainingTime$en {
|
||||
_Translations$progressPage$remainingTime$he._(TranslationsHe root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsHe _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override
|
||||
String minutesUnit({required num m}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('he'))(
|
||||
m,
|
||||
one: 'ודקה',
|
||||
other: 'ו־${m} דקות',
|
||||
);
|
||||
@override
|
||||
String hoursUnit({required num h}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('he'))(
|
||||
h,
|
||||
one: 'שעה',
|
||||
two: 'שעתיים',
|
||||
other: '${h} שעות',
|
||||
);
|
||||
@override
|
||||
String hoursUnitWithAnd({required num h}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('he'))(
|
||||
h,
|
||||
one: 'ושעה',
|
||||
two: 'ושעתיים',
|
||||
other: 'ו־${h} שעות',
|
||||
);
|
||||
@override
|
||||
String daysUnit({required num d}) => (_root.$meta.cardinalResolver ?? PluralResolvers.cardinal('he'))(
|
||||
d,
|
||||
one: 'יום',
|
||||
two: 'יומיים',
|
||||
other: '${d} ימים',
|
||||
);
|
||||
@override
|
||||
String hours({required num h, required num m}) =>
|
||||
'${_root.progressPage.remainingTime.hoursUnit(h: h)} ${_root.progressPage.remainingTime.minutesUnit(m: m)}';
|
||||
@override
|
||||
String days({required num d, required num h, required num m}) =>
|
||||
'${_root.progressPage.remainingTime.daysUnit(d: d)}, ${_root.progressPage.remainingTime.hoursUnit(h: h)} ${_root.progressPage.remainingTime.minutesUnit(m: m)}';
|
||||
}
|
||||
|
||||
// Path: dialogs.addFile
|
||||
class _Translations$dialogs$addFile$he extends Translations$dialogs$addFile$en {
|
||||
_Translations$dialogs$addFile$he._(TranslationsHe root) : this._root = root, super.internal(root);
|
||||
|
||||
@@ -16,6 +16,9 @@ Future<void> initI18n() async {
|
||||
if (n == 1) {
|
||||
return one ?? other ?? n.toString();
|
||||
}
|
||||
if (locale == AppLocale.he && n == 2) {
|
||||
return two ?? other ?? n.toString();
|
||||
}
|
||||
return other ?? n.toString();
|
||||
},
|
||||
ordinalResolver: (n, {zero, one, two, few, many, other}) {
|
||||
|
||||
@@ -9,6 +9,25 @@ final notificationStrings = NotificationStrings(
|
||||
titleReceiving: t.progressPage.titleReceiving,
|
||||
titleSending: t.progressPage.titleSending,
|
||||
remainingTimeMinutes: t.progressPage.remainingTime.minutes,
|
||||
remainingTimeHours: t.progressPage.remainingTime.hours,
|
||||
remainingTimeDays: t.progressPage.remainingTime.days,
|
||||
remainingTimeLong: _remainingTimeLong,
|
||||
);
|
||||
|
||||
String _remainingTimeLong({required num d, required num h, required num m}) {
|
||||
final remainingTime = t.progressPage.remainingTime;
|
||||
if (d == 0 && m == 0) {
|
||||
return remainingTime.hoursUnit(h: h);
|
||||
}
|
||||
if (d == 0) {
|
||||
return remainingTime.hours(h: h, m: m);
|
||||
}
|
||||
if (h == 0 && m == 0) {
|
||||
return remainingTime.daysUnit(d: d);
|
||||
}
|
||||
if (h == 0) {
|
||||
return '${remainingTime.daysUnit(d: d)} ${remainingTime.minutesUnit(m: m)}';
|
||||
}
|
||||
if (m == 0) {
|
||||
return '${remainingTime.daysUnit(d: d)} ${remainingTime.hoursUnitWithAnd(h: h)}';
|
||||
}
|
||||
return remainingTime.days(d: d, h: h, m: m);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import 'package:localsend_app/gen/strings.g.dart';
|
||||
import 'package:localsend_app/util/i18n.dart';
|
||||
import 'package:localsend_app/util/notification_strings.dart';
|
||||
import 'package:localsend_isolates/util/file_speed_helper.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
setUpAll(() async {
|
||||
await initI18n();
|
||||
LocaleSettings.setLocaleSync(AppLocale.he);
|
||||
});
|
||||
|
||||
const cases = [
|
||||
(Duration(minutes: 10, seconds: 54), '10:54'),
|
||||
(Duration(hours: 1), 'שעה'),
|
||||
(Duration(hours: 1, minutes: 1), 'שעה ודקה'),
|
||||
(Duration(hours: 2, minutes: 2), 'שעתיים ו־2 דקות'),
|
||||
(Duration(hours: 1, minutes: 5), 'שעה ו־5 דקות'),
|
||||
(Duration(days: 1), 'יום'),
|
||||
(Duration(days: 2), 'יומיים'),
|
||||
(Duration(days: 3), '3 ימים'),
|
||||
(Duration(days: 1, hours: 1), 'יום ושעה'),
|
||||
(Duration(days: 1, minutes: 5), 'יום ו־5 דקות'),
|
||||
(
|
||||
Duration(days: 1, hours: 2, minutes: 5),
|
||||
'יום, שעתיים ו־5 דקות',
|
||||
),
|
||||
(Duration(hours: 1, minutes: 5, seconds: 9), 'שעה ו־5 דקות'),
|
||||
];
|
||||
|
||||
for (final (duration, expected) in cases) {
|
||||
test('$duration → $expected', () {
|
||||
expect(
|
||||
getRemainingTime(
|
||||
bytesPerSeconds: 1000,
|
||||
remainingBytes: duration.inMilliseconds,
|
||||
strings: notificationStrings,
|
||||
),
|
||||
expected,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -17,18 +17,18 @@ void main() {
|
||||
});
|
||||
|
||||
test('shows hours and minutes for duration 1 hour or more but less than 1 day', () {
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 3600000, strings: notificationStrings), '1h 0m');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 3600000, strings: notificationStrings), '1h');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 3660000, strings: notificationStrings), '1h 1m');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 7200000, strings: notificationStrings), '2h 0m');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 7200000, strings: notificationStrings), '2h');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 12000000, strings: notificationStrings), '3h 20m');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 86340000, strings: notificationStrings), '23h 59m');
|
||||
});
|
||||
|
||||
test('shows days, hours and minutes for duration 1 day or more', () {
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 86400000, strings: notificationStrings), '1d 0h 0m');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 90000000, strings: notificationStrings), '1d 1h 0m');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 86400000, strings: notificationStrings), '1d');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 90000000, strings: notificationStrings), '1d 1h');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 93660000, strings: notificationStrings), '1d 2h 1m');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 172800000, strings: notificationStrings), '2d 0h 0m');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 172800000, strings: notificationStrings), '2d');
|
||||
expect(getRemainingTime(bytesPerSeconds: 1000, remainingBytes: 183780000, strings: notificationStrings), '2d 3h 3m');
|
||||
});
|
||||
|
||||
|
||||
@@ -32,13 +32,13 @@ String getRemainingTime({
|
||||
} else if (remainingTimeInSeconds < _secondsPerDay) {
|
||||
final hours = remainingTimeInSeconds ~/ _secondsPerHour;
|
||||
final minutes = (remainingTimeInSeconds % _secondsPerHour) ~/ _secondsPerMinute;
|
||||
return strings.remainingTimeHours(h: hours, m: minutes);
|
||||
return strings.remainingTimeLong(d: 0, h: hours, m: minutes);
|
||||
} else {
|
||||
final days = remainingTimeInSeconds ~/ _secondsPerDay;
|
||||
final remainingAfterDays = remainingTimeInSeconds % _secondsPerDay;
|
||||
final hours = remainingAfterDays ~/ _secondsPerHour;
|
||||
final minutes = (remainingAfterDays % _secondsPerHour) ~/ _secondsPerMinute;
|
||||
return strings.remainingTimeDays(d: days, h: hours, m: minutes);
|
||||
return strings.remainingTimeLong(d: days, h: hours, m: minutes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// The translated strings that this package needs but cannot produce on its own: the app owns the
|
||||
/// translations, and the dependency only points from the app to this package.
|
||||
///
|
||||
/// Inject an instance via `TransferNotification.init`. The signatures mirror the ones slang
|
||||
/// generates, so the app can hand over its translation members directly.
|
||||
/// Inject an instance via `TransferNotification.init` to keep this package independent of the
|
||||
/// app's localization implementation.
|
||||
class NotificationStrings {
|
||||
/// Title while files are being received, e.g. "Receiving files".
|
||||
final String titleReceiving;
|
||||
@@ -13,17 +13,13 @@ class NotificationStrings {
|
||||
/// Remaining time below an hour, e.g. "1:30" or "0:45". [ss] is zero padded.
|
||||
final String Function({required Object n, required Object ss}) remainingTimeMinutes;
|
||||
|
||||
/// Remaining time below a day, e.g. "2h 5m".
|
||||
final String Function({required num h, required num m}) remainingTimeHours;
|
||||
|
||||
/// Remaining time of a day or more, e.g. "3d 4h 5m".
|
||||
final String Function({required num d, required num h, required num m}) remainingTimeDays;
|
||||
/// Remaining time of an hour or more, e.g. "2h 5m" or "3d 4h 5m".
|
||||
final String Function({required num d, required num h, required num m}) remainingTimeLong;
|
||||
|
||||
const NotificationStrings({
|
||||
required this.titleReceiving,
|
||||
required this.titleSending,
|
||||
required this.remainingTimeMinutes,
|
||||
required this.remainingTimeHours,
|
||||
required this.remainingTimeDays,
|
||||
required this.remainingTimeLong,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user