Skip to content

Commit

Permalink
Adds translations to Advanced Repeat Rules
Browse files Browse the repository at this point in the history
Co-authored-by: pas <[email protected]>
  • Loading branch information
2 people authored and tutao-mac committed Feb 3, 2025
1 parent ad42294 commit 30a7bb4
Show file tree
Hide file tree
Showing 5 changed files with 149 additions and 43 deletions.
111 changes: 107 additions & 4 deletions src/calendar-app/calendar/gui/eventpopup/EventPreviewView.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import type { CalendarEvent, CalendarEventAttendee, CalendarRepeatRule, EncryptedMailAddress } from "../../../../common/api/entities/tutanota/TypeRefs.js"
import type {
AdvancedRepeatRule,
CalendarEvent,
CalendarEventAttendee,
CalendarRepeatRule,
EncryptedMailAddress,
} from "../../../../common/api/entities/tutanota/TypeRefs.js"
import { createCalendarEventAttendee, createEncryptedMailAddress } from "../../../../common/api/entities/tutanota/TypeRefs.js"
import m, { Children, Component, Vnode } from "mithril"
import { AllIcons, Icon, IconSize } from "../../../../common/gui/base/Icon.js"
Expand All @@ -21,6 +27,7 @@ import { ExternalLink } from "../../../../common/gui/base/ExternalLink.js"

import { createRepeatRuleFrequencyValues, formatEventDuration, getDisplayEventTitle, iconForAttendeeStatus } from "../CalendarGuiUtils.js"
import { hasError } from "../../../../common/api/common/utils/ErrorUtils.js"
import { ByRule } from "../../../../common/calendar/import/ImportExportUtils.js"

