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

Studio: Translate "About Studio" modal #228

Merged
merged 6 commits into from
Jun 11, 2024

Conversation

katinthehatsite
Copy link
Contributor

@katinthehatsite katinthehatsite commented Jun 10, 2024

Closes https://github.com/Automattic/dotcom-forge/issues/7522

Proposed Changes

This PR makes the strings in the "About Studio" window translatable.

Testing Instructions

  • Pull the changes from this branch locally
  • Before starting the app, modify the language in locale.ts in getPreferredSystemLanguages to return French:
export function getPreferredSystemLanguages() {
	if ( process.platform === 'linux' && process.env.NODE_ENV !== 'test' ) {
			.getPreferredSystemLanguages()
			.filter( ( lang ) => supportedLocales.includes( lang ) );
	}
	return [ 'fr' ];
}
  • Navigate to src/translations/studio-fr.jed.json
  • Add the following strings and translations to the file:
            "Demo sites powered by": [
                "Sites de démonstration propulsés par"
            ],
            "Local sites powered by": [
                "Sites locaux propulsés par"
            ],
            "Share Feedback": [
                "Partager des commentaires"
            ],
            "Studio by WordPress.com": [
                "Studio par WordPress.com"
            ],
            "Version": [
                "Version"
            ]
  • Start the app with nvm use && npm install && npm start
  • Open the About Studio window
  • Confirm that the strings are translated to French:
Capture d’écran, le 2024-06-10 à 13 46 09

Notes:

  • I explored refactoring the HTML file into a React component and then rendering it into this custom window but the solution required modifying the app setup in multiple places. I opted for a more straightforward approach considering that that window is fairly static

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?

@katinthehatsite katinthehatsite requested a review from a team June 10, 2024 11:53
<p class="studio-name">Studio by WordPress.com</p>
<p class="version">Version <span id="version"></span></p>
<p class="studio-name" id="studio-by-wpcom">Studio by WordPress.com</p>
<p class="version"><span id="version-text">Version</span> <span id="version"></span></p>
<p class="links">
<a href="https://github.com/Automattic/studio" target="_blank">GitHub</a>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did not add translation for GitHub since it is a proper name. Happy to add it if it is considered necessary.

Copy link
Member

@sejas sejas left a comment

Choose a reason for hiding this comment

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

I've followed the testing instructions and it works as expected.

Screenshot 2024-06-10 at 23 09 48

I wanted to recommend using esc_attr__ , but it's not part of @wordpress/i18n.
I suggest adding Sentry or sanitizing the strings with a custom function. My concern is that some translation would include a single quote: ' , which would break the string replacements.

document.getElementById('share-feedback').innerText = '${ __( 'Share Feedback' ) }';
document.getElementById('demo-sites').innerText = '${ __( 'Demo sites powered by' ) }';
document.getElementById('local-sites').innerText = '${ __( 'Local sites powered by' ) }';`
)
.catch( ( err ) => {
console.error( 'Error executing JavaScript:', err );
Copy link
Member

Choose a reason for hiding this comment

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

Should we capture the error in sentry?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added in 343ac4d

Comment on lines 44 to 46
`document.getElementById('version').innerText = '${ packageJson }';
document.getElementById('studio-by-wpcom').innerText = '${ __( 'Studio by WordPress.com' ) }';
document.getElementById('version-text').innerText = '${ __( 'Version' ) }';
Copy link
Member

Choose a reason for hiding this comment

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

Let's unify the word Version and the actual number. Something like sprintf( __( 'Version %s' ), packageJson )

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added in af02dbb

<p class="studio-name">Studio by WordPress.com</p>
<p class="version">Version <span id="version"></span></p>
<p class="studio-name" id="studio-by-wpcom">Studio by WordPress.com</p>
<p class="version"><span id="version-text">Version</span> <span id="version"></span></p>
Copy link
Member

Choose a reason for hiding this comment

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

Let's use only one string here, so RTL languages will work better.

Suggested change
<p class="version"><span id="version-text">Version</span> <span id="version"></span></p>
<p class="version"><span id="version-text">Version x.y.z</span></p>

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added in af02dbb

