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

[Tooling] Migrate iOS13 Widgets to use App strings #17630

Merged
merged 6 commits into from
Dec 8, 2021
Merged
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
69 changes: 69 additions & 0 deletions WordPress/Classes/Utility/AppLocalizedString.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import SwiftUI


extension Bundle {
/// Returns the `Bundle` for the host `.app`.
///
/// - If this is called from code already located in the main app's bundle or from a Pod/Framework,
/// this will return the same as `Bundle.main`, aka the bundle of the app itself.
/// - If this is called from an App Extension (Widget, ShareExtension, etc), this will return the bundle of the
/// main app hosting said App Extension (while `Bundle.main` would return the App Extension itself)
///
/// This is particularly useful to reference a resource or string bundled inside the app from an App Extension / Widget.
///
/// - Note:
/// In the context of Unit Tests this will return the Test Harness (aka Test Host) app, since that is the app running said tests.
///
static let app: Bundle = {
var url = Bundle.main.bundleURL
while url.pathExtension != "app" && url.lastPathComponent != "/" {
url.deleteLastPathComponent()
}
guard let appBundle = Bundle(url: url) else { fatalError("Unable to find the parent app bundle") }
return appBundle
}()
}

/// Use this to express *intent* on your API that the string you are manipulating / returning is intended to already be localized
/// and its value to have been provided via a call to `NSLocalizedString` or `AppLocalizedString`.
///
/// Semantically speaking, a method taking or returning a `LocalizedString` is signaling that you can display said UI string
/// to the end user, without the need to be treated as a key to be localized. The string is expected to already have been localized
/// at that point of the code, via a call to `NSLocalizedString`, `AppLocalizedString` or similar upstream in the code.
///
/// - Note: Remember though that, as a `typealias`, this won't provide any compile-time guarantee.
typealias LocalizedString = String

