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

Add English localization #107

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions ViteMaDose.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@
57FE5C0E261FA84D0012B66D /* UIColor+VideMaDose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+VideMaDose.swift"; sourceTree = "<group>"; };
6A28354B262DC06C00FA6456 /* ViteMaDose.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ViteMaDose.entitlements; sourceTree = "<group>"; };
889B9A49263307EC00175E24 /* .swiftlint.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = .swiftlint.yml; sourceTree = "<group>"; };
A17FECFE264D301E0044E034 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
A17FECFF264D301F0044E034 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
DA234DC22626494600D6F71C /* remote-configuration.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "remote-configuration.plist"; sourceTree = "<group>"; };
DA234DD02626506600D6F71C /* RemoteConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteConfig.swift; sourceTree = "<group>"; };
DA4D9952261E6B6A00D28AD0 /* LocationSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationSearchViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -715,6 +717,7 @@
knownRegions = (
fr,
Base,
en,
);
mainGroup = 576738B3261E329C004A700D;
packageReferences = (
Expand Down Expand Up @@ -1011,6 +1014,7 @@
isa = PBXVariantGroup;
children = (
57B2BCA42633B254001B3D61 /* fr */,
A17FECFE264D301E0044E034 /* en */,
);
name = Localizable.strings;
sourceTree = "<group>";
Expand All @@ -1019,6 +1023,7 @@
isa = PBXVariantGroup;
children = (
57DEAA04263444BB005E8628 /* fr */,
A17FECFF264D301F0044E034 /* en */,
);
name = Localizable.stringsdict;
sourceTree = "<group>";
Expand Down
18 changes: 9 additions & 9 deletions ViteMaDose/Helpers/Utils/OnboardingManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ enum OnboardingManager {
private static let descriptionFontSize: CGFloat = 18.0

static func makeFirstPage() -> BLTNPageItem {
let page = BLTNPageItem(title: "Vite Ma Dose fait le plein de nouveautés !")
let page = BLTNPageItem(title: Localization.Onboarding.Page1.title)
page.image = "🎉".toImage(ofSize: 60)

let appearance = BLTNItemAppearance()
Expand All @@ -22,8 +22,8 @@ enum OnboardingManager {
appearance.actionButtonColor = .royalBlue

page.appearance = appearance
page.descriptionText = "Découvrez les notifications pour ne rater aucune dose, et les chronodoses permettant à chacun de trouver un rendez-vous en 24h sans restriction."
page.actionButtonTitle = "Suivant"
page.descriptionText = Localization.Onboarding.Page1.description
page.actionButtonTitle = Localization.Onboarding.Page1.button
page.alternativeButton?.isHidden = true
page.isDismissable = false
page.actionHandler = { item in
Expand All @@ -34,7 +34,7 @@ enum OnboardingManager {
}

static func makeNotificationsPage() -> BLTNPageItem {
let page = BLTNPageItem(title: "Notifications")
let page = BLTNPageItem(title: Localization.Onboarding.Page2.title)
page.image = "🔔".toImage(ofSize: 60)

let appearance = BLTNItemAppearance()
Expand All @@ -43,8 +43,8 @@ enum OnboardingManager {
appearance.actionButtonColor = .royalBlue

page.appearance = appearance
page.descriptionText = "Pour ne rater aucun créneau de vaccination, nous avons ajouté un système de notifications ! Pour vous abonner à un centre, rien de plus simple, il suffit de toucher la cloche. Vous recevrez une alerte si nous détectons des disponibilités."
page.actionButtonTitle = "Suivant"
page.descriptionText = Localization.Onboarding.Page2.description
page.actionButtonTitle = Localization.Onboarding.Page2.button
page.alternativeButton?.isHidden = true
page.isDismissable = false
page.actionHandler = { item in
Expand All @@ -56,7 +56,7 @@ enum OnboardingManager {
}

static func makeChronoDosesPage() -> BLTNPageItem {
let page = BLTNPageItem(title: "Chronodoses")
let page = BLTNPageItem(title: Localization.Onboarding.Page3.title)
page.image = "⚡️".toImage(ofSize: 60)

let appearance = BLTNItemAppearance()
Expand All @@ -65,8 +65,8 @@ enum OnboardingManager {
appearance.actionButtonColor = .mandy

page.appearance = appearance
page.descriptionText = "À partir du mercredi 12 mai, vous pourrez réserver les rendez-vous de vaccination vacants du jour même et du lendemain, sans restriction. Nous les appelons les “Chronodoses”, et sont matérialisées par des éclairs et un bandeau rouge."
page.actionButtonTitle = "Merci !"
page.descriptionText = Localization.Onboarding.Page3.description
page.actionButtonTitle = Localization.Onboarding.Page3.button
page.alternativeButton?.isHidden = true
page.isDismissable = false
page.actionHandler = { item in
Expand Down
11 changes: 7 additions & 4 deletions ViteMaDose/Models/VaccinationCentre.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,18 @@ extension VaccinationCentre {
}

var nextAppointmentDate: Date? {
return prochainRdv?.toDate(nil, region: AppConstant.franceRegion)?.date ?? prochainRdv?.toISODate(nil, region: AppConstant.franceRegion)?.date
return prochainRdv?.toDate(nil, region: Region.current)?.date ?? prochainRdv?.toISODate(nil, region: Region.current)?.date
}

var nextAppointmentDay: String? {
return prochainRdv?.toString(with: .date(.long), region: AppConstant.franceRegion)
// Don't display year
// [TODO] Technically an en_US locale should do "MMM dd" instead
return prochainRdv?.toString(with: .custom("dd MMM"), region: Region.current)
}

var nextAppointmentTime: String? {
return prochainRdv?.toString(with: .time(.short), region: AppConstant.franceRegion)
// Avoid AM/PM in English locale
return prochainRdv?.toString(with: .custom("HH:mm"), region: Region.current)
}

var appointmentUrl: URL? {
Expand Down Expand Up @@ -230,7 +233,7 @@ struct VaccinationCentres: Codable, Hashable {
}

var formattedLastUpdated: String? {
guard let lastUpdateDate = lastUpdated?.toDate(nil, region: AppConstant.franceRegion) else {
guard let lastUpdateDate = lastUpdated?.toDate(nil, region: Region.current) else {
return nil
}

Expand Down
5 changes: 0 additions & 5 deletions ViteMaDose/Resources/AppConstant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,4 @@ import Foundation
import SwiftDate

enum AppConstant {
static let franceRegion = Region(
calendar: Calendar.current,
zone: Zones.current,
locale: Locale(identifier: "fr_FR")
)
}
26 changes: 25 additions & 1 deletion ViteMaDose/Resources/Localization/Localization.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ enum Localization {
}

enum LocationSearch {
static let search_placeholder = "Commune, Code Postal, Département...".localized
static let search_placeholder = "location_search.search_placeholder".localized

enum MainTitle {
static let title = "location_search.main_title".localized
Expand All @@ -42,6 +42,7 @@ enum Localization {
enum Locations {
static let list_title = "locations.list_title".localized
static let followed_list_title = "locations.followed_list_title".localized
static let followed_list_button = "locations.followed_list_button".localized
static let no_results = "locations.no_results".localized
static let available_locations = "locations.available_locations".localized
static let all_locations = "locations.all_locations".localized
Expand All @@ -59,6 +60,7 @@ enum Localization {
}

enum Location {
static let chronodoses_available = "location.chronodoses_available".localized
static let date = "location.date".localized
static let book_button = "location.book_button".localized
static let verify_button = "location.verify_button".localized
Expand All @@ -70,6 +72,8 @@ enum Localization {
static let unavailable_address = "location.unavailable_address".localized
static let start_following_title = "location.start_following_title".localized
static let start_following_message = "location.start_following_message".localized
static let start_following_button_all = "location.start_following_button_all".localized
static let start_following_button_chronodoses = "location.start_following_button_chronodoses".localized
static let follow_action_title = "location.follow_action_title".localized
static let notify_button = "location.notify_button".localized
static let follow_button = "location.follow_button".localized
Expand All @@ -92,4 +96,24 @@ enum Localization {
static let offline = "error.network.offline".localized
}
}

enum Onboarding {
enum Page1 {
static let title = "onboarding.page_1.title".localized
static let description = "onboarding.page_1.description".localized
static let button = "onboarding.page_1.button".localized
}

enum Page2 {
static let title = "onboarding.page_2.title".localized
static let description = "onboarding.page_2.description".localized
static let button = "onboarding.page_2.button".localized
}

enum Page3 {
static let title = "onboarding.page_3.title".localized
static let description = "onboarding.page_3.description".localized
static let button = "onboarding.page_3.button".localized
}
}
}
72 changes: 72 additions & 0 deletions ViteMaDose/Resources/Localization/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
Localizable.strings
ViteMaDose

Created by Philip Blair on 12/05/2021.

*/

// Home
"home.main_title" = "Find a vaccine quickly and easily";
"home.main_title.first_highlighted_text" = "quickly";
"home.main_title.second_highlighted_text" = "easily";
"home.search_placeholder" = "Search...";
"home.last_stats" = "Latest statistics...";
"home.open_map" = "See locations on the map";
"home.partners" = "Find your appointments with";
"home.stats.all_locations" = "Locations found in France";
"home.stats.all_availabilities" = "Appointments available";
"home.stats.locations_with_availabilities" = "Locations with available appointments";
"home.stats.available_locations_percentage" = "Of locations have availabilities";
// Department Selection
"location_search.main_title" = "Select or search for a location in France";
"location_search.main_title.highlighted_text" = "France";
"location_search.search_placeholder" = "Commune, Postal Code, Department...";
// Locations
"locations.list_title" = "List of locations";
"locations.followed_list_button" = "My locations";
"locations.followed_list_title" = "My followed locations";
"locations.no_results" = "We have not found any appointments for %@";
"locations.sort_option.closest" = "Closest";
"locations.sort_option.fastest" = "Available soonest";
// Location
"location.chronodoses_available" = "Chronodoses Available";
"location.date" = "On %@ at %@";
"location.book_button" = "Book an appointment";
"location.verify_button" = "Check with this location";
"location.last_update" = "Last updated on %@ at %@";
"location.no_appointment" = "No appointments";
"location.open_route" = "Show route";
"location.unavailable_date" = "Date unavailable";
"location.unavailable_name" = "Name of location unavailable";
"location.unavailable_address" = "Address unavailable";
// Location start following
"location.start_following_title" = "Start following?";
"location.start_following_message" = "You can choose to be notified for each change in availability or only when Chronodoses become available at this center.";
"location.start_following_button_all" = "All notifications";
"location.start_following_button_chronodoses" = "Chronodoses only";
"location.follow_action_title" = "Follow";
"location.notify_button" = "Be Notified";
"location.follow_button" = "Follow without notifications";
// Location stop following
"location.stop_following_title" = "Stop following this center?";
"location.stop_following_message" = "If you have activated notifications for this center, they will be deactivated.";
"location.unfollow_action_title" = "Stop Following?";
"location.stop_following_button" = "Unfollow";
// Error
"error.generic.title" = "Oops! We're having some technical difficulties...";
"error.generic.retry_button" = "Retry";
"error.generic.cancel_button" = "Cancel";
"error.generic.default_message" = "If the problem persists, please contact the team at https://covidtracker.fr/contact";
"error.network.server_error" = "We've encountered a server error. Please try again later.";
"error.network.offline" = "You appear to be offline.";
// Onboarding
"onboarding.page_1.title" = "Vite Ma Dose has many new features!";
"onboarding.page_1.description" = "Notifications allow you to never miss a new dose, and Chronodoses allow anyone to find an appointment in the next 24 hours without any restrictions.";
"onboarding.page_1.button" = "Next";
"onboarding.page_2.title" = "Notifications";
"onboarding.page_2.description" = "To never miss a vaccination availability, we have added a notification system! To follow a center, it's as simple as pressing the bell icon. You will recieve an alert if we detect any openings.";
"onboarding.page_2.button" = "Next";
"onboarding.page_3.title" = "Chronodoses";
"onboarding.page_3.description" = "Starting 12 May, you can reserve a vaccination appointment the same day or the next day, without restrictions. We call these Chronodoses, and they are denoted by lightning and a red band.";
"onboarding.page_3.button" = "Thank You!";
112 changes: 112 additions & 0 deletions ViteMaDose/Resources/Localization/en.lproj/Localizable.stringsdict
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>locations.available_locations</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string>Locations with appointments</string>
<key>one</key>
<string>Location with appointments</string>
<key>other</key>
<string>Locations with appointments</string>
</dict>
</dict>
<key>locations.all_locations</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string>Total locations found</string>
<key>one</key>
<string>Total location found</string>
<key>other</key>
<string>Total locations found</string>
</dict>
</dict>
<key>locations.appointments</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string>%d appointments</string>
<key>one</key>
<string>%d appointment</string>
<key>other</key>
<string>%d appointments</string>
</dict>
</dict>
<key>locations.main_title_department</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>We have found %d appointment for %@</string>
<key>other</key>
<string>We have found %d appointments for %@</string>
</dict>
</dict>
<key>locations.main_title_city</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>one</key>
<string>We have found %d appointment near %@</string>
<key>other</key>
<string>We have found %d appointments near %@</string>
</dict>
</dict>
<key>home.recent_search</key>
<dict>
<key>New item</key>
<string></string>
<key>NSStringLocalizedFormatKey</key>
<string>%#@count@</string>
<key>count</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string>Recent searches</string>
<key>one</key>
<string>Recent search</string>
<key>other</key>
<string>Recent searches</string>
</dict>
</dict>
</dict>
</plist>
Loading