@katinthehatsite
Copy link
Contributor Author

I suggest adding Sentry or sanitizing the strings with a custom function. My concern is that some translation would include a single quote: ' , which would break the string replacements.

Yeah I think you are right, I tried to break it and it did break. Let me conjure something for this. I will re-request review once I am ready

@katinthehatsite
Copy link
Contributor Author

katinthehatsite commented Jun 11, 2024

@sejas I added something simple in 6c1f64f to handle the ' to ensure that it is rendered.

I also found that we have something like https://www.npmjs.com/package/@wordpress/escape-html that we already have available and installed but a single quote breaks when I try to use escapeAtrribute or escapeHMTL. Do you think the fix about would be sufficient for this case in combination with Sentry capture?

Comment on lines +40 to +42
function escapeSingleQuotes( str: string ) {
return str.replace( /'/g, "\\'" );
}
Copy link
Member

@sejas sejas Jun 11, 2024

Choose a reason for hiding this comment

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

Thanks for the changes!

Nice! I tested it and it renders the single quote and it doesn't break the About page.
I tried replacing to &quot;, but it didn't render the correct entity.

Screenshot 2024-06-11 at 13 48 14

I've also seen that @wordpress/escape-html escapeAttribute Only escapes, the >, " and & symbols.

@katinthehatsite katinthehatsite merged commit 216154a into trunk Jun 11, 2024
11 checks passed
@katinthehatsite katinthehatsite deleted the add/translate-about-window branch June 11, 2024 13:52
Copy link
Contributor

@wojtekn wojtekn left a comment

Choose a reason for hiding this comment

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

I explored refactoring the HTML file into a React component and then rendering it into this custom window but the solution required modifying the app setup in multiple places. I opted for a more straightforward approach considering that that window is fairly static

Thanks for sharing the details explaining the approach you took. It seems reasonable to do so.

</div>
<div class="info">
<p>Local sites powered by<br><a href="https://wordpress.org/playground/" target="_blank">WordPress Playground ↗</a></p>
<p><span id="local-sites">Local sites powered by</span><br><a href="https://wordpress.org/playground/" target="_blank">WordPress Playground ↗</a></p>
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need those phrases in two places: here in the template and in the file that replaces those with translations?

Copy link
Member

Choose a reason for hiding this comment

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

Do you mean why the translation is divided in two "divs"?
<p><span id="local-sites">Local sites powered by</span><br><a href="https://wordpress.org/playground/" target="_blank">WordPress Playground ↗</a></p> instead of <p id="local-sites">Local sites powered by<br><a href="https://wordpress.org/playground/" target="_blank">WordPress Playground ↗</a></p>

When reviewing I thought it could produce errors in RTL languages but the fact that we display one on top of the other solves any issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

No, I meant that tests, e.g., Local sites powered by, are now placed in two places.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am guessing that your question is if it could be removed from https://github.com/Automattic/studio/blob/c2c9c20219ea884493bd3ba8ffbc64f2bc5cc1ce/src/about-menu/about-menu.html#L90 since we are inserting it anyway so that it would be something like:

 <p><span id="demo-sites"></span><br><a href="https://wordpress.com/hosting/?utm_source=studio&utm_medium=referral&utm_campaign=about_screen" target="_blank">WordPress.com hosting ↗</a></p>

(so just the id and no text)

Is that right?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, this is correct. I was wondering if, with the current implementation, there is a reason to keep it in the file template, too. Does it work as a fallback, so if the translation couldn't be loaded, we would display the English version included in the template? Or could such a situation not occur?

My point is that keeping the source text in two places comes with a risk that someone updates it in one place, skipping the latter.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's right. The strings in the HTML file serve as fallback content. This ensures that if the JavaScript fails to inject the translations or if there is any issue with the translation strings, the user will still see the default text that is added in the HTML file.

However, you bring up an important point - it might not be obvious that the code needs to be handled in two places. I will create a PR to add clarifying comments to this code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I created a PR here to add some clarifying comments:

#290

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for following up on this and adding those comments. It will be helpful for future us!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants