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

[Brand Updates] Add missing periods to Empty State messages #14940

Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ private extension BlazeCampaignListView {
static let create = NSLocalizedString("Create", comment: "Title of the button to create a new campaign on the Blaze campaign list view")
static let emptyStateTitle = NSLocalizedString("No campaigns yet", comment: "Title of the empty state of the Blaze campaign list view")
static let emptyStateMessage = NSLocalizedString(
"Drive more sales to your store with Blaze",
"Drive more sales to your store with Blaze.",
comment: "Subtitle of the empty state of the Blaze campaign list view"
)
static let done = NSLocalizedString("Done", comment: "Button to dismiss the Blaze campaign detail view")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ extension BlazeTargetLocationPickerViewModel {
enum Localization {
static let searchViewHintMessage = NSLocalizedString(
"blazeTargetLocationPickerViewModel.searchViewHintMessage",
value: "Start typing country, state or city to see available options",
value: "Start typing country, state or city to see available options.",
comment: "Hint message to enter search query on the target location picker for campaign creation"
)
static let longerQuery = NSLocalizedString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ extension CustomFieldsListHostingController {
static let emptyStateDescription = NSLocalizedString(
"customFieldsListHostingController.emptyStateDescription",
value: "Custom fields are optional metadata to display extra information or customize "
+ "your store's shopping experience",
+ "your store's shopping experience.",
comment: "Message when the list is empty."
)
static let emptyStateButton = NSLocalizedString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private extension CustomersListView {
value: "No customers yet",
comment: "Title when there are no customers to show in the Customers list screen.")
static let emptyStateMessage = NSLocalizedString("customerList.emptyStateMessage",
value: "Create an order to start gathering customer insights",
value: "Create an order to start gathering customer insights.",
comment: "Message when there are no customers to show in the Customers list screen.")
static let searchPlaceholder = NSLocalizedString("customersList.searchPlaceholder",
value: "Search for customers",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ private extension DashboardView {

static let subtitle = NSLocalizedString(
"dashboardView.shareStoreCard.subtitle",
value: "Use email or social media to spread the word about your store",
value: "Use email or social media to spread the word about your store.",
comment: "Subtitle of the Share Your Store card"
)

Expand Down
2 changes: 1 addition & 1 deletion WooCommerce/Classes/ViewRelated/Inbox/Inbox.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private extension Inbox {
static let title = NSLocalizedString("Inbox", comment: "Title for the screen that shows inbox notes.")
static let emptyStateTitle = NSLocalizedString("Congrats, you’ve read everything!",
comment: "Title displayed if there are no inbox notes in the inbox screen.")
static let emptyStateMessage = NSLocalizedString("Come back soon for more tips and insights on growing your store",
static let emptyStateMessage = NSLocalizedString("Come back soon for more tips and insights on growing your store.",
comment: "Message displayed if there are no inbox notes to display in the inbox screen.")
static let dismissAllNotes = NSLocalizedString("Dismiss All",
comment: "Dismiss All button in Inbox Notes for dismissing all the notes.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1000,7 +1000,7 @@ private extension OrderListViewController {
enum Localization {
static let allOrdersEmptyStateMessage = NSLocalizedString("Waiting for your first order",
comment: "The message shown in the Orders → All Orders tab if the list is empty.")
static let allOrdersEmptyStateDetail = NSLocalizedString("Explore how you can increase your store sales",
static let allOrdersEmptyStateDetail = NSLocalizedString("Explore how you can increase your store sales.",
comment: "The detailed message shown in the Orders → All Orders tab if the list is empty.")
static let learnMore = NSLocalizedString("Learn more", comment: "Title of button shown in the Orders → All Orders tab if the list is empty.")
static let createTestOrderDetail = NSLocalizedString(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -807,7 +807,7 @@ private extension ProductVariationsViewController {
enum Localization {
static let emptyStateTitle = NSLocalizedString("Create your first variation",
comment: "Title on the variations list screen when there are no variations")
static let emptyStateSubtitle = NSLocalizedString("To add a variation, you'll need to set its attributes (ie \"Color\", \"Size\") first",
static let emptyStateSubtitle = NSLocalizedString("To add a variation, you'll need to set its attributes (ie \"Color\", \"Size\") first.",
comment: "Subtitle on the variations list screen when there are no variations and attributes")
static let addAttributesAction = NSLocalizedString("Add Attributes",
comment: "Title on empty state button when the product has no attributes and variations")
Expand Down
24 changes: 0 additions & 24 deletions WooCommerce/Resources/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -1916,9 +1916,6 @@ which should be translated separately and considered part of this sentence. */
/* Message indicating no search result on the target location picker for campaign creation */
"blazeTargetLocationPickerViewModel.noResult" = "No location found.\nPlease try again.";

/* Hint message to enter search query on the target location picker for campaign creation */
"blazeTargetLocationPickerViewModel.searchViewHintMessage" = "Start typing country, state or city to see available options";

/* Title of the row to select all target location for Blaze campaign creation */
"blazeTargetLocationSearchView.allTitle" = "Everywhere";

Expand Down Expand Up @@ -2698,9 +2695,6 @@ which should be translated separately and considered part of this sentence. */
/* Country option for a site address. */
"Colombia" = "Colombia";

/* Message displayed if there are no inbox notes to display in the inbox screen. */
"Come back soon for more tips and insights on growing your store" = "Come back soon for more tips and insights on growing your store";

/* Country option for a site address. */
"Comoros" = "Comoros";

Expand Down Expand Up @@ -3383,9 +3377,6 @@ which should be translated separately and considered part of this sentence. */
/* Title when there are no customers in the search results in the Customers list screen. */
"customerList.emptySearchTitle" = "No customers found";

/* Message when there are no customers to show in the Customers list screen. */
"customerList.emptyStateMessage" = "Create an order to start gathering customer insights";

/* Title when there are no customers to show in the Customers list screen. */
"customerList.emptyStateTitle" = "No customers yet";

Expand Down Expand Up @@ -3476,9 +3467,6 @@ which should be translated separately and considered part of this sentence. */
/* Text for button that's shown when the list is empty. */
"customFieldsListHostingController.emptyStateButton" = "Learn more";

/* Message when the list is empty. */
"customFieldsListHostingController.emptyStateDescription" = "Custom fields are optional metadata to display extra information or customize your store's shopping experience";

/* Title for the message when the list is empty. */
"customFieldsListHostingController.emptyStateTitle" = "No custom fields found";

Expand Down Expand Up @@ -3606,9 +3594,6 @@ which should be translated separately and considered part of this sentence. */
/* Label of the button to share the store */
"dashboardView.shareStoreCard.shareButtonLabel" = "Share Your Store";

/* Subtitle of the Share Your Store card */
"dashboardView.shareStoreCard.subtitle" = "Use email or social media to spread the word about your store";

/* Title of the Share Your Store card */
"dashboardView.shareStoreCard.title" = "Get the word out!";

Expand Down Expand Up @@ -3977,9 +3962,6 @@ which should be translated separately and considered part of this sentence. */
/* Drag and drop helper text above photo list in Product images screen */
"Drag and drop to re-order photos" = "Drag and drop to re-order photos";

/* Subtitle of the empty state of the Blaze campaign list view */
"Drive more sales to your store with Blaze" = "Drive more sales to your store with Blaze";

/* Button title to duplicate a product in Product More Options Action Sheet */
"Duplicate" = "Duplicate";

Expand Down Expand Up @@ -4520,9 +4502,6 @@ which should be translated separately and considered part of this sentence. */
/* Button title to explore an extension that isn't installed */
"Explore" = "Explore";

/* The detailed message shown in the Orders → All Orders tab if the list is empty. */
"Explore how you can increase your store sales" = "Explore how you can increase your store sales";

/* Display label for affiliate product type. */
"External/Affiliate" = "External/Affiliate";

Expand Down Expand Up @@ -11332,9 +11311,6 @@ which should be translated separately and considered part of this sentence. */
/* Description text for the product discount row informational tooltip */
"To add a Product Discount, please remove all Coupons from your order" = "To add a Product Discount, please remove all Coupons from your order";

/* Subtitle on the variations list screen when there are no variations and attributes */
"To add a variation, you'll need to set its attributes (ie \"Color\", \"Size\") first" = "To add a variation, you'll need to set its attributes (ie \"Color\", \"Size\") first";

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to remove these strings from Localizable.strings, since they will be removed automatically during the code freeze.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with localization process for iOS, so please bear with me here 😅.

I did this because I noticed it was done before multiple times for similar cases (history of the file), if I don't update the file like this, then the old Strings defined in the file will keep showing until the localization is done, which would happen at the end of the code freeze if I'm not mistaken, and this would mean releasing the first beta build with the old strings, WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since they will be removed automatically during the code freeze.

There are two cases here I think, for Strings with defined keys, they won't be removed, they will be updated, and it's for them that my remark above applies.
For the others, I agree, there is no need to remove them, but since we need to remove some, I'm not sure if it's worth it to revert them 🤔.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry Hicham, it's understandable if you are not familiar with the process. 😉
Here you can find the instructions on how the localization works in WCiOS.
Basically, you don't need to touch the Localizable.string file. If you delete a string, no other work is needed. While if you update a string, be sure to update the key as well in the code. But also in this last case, you don't need to modify the Localizable.string.
TBH, I would revert the file, just because I wouldn't want this change to create problems for the automatic Localizable file update process.

Copy link
Member Author

@hichamboushaba hichamboushaba Jan 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think something is still missing in the discussion, I already checked the above document, and it doesn't talk about the issue here: updating the content of some existing keys, from what I see, in the past other developers resorted to different processes: either update the content in the Localizable.string as well, or delete the key, if you prefer updating I can do it too, but it still means touching the file manually, I don't think created any issues in the past, as Glotpress will still download a new updated file at the end of the code freeze.

TBH, I would revert the file, just because I wouldn't want this change to create problems for the automatic Localizable file update process.

As I shared above, this will mean we'll release the beta at the start of code freeze with the old content, and it would also mean issues during the design review expected before giving the green light for the project.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @AliSoftware for the great insights, I don't think what you shared here is common knowledge, and at least in Android, we tend to frequently update the English copies directly in strings.xml when making just content changes (Strings that placeholders is another topic that I think most developers should be aware of), so I think we should update our docs to explicitly mention that the key|value pair should immutable once sent for translation.

mostly due to the imbalance that we send originals from trunk but pull translations into release/*

TIL, can I ask why this the process and why we don't take the originals from release/* at the start of code freeze? I always thought it was taking from release/*.


For this PR specifically, since we are just adding periods to some strings, which won't cause a significant change to translation, I think we should be safe, right?

Copy link
Contributor

@AliSoftware AliSoftware Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @AliSoftware for the great insights, I don't think what you shared here is common knowledge, and at least in Android, we tend to frequently update the English copies directly in strings.xml when making just content changes (Strings that placeholders is another topic that I think most developers should be aware of), so I think we should update our docs to explicitly mention that the key|value pair should immutable once sent for translation.

FWIW, I've written all those in a couple of past P2s a while ago, so an MGS search should give you some additional info; I've also made a presentation about all that during the WordPress team meetup in Porto 2022 (with slides and all), and most of that presentation applies to Woo and other products as well, in case that helps better understanding all that.

TIL, can I ask why this the process and why we don't take the originals from release/* at the start of code freeze? I always thought it was taking from release/*.

Well actually you're right, strings are also frozen before we send them to GlotPress:

  • For WCiOS, since the Localizable.strings file is not supposed to be edited by developers and is instead generated using genstrings (from the content of the codebase) at the time we do the code-freeze, then the content of the en.lproj/Localizable.strings should always reflect the content of the last frozen state. So even if we later backmerge release/* into trunk and the en.lproj/Localizable.strings that got generated right after the code freeze is back-propagated to trunk, its content is always supposed to reflect what's used in the code that is in the release/* branch, because that's the only time that file gets regenerated/updated (right after code-freeze)
  • For WCAndroid, while the values/strings.xml can be modified by devs manually anytime, during code-freeze we make a copy of that file into fastlane/resources/values/strings.xml, which is then the file that gets imported into GlotPress by the wpcom job. This ensures that even if the original strings.xml gets updated post-code-freeze by devs working on features, those changes won't get imported into GlotPress, only the changes that were frozen/copied into fastlane/resources/ during code-freeze will (and that file is not supposed to be changed manually either)

So in practice the strings that are sent to GlotPress are indeed the ones as they are at the beginning of the release/* branch right after the code freeze happened.

Which in theory means that this should cover the cases where a string is modified in trunk while it has already been sent to GlotPress during the current code-freeze and creation of the release/* branch: such a change in trunk should not impact GlotPress after all, at least not until the next code-freeze.

But there's still a risk of a key/string that was already previously translated into GlotPress and gets changed later but its new value is only partially translated while the key remains the same… in which case, while I think that GlotPress is able to be smart enough to mark such strings as "needing revision" when it detects the original changed, I fear there's still a risk that an old translation of the old string could still get pulled into the release/* branch and create an inconsistency…

Note

This is not true for all our products, for example Tumblr uses a different approach where they send the strings to the translators continuously from trunk because their code-freeze period is only one week and it'd be too short for the paid translators to translate too many strings in all locales in time if they were only sent on code-freeze Monday to be collected on Thursday to be ready for Friday's submission).
So there are products, like Tumblr, for which the risk is higher given the different process, and for which keeping those strings immutable is even more important (Internal ref: paaHJt-51A-p2); while for Woo at least we have less chances of this happening given the strings are only sent to translation once frozen.

That's why our policy about those cases have still always been "better safe than sorry"—especially since we encountered crashes due to mismatching placeholders in different locales/translations due to such cases in the past and encouraging to consider strings to be immutable helps put all the chances on our side to prevent this from happening again in the future.

For this PR specifically, since we are just adding periods to some strings, which won't cause a significant change to translation, I think we should be safe, right?

Yep, if the change is only a typo in the English copy that would not change the meaning / semantics of the copy (e.g. from "plan_price_subtitle" = "This plan is completely free!" to `"plan_price_subtitle" = "This plan is a paid option, but you can get 10% off the first month.") and that the typo that was present in the English copy is likely not present in the translations (as they would have self-corrected it while translating to the new locale)… then this should be all ok and not cause any trouble.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again Olivier 🙏

FWIW, I've written all those in a couple of past P2s a while ago

Yes, I've checked the P2 that Paolo shared above, and saw also the slides of the presentation you made (thanks btw ❤️), and unless I missed it, I didn't see any explicit mentions about the immutability point, and from my day to day experience, I can tell you the other Android devs are also not aware of this (maybe iOS devs too based on the git history 😅), and that's why I suggested we update our documentation to state this explicitly, I'll try to find some time to handle this for Android.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I think at the time I wrote the slides of the presentation (and also at the time some of the past P2s were written) we didn't yet have the rule of thumb to consider strings immutable; it's mostly when we encountered the crashers later—plus seeing how it was an even bigger problem with some other product's processes (like Tumblr)—that we started to enforce this.

@iangmaia I think there have been discussions as well about introducing a Danger check to warn if developers were modifying an existing key as part of a PR? At least it could be an idea to consider. Not sure how easy it'd be—for iOS it'd mostly be detecting manual changes in the en.lproj/Localizable.strings on any PR other than the code-freeze one, for Android it'd be a bit trickier to detect changes in existing keys (even if the corresponding lines in the strings.xml were also moved to a different line in the file and not just changed in place) all while not detecting additions of new strings as false-positives…—but I'm sure there are ideas to experiment with…

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do recall some ideas around strings immutability. Tthere's this issue already created, but it seems like something else. I think I'll just update it to consider these other possible scenarios as well.

/* Error message displayed when unable to close user account due to having active atomic site. */
"To close this account now, contact our support team." = "To close this account now, contact our support team.";

Expand Down
Loading