export type EventPreviewViewAttrs = {
event: Omit<CalendarEvent, "description">
Expand Down Expand Up @@ -229,20 +236,95 @@ export function formatRepetitionFrequency(repeatRule: RepeatRule): string | null
const frequency = createRepeatRuleFrequencyValues().find((frequency) => frequency.value === repeatRule.frequency)

if (frequency) {
return frequency.name
const freq = frequency.name
const readable = buildReadableAdvancedRepetitionRule(repeatRule.advancedRules, downcast(repeatRule.frequency))

return `${freq}. ${readable}`.trim()
}
} else {
return lang.get("repetition_msg", {
const repeatMessage = lang.get("repetition_msg", {
"{interval}": repeatRule.interval,
"{timeUnit}": getFrequencyTimeUnit(downcast(repeatRule.frequency)),
})

const advancedRule = buildReadableAdvancedRepetitionRule(repeatRule.advancedRules, downcast(repeatRule.frequency))

return `${repeatMessage}. ${advancedRule}`.trim()
}

return null
}

function buildReadableAdvancedRepetitionRule(advancedRule: AdvancedRepeatRule[], frequency: RepeatPeriod): string {
const hasInvalidRules = advancedRule.some(
(rule) => !((frequency === RepeatPeriod.WEEKLY || frequency === RepeatPeriod.MONTHLY) && rule.ruleType === ByRule.BYDAY),
)

let translationKey: TranslationKey = "withCustomRules_label"
if (hasInvalidRules) {
return lang.get(translationKey)
}

const days: string[] = []

advancedRule.forEach((item) => {
switch (item.ruleType) {
case ByRule.BYDAY:
days.push(item.interval)
break
default:
return lang.get(translationKey)
}
})

if (days.length === 0) return ""

if (frequency === RepeatPeriod.MONTHLY) {
const ruleRegex = /^([-+]?\d{0,3})([a-zA-Z]{2})?$/g

const parsedRuleValue = Array.from(days[0].matchAll(ruleRegex)).flat()

const day = parseShortDay(parsedRuleValue[2] ?? "")
const leadingValue = Number.parseInt(parsedRuleValue[1])

if (leadingValue === 1) {
translationKey = "firstOfPeriod_label"
} else if (leadingValue === 2) {
translationKey = "secondOfPeriod_label"
} else if (leadingValue === -1) {
translationKey = "lastOfPeriod_label"
} else if (!Number.isNaN(leadingValue)) {
translationKey = "nthOfPeriod_label"
}

return lang.get(translationKey, {
"{days}": day,
"{n}": leadingValue,
})
}

return lang.get("onDays_label", {
"{days}": joinWithAnd(
days.map((day) => parseShortDay(day)),
", ",
lang.get("and_label"),
),
})
}

function joinWithAnd(items: any[], separator: string, lastSeparator: string) {
if (items.length > 1) {
const last = items.pop()
const joinedString = items.join(separator)

return `${joinedString} ${lastSeparator} ${last}`
}

return items.join(separator)
}

/**
* @returns {string} The returned string includes a leading separator (", " or " ").
* @returns {string} The returned string includes a leading separator (", " or "").
*/
export function formatRepetitionEnd(repeatRule: RepeatRule, isAllDay: boolean): string {
switch (repeatRule.endType) {
Expand Down Expand Up @@ -287,6 +369,27 @@ function getFrequencyTimeUnit(frequency: RepeatPeriod): string {
}
}

function parseShortDay(day: string) {
switch (day) {
case "MO":
return lang.get("monday_label")
case "TU":
return lang.get("tuesday_label")
case "WE":
return lang.get("wednesday_label")
case "TH":
return lang.get("thursday_label")
case "FR":
return lang.get("friday_label")
case "SA":
return lang.get("saturday_label")
case "SU":
return lang.get("sunday_label")
default:
return ""
}
}

function prepareAttendees(attendees: Array<CalendarEventAttendee>, organizer: EncryptedMailAddress | null): Array<CalendarEventAttendee> {
// We copy the attendees array so that we can add the organizer, in the case that they are not already in attendees
// This is just for display purposes. We need to copy because event.attendees is the source of truth for the event
Expand Down
21 changes: 4 additions & 17 deletions src/common/misc/TranslationKey.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1896,27 +1896,14 @@ export type TranslationKeyType =
| "friday_label"
| "saturday_label"
| "sunday_label"
| "january_label"
| "february_label"
| "march_label"
| "april_label"
| "may_label"
| "june_label"
| "july_label"
| "august_label"
| "september_label"
| "october_label"
| "november_label"
| "december_label"
| "firstOfPeriod_label"
| "secondOfPeriod_label"
| "thirdOfPeriod_label"
| "nthOfPeriod_label"
| "lastOfPeriod_label"
| "onNDayOfPeriod_label"
| "inMonths_label"
| "onDays_label"
| "inWeek_label"
| "afterStartOfPeriod_label"
| "and_label"
| "beforeEndOfPeriod_label"
| "withCustomRules_label"
| "unsupportedAdvancedRules_msg"
// Put in temporarily, will be removed soon
| "localAdminGroup_label"
Expand Down
15 changes: 15 additions & 0 deletions src/mail-app/translations/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,21 @@ export default {
"yourFolders_action": "DEINE ORDNER",
"yourMessage_label": "Deine Nachricht",
"you_label": "Du",
"monday_label": "Montag",
"tuesday_label": "Dienstag",
"wednesday_label": "Mittwoch",
"thursday_label": "Donnerstag",
"friday_label": "Freitag",
"saturday_label": "Samstag",
"sunday_label": "Sonntag",
"and_label": "und",
"firstOfPeriod_label": "Am ersten {day} des Monats",
"secondOfPeriod_label": "Am zweiten {day} des Monats",
"thirdOfPeriod_label": "Am dritten {day} des Monats",
"nthOfPeriod_label": "Am {n}-ten {day} des Monats",
"lastOfPeriod_label": "Am letzten {day} des Monats",
"withCustomRules_label": "Mit benutzerdefinierten Wiederholungsregeln",
"unsupportedAdvancedRules_msg": "Dieses Ereignis enthält eine oder mehrere nicht unterstützte erweiterte Wiederholungsregeln; jede Änderung führt zum Verlust dieser Regeln.",
// Put in temporarily, will be removed soon
"localAdminGroup_label": "Local admin group",
"assignAdminRightsToLocallyAdministratedUserError_msg": "You can't assign global admin rights to a locally administrated user.",
Expand Down
15 changes: 15 additions & 0 deletions src/mail-app/translations/de_sie.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1909,6 +1909,21 @@ export default {
"yourFolders_action": "Ihre ORDNER",
"yourMessage_label": "Ihre Nachricht",
"you_label": "Sie",
"monday_label": "Montag",
"tuesday_label": "Dienstag",
"wednesday_label": "Mittwoch",
"thursday_label": "Donnerstag",
"friday_label": "Freitag",
"saturday_label": "Samstag",
"sunday_label": "Sonntag",
"and_label": "und",
"firstOfPeriod_label": "Am ersten {day} des Monats",
"secondOfPeriod_label": "Am zweiten {day} des Monats",
"thirdOfPeriod_label": "Am dritten {day} des Monats",
"nthOfPeriod_label": "Am {n}-ten {day} des Monats",
"lastOfPeriod_label": "Am letzten {day} des Monats",
"withCustomRules_label": "Mit benutzerdefinierten Wiederholungsregeln",
"unsupportedAdvancedRules_msg": "Dieses Ereignis enthält eine oder mehrere nicht unterstützte erweiterte Wiederholungsregeln; jede Änderung führt zum Verlust dieser Regeln.",
// Put in temporarily, will be removed soon
"localAdminGroup_label": "Local admin group",
"assignAdminRightsToLocallyAdministratedUserError_msg": "You can't assign global admin rights to a locally administrated user.",
Expand Down
30 changes: 8 additions & 22 deletions src/mail-app/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1912,30 +1912,16 @@ export default {
"friday_label": "Friday",
"saturday_label": "Saturday",
"sunday_label": "Sunday",
"january_label": "January",
"february_label": "February",
"march_label": "March",
"april_label": "April",
"may_label": "May",
"june_label": "June",
"july_label": "July",
"august_label": "August",
"september_label": "September",
"october_label": "October",
"november_label": "November",
"december_label": "December",
"firstOfPeriod_label": "First {day} of the {period}",
"lastOfPeriod_label": "Last {day} of the {period}",
"onNDayOfPeriod_label": "on {day} of {period}",
"theYear_label": "the Year",
"theMonth_label": "the Month",
"inMonths_label": "in {months}",
"onDays_label": "on {days}",
"inWeek_label": "in weeks {weeks}",
"afterStartOfPeriod_label": "{days} occurrence after start of the {period}",
"onDays_label": "On {days}",
"and_label": "and",
"beforeEndOfPeriod_label": "{days} occurrence before end of the {period}",
"firstOfPeriod_label": "On first {day} of the month",
"secondOfPeriod_label": "On second {day} of the month",
"thirdOfPeriod_label": "On third {day} of the month",
"nthOfPeriod_label": "On {n}th {day} of the month",
"lastOfPeriod_label": "On last {day} of the month",
"withCustomRules_label": "With custom repeat rules",
"unsupportedAdvancedRules_msg": "This event contains one or more unsupported Advanced Recurrence Rules, any changes will result in the loss of these rules",
"beforeEndOfPeriod_label": "{days} occurrence before end of the {period}",
// Put in temporarily, will be removed soon
"localAdminGroup_label": "Local admin group",
"assignAdminRightsToLocallyAdministratedUserError_msg": "You can't assign global admin rights to a locally administrated user.",
Expand Down

0 comments on commit 30a7bb4

Please sign in to comment.