diff --git a/client/native-shell/amount.ts b/client/native-shell/amount.ts index 19e5756ea..33f1a2b75 100644 --- a/client/native-shell/amount.ts +++ b/client/native-shell/amount.ts @@ -12,9 +12,9 @@ interface Amount { render(value: number): string; } -// Digits with the marks stores put between them: . , space, no-break spaces, and -// the apostrophes Swiss formats group thousands with (1'290 and 1’290). -const NUMBER = /\d[\d.,\s  '’]*\d|\d/; +// Digits with the marks stores put between them: . , any space (\s takes the +// no-break ones too) and the apostrophes Swiss formats group thousands with. +const NUMBER = /\d[\d.,\s'’]*\d|\d/; export function amountIn(label: string): Amount | null { const match = NUMBER.exec(label); @@ -25,7 +25,7 @@ export function amountIn(label: string): Amount | null { const decimals = decimal ? decimal[2].length : 0; const mark = decimal ? decimal[1] : ''; const whole = decimal ? raw.slice(0, raw.length - decimal[0].length) : raw; - const group = /[.,\s  '’]/.exec(whole)?.[0] ?? ''; + const group = /[.,\s'’]/.exec(whole)?.[0] ?? ''; const digits = whole.replace(/\D/g, '') + (decimal ? `.${decimal[2]}` : ''); const value = Number(digits); if (!Number.isFinite(value)) return null; diff --git a/client/src/mobile/mobile.css b/client/src/mobile/mobile.css index 5301044c1..d7f11e834 100644 --- a/client/src/mobile/mobile.css +++ b/client/src/mobile/mobile.css @@ -578,12 +578,15 @@ html[dir='rtl']:has(.m-shell[data-size='wide'], .m-shell[data-size='split']) .m- inset-inline-end: 0; } /* Without the rail the floating bars keep clear of the sides' safe area too: - a camera in a corner can come as a side inset. Physical sides, as the - insets are the screen's, not the text direction's. On a wide window the - rail takes the leading side and a bar may centre itself (mx-auto). */ + a camera in a corner can come as a side inset. The insets are the screen's, + not the text direction's, so right to left takes them the other way round. + On a wide window the rail takes the leading side and a bar may centre itself + (mx-auto). */ html:not(:has(.m-shell[data-size='wide'], .m-shell[data-size='split'])) :is(.m-bar-x, .m-span-x) { - margin-left: var(--m-safe-l, 0px); - margin-right: var(--m-safe-r, 0px); + margin-inline: var(--m-safe-l, 0px) var(--m-safe-r, 0px); +} +html[dir='rtl']:not(:has(.m-shell[data-size='wide'], .m-shell[data-size='split'])) :is(.m-bar-x, .m-span-x) { + margin-inline: var(--m-safe-r, 0px) var(--m-safe-l, 0px); } /* A screen whose background is a map reaches under the rail: the map runs to the window's edge and the rail floats over it like the top controls do. Its diff --git a/client/src/native/widgets.ts b/client/src/native/widgets.ts index 4b4019eda..1a1c397bd 100644 --- a/client/src/native/widgets.ts +++ b/client/src/native/widgets.ts @@ -358,7 +358,7 @@ export function tripDayState(day: TripDay, nowMinutes: number, allDone: string): } /** How long before the day's first timed stop its Live Activity appears. */ -export const LIVE_LEAD_MINUTES = 3 * 60; +const LIVE_LEAD_MINUTES = 3 * 60; /** * Whether the travel day's Live Activity belongs on the lock screen now: from diff --git a/shared/scripts/i18n-parity.mjs b/shared/scripts/i18n-parity.mjs index 778967a47..443fad842 100644 --- a/shared/scripts/i18n-parity.mjs +++ b/shared/scripts/i18n-parity.mjs @@ -104,10 +104,13 @@ export const NOT_PLURAL = [ { key: 'dawarich.duration.hours', because: 'a duration in a unit symbol (h), the same for any number' }, { key: 'dawarich.duration.hoursMinutes', because: 'a duration in unit symbols (h, min), the same for any number' }, { key: 'files.uploadErrorSize', because: 'a size limit in a unit symbol (MB), the same for any number' }, - { key: 'native.plans.storage', because: 'a storage size in a unit symbol (GB), the same for any number' }, { - key: 'native.plans.aiDocs', - because: 'a monthly document allowance, always in the tens, so no singular ever shows', + key: 'native.plans.photos', + because: 'an estimate of photos a plan holds, always in the thousands, so no singular ever shows', + }, + { + key: 'native.plans.aiPerMonth', + because: 'a monthly document allowance before a unit ("25 / month"), always in the tens', }, ]; diff --git a/shared/src/i18n/ar/native.ts b/shared/src/i18n/ar/native.ts index 12d65fbd0..3601c280a 100644 --- a/shared/src/i18n/ar/native.ts +++ b/shared/src/i18n/ar/native.ts @@ -207,8 +207,8 @@ const native: TranslationStrings = { 'native.plans.billing': 'الدفع', 'native.claim.almost': 'اقتربنا', 'native.claim.addressField': 'العنوان', - 'native.claim.slugPlaceholder': 'yourname', // same-as-en - 'native.claim.emailPlaceholder': 'you@example.com', // same-as-en + 'native.claim.slugPlaceholder': 'ismuka', + 'native.claim.emailPlaceholder': 'anta@mithal.com', 'native.claim.passwordPlaceholder': 'اختر كلمة مرور', 'native.claim.freeBadge': 'متاح', 'native.claim.renews': 'يتجدّد تلقائيًا، ألغِ في أي وقت.', diff --git a/shared/src/i18n/he/native.ts b/shared/src/i18n/he/native.ts index d6b008010..e0f6d565f 100644 --- a/shared/src/i18n/he/native.ts +++ b/shared/src/i18n/he/native.ts @@ -206,8 +206,8 @@ const native: TranslationStrings = { 'native.plans.billing': 'חיוב', 'native.claim.almost': 'כמעט שם', 'native.claim.addressField': 'כתובת', - 'native.claim.slugPlaceholder': 'yourname', // same-as-en - 'native.claim.emailPlaceholder': 'you@example.com', // same-as-en + 'native.claim.slugPlaceholder': 'hashem-shelcha', + 'native.claim.emailPlaceholder': 'ata@dugma.co.il', 'native.claim.passwordPlaceholder': 'בחרו סיסמה', 'native.claim.freeBadge': 'פנויה', 'native.claim.renews': 'מתחדש אוטומטית, ביטול בכל עת.', diff --git a/shared/src/i18n/ja/native.ts b/shared/src/i18n/ja/native.ts index 6df5e48e9..364d6c21d 100644 --- a/shared/src/i18n/ja/native.ts +++ b/shared/src/i18n/ja/native.ts @@ -212,8 +212,8 @@ const native: TranslationStrings = { 'native.plans.billing': 'お支払い', 'native.claim.almost': 'もうすぐ到着', 'native.claim.addressField': 'アドレス', - 'native.claim.slugPlaceholder': 'yourname', // same-as-en - 'native.claim.emailPlaceholder': 'you@example.com', // same-as-en + 'native.claim.slugPlaceholder': 'namae', + 'native.claim.emailPlaceholder': 'anata@rei.jp', 'native.claim.passwordPlaceholder': 'パスワードを決める', 'native.claim.freeBadge': '空き', 'native.claim.renews': '自動更新、いつでも解約できます。', diff --git a/shared/src/i18n/ko/native.ts b/shared/src/i18n/ko/native.ts index 4ad990a4d..e30a13075 100644 --- a/shared/src/i18n/ko/native.ts +++ b/shared/src/i18n/ko/native.ts @@ -209,8 +209,8 @@ const native: TranslationStrings = { 'native.plans.billing': '결제', 'native.claim.almost': '거의 다 왔어요', 'native.claim.addressField': '주소', - 'native.claim.slugPlaceholder': 'yourname', // same-as-en - 'native.claim.emailPlaceholder': 'you@example.com', // same-as-en + 'native.claim.slugPlaceholder': 'ireum', + 'native.claim.emailPlaceholder': 'na@yesi.kr', 'native.claim.passwordPlaceholder': '비밀번호 정하기', 'native.claim.freeBadge': '사용 가능', 'native.claim.renews': '자동 갱신되며 언제든 해지할 수 있습니다.', diff --git a/shared/src/i18n/th/native.ts b/shared/src/i18n/th/native.ts index 69f26ab6b..00419616e 100644 --- a/shared/src/i18n/th/native.ts +++ b/shared/src/i18n/th/native.ts @@ -205,8 +205,8 @@ const native: TranslationStrings = { 'native.plans.billing': 'การชำระเงิน', 'native.claim.almost': 'ใกล้ถึงแล้ว', 'native.claim.addressField': 'ที่อยู่', - 'native.claim.slugPlaceholder': 'yourname', // same-as-en - 'native.claim.emailPlaceholder': 'you@example.com', // same-as-en + 'native.claim.slugPlaceholder': 'chue-khong-khun', + 'native.claim.emailPlaceholder': 'khun@tuayang.co.th', 'native.claim.passwordPlaceholder': 'ตั้งรหัสผ่าน', 'native.claim.freeBadge': 'ว่าง', 'native.claim.renews': 'ต่ออายุอัตโนมัติ ยกเลิกได้ทุกเมื่อ', diff --git a/shared/src/i18n/zh-TW/native.ts b/shared/src/i18n/zh-TW/native.ts index ad311ae1f..e904422f0 100644 --- a/shared/src/i18n/zh-TW/native.ts +++ b/shared/src/i18n/zh-TW/native.ts @@ -200,8 +200,8 @@ const native: TranslationStrings = { 'native.plans.billing': '付款', 'native.claim.almost': '快到了', 'native.claim.addressField': '網址', - 'native.claim.slugPlaceholder': 'yourname', // same-as-en - 'native.claim.emailPlaceholder': 'you@example.com', // same-as-en + 'native.claim.slugPlaceholder': 'nidemingzi', + 'native.claim.emailPlaceholder': 'ni@shili.tw', 'native.claim.passwordPlaceholder': '設定密碼', 'native.claim.freeBadge': '可用', 'native.claim.renews': '自動續訂,隨時可取消。', diff --git a/shared/src/i18n/zh/native.ts b/shared/src/i18n/zh/native.ts index e51551e45..cdd7e13da 100644 --- a/shared/src/i18n/zh/native.ts +++ b/shared/src/i18n/zh/native.ts @@ -199,8 +199,8 @@ const native: TranslationStrings = { 'native.plans.billing': '付款', 'native.claim.almost': '马上就到', 'native.claim.addressField': '地址', - 'native.claim.slugPlaceholder': 'yourname', // same-as-en - 'native.claim.emailPlaceholder': 'you@example.com', // same-as-en + 'native.claim.slugPlaceholder': 'nidemingzi', + 'native.claim.emailPlaceholder': 'ni@shili.cn', 'native.claim.passwordPlaceholder': '设置密码', 'native.claim.freeBadge': '可用', 'native.claim.renews': '自动续订,随时可取消。',