/// Use this function instead of `NSLocalizedString` to reference localized strings **from the app bundle** – especially
/// when using localized strings from the code of an app extension.
///
/// You should use this `AppLocalizedString` method in place of `NSLocalizedString` especially when calling it
/// from App Extensions and Widgets, in order to reference strings whose localization live in the app bundle's `.strings` file
/// (rather than the AppExtension's own bundle).
///
/// In order to avoid duplicating our strings accross targets, and make our localization process & tooling easier, we keep all
/// localized `.strings` in the app's bundle (and don't have a `.strings` file in the App Extension targets themselves);
/// then we make those App Extensions & Widgets reference the strings from the `Localizable.strings` files
/// hosted in the app bundle itself – which is when this helper method is helpful.
///
/// - Note:
/// Tooling: Be sure to pass this function's name as a custom routine when parsing the code to generate the main `.strings` file,
/// using `genstrings -s AppLocalizedString`, so that this helper method is recognized. You will also have to
/// exclude this very file from being parsed by `genstrings`, so that it won't accidentally misinterpret that routine/function definition
/// below as a call site and generate an error because of it.
///
/// - Parameters:
/// - key: An identifying value used to reference a localized string.
/// - tableName: The basename of the `.strings` file **in the app bundle** containing
/// the localized values. If `tableName` is `nil`, the `Localizable` table is used.
/// - value: The English/default copy for the string. This is the user-visible string that the
/// translators will use as original to translate, and also the string returned when the localized string for
/// `key` cannot be found in the table. If `value` is `nil` or empty, `key` would be returned instead.
/// - comment: A note to the translator describing the context where the localized string is presented to the user.
///
/// - Returns: A localized version of the string designated by `key` in the table identified by `tableName`.
/// If the localized string for `key` cannot be found within the table, `value` is returned.
/// (However, `key` is returned instead when `value` is `nil` or the empty string).
func AppLocalizedString(_ key: String, tableName: String? = nil, value: String? = nil, comment: String) -> LocalizedString {
Bundle.app.localizedString(forKey: key, value: value, table: nil)
}
45 changes: 33 additions & 12 deletions WordPress/Classes/ViewRelated/Stats/Extensions/Double+Stats.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,39 @@ extension Double {
struct Cache {
static let units: [Unit] = {
var units: [Unit] = []

units.append(Unit(abbreviationFormat: NSLocalizedString("%@K", comment: "Label displaying value in thousands. Ex: 66.6K."), accessibilityLabelFormat: NSLocalizedString("%@ thousand", comment: "Accessibility label for value in thousands. Ex: 66.6 thousand.")))

units.append(Unit(abbreviationFormat: NSLocalizedString("%@M", comment: "Label displaying value in millions. Ex: 66.6M."), accessibilityLabelFormat: NSLocalizedString("%@ million", comment: "Accessibility label for value in millions. Ex: 66.6 million.")))

units.append(Unit(abbreviationFormat: NSLocalizedString("%@B", comment: "Label displaying value in billions. Ex: 66.6B."), accessibilityLabelFormat: NSLocalizedString("%@ billion", comment: "Accessibility label for value in billions. Ex: 66.6 billion.")))

units.append(Unit(abbreviationFormat: NSLocalizedString("%@T", comment: "Label displaying value in trillions. Ex: 66.6T."), accessibilityLabelFormat: NSLocalizedString("%@ trillion", comment: "Accessibility label for value in trillions. Ex: 66.6 trillion.")))

units.append(Unit(abbreviationFormat: NSLocalizedString("%@P", comment: "Label displaying value in quadrillions. Ex: 66.6P."), accessibilityLabelFormat: NSLocalizedString("%@ quadrillion", comment: "Accessibility label for value in quadrillion. Ex: 66.6 quadrillion.")))

units.append(Unit(abbreviationFormat: NSLocalizedString("%@E", comment: "Label displaying value in quintillions. Ex: 66.6E."), accessibilityLabelFormat: NSLocalizedString("%@ quintillion", comment: "Accessibility label for value in quintillions. Ex: 66.6 quintillion.")))
// Note: using `AppLocalizedString` here (instead of `NSLocalizedString`) to ensure that strings
// will be looked up from the app's _own_ `Localizable.strings` file, even when this file is used
// as part of an _App Extension_ (especially our various stats Widgets which also use this file)

units.append(Unit(
abbreviationFormat: AppLocalizedString("%@K", comment: "Label displaying value in thousands. Ex: 66.6K."),
accessibilityLabelFormat: AppLocalizedString("%@ thousand", comment: "Accessibility label for value in thousands. Ex: 66.6 thousand.")
))

units.append(Unit(
abbreviationFormat: AppLocalizedString("%@M", comment: "Label displaying value in millions. Ex: 66.6M."),
accessibilityLabelFormat: AppLocalizedString("%@ million", comment: "Accessibility label for value in millions. Ex: 66.6 million.")
))

units.append(Unit(
abbreviationFormat: AppLocalizedString("%@B", comment: "Label displaying value in billions. Ex: 66.6B."),
accessibilityLabelFormat: AppLocalizedString("%@ billion", comment: "Accessibility label for value in billions. Ex: 66.6 billion.")
))

units.append(Unit(
abbreviationFormat: AppLocalizedString("%@T", comment: "Label displaying value in trillions. Ex: 66.6T."),
accessibilityLabelFormat: AppLocalizedString("%@ trillion", comment: "Accessibility label for value in trillions. Ex: 66.6 trillion.")
))

units.append(Unit(
abbreviationFormat: AppLocalizedString("%@P", comment: "Label displaying value in quadrillions. Ex: 66.6P."),
accessibilityLabelFormat: AppLocalizedString("%@ quadrillion", comment: "Accessibility label for value in quadrillion. Ex: 66.6 quadrillion.")
))

units.append(Unit(
abbreviationFormat: AppLocalizedString("%@E", comment: "Label displaying value in quintillions. Ex: 66.6E."),
accessibilityLabelFormat: AppLocalizedString("%@ quintillion", comment: "Accessibility label for value in quintillions. Ex: 66.6 quintillion.")
))

return units
}()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ private extension WidgetDifferenceCell {
enum Constants {
static let noDataLabel = "-"
static let cornerRadius: CGFloat = 4.0
static let today = NSLocalizedString("Today", comment: "Label for most recent stat row.")
static let today = AppLocalizedString("Today", comment: "Label for most recent stat row.")
static let positiveColor: UIColor = .success
static let negativeColor: UIColor = .error
static let neutralColor: UIColor = .neutral(.shade40)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ private extension WidgetNoConnectionCell {
}

enum LocalizedText {
static let title = NSLocalizedString("No network available", comment: "Displayed in the Stats widgets when there is no network")
static let message = NSLocalizedString("Stats will be updated next time you're online", comment: "Displayed in the Stats widgets when there is no network")
static let title = AppLocalizedString("No network available", comment: "Displayed in the Stats widgets when there is no network")
static let message = AppLocalizedString("Stats will be updated next time you're online", comment: "Displayed in the Stats widgets when there is no network")
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ private extension WidgetUnconfiguredCell {
}

enum LocalizedText {
static let configureToday = NSLocalizedString("Display your site stats for today here. Configure in the WordPress app in your site stats.", comment: "Unconfigured stats today widget helper text")
static let configureAllTime = NSLocalizedString("Display your all-time site stats here. Configure in the WordPress app in your site stats.", comment: "Unconfigured stats all-time widget helper text")
static let configureThisWeek = NSLocalizedString("Display your site stats for this week here. Configure in the WordPress app in your site stats.", comment: "Unconfigured stats this week widget helper text")
static let openWordPress = NSLocalizedString("Open WordPress", comment: "Today widget label to launch WP app")
static let loadingFailed = NSLocalizedString("Couldn't load data", comment: "Message displayed when a Stats widget failed to load data.")
static let retry = NSLocalizedString("Retry", comment: "Stats widgets label to reload the widget.")
static let configureToday = AppLocalizedString("Display your site stats for today here. Configure in the WordPress app in your site stats.", comment: "Unconfigured stats today widget helper text")
static let configureAllTime = AppLocalizedString("Display your all-time site stats here. Configure in the WordPress app in your site stats.", comment: "Unconfigured stats all-time widget helper text")
static let configureThisWeek = AppLocalizedString("Display your site stats for this week here. Configure in the WordPress app in your site stats.", comment: "Unconfigured stats this week widget helper text")
static let openWordPress = AppLocalizedString("Open WordPress", comment: "Today widget label to launch WP app")
static let loadingFailed = AppLocalizedString("Couldn't load data", comment: "Message displayed when a Stats widget failed to load data.")
static let retry = AppLocalizedString("Retry", comment: "Stats widgets label to reload the widget.")
}

}
Loading