-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Update provider so the useI18n()
hook can use the global translation functions from @wordpress/i18n
#47352
Conversation
useI18n()
hook use the global translation functions from @wordpress/i18n
Caution: This PR affects files in the Editing Toolkit Plugin on WordPress.com D52644-code has been created so you can easily test it on your sandbox. See this FieldGuide page about developing the Editing Toolkit Plugin for more info: PCYsg-ly5-p2 |
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser: App Entrypoints (~42 bytes removed 📉 [gzipped])
Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used. Legend What is parsed and gzip size?Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory. Generated by performance advisor bot at iscalypsofastyet.com. |
@sirreal I think you were involved at the start of |
This looks like an OK solution that solves a product issue. But I wish we could refactor it to something that doesn't need to introduce a new provider. The existing one should be able to work even with the default instance of import { defaultI18n } from '@wordpress/i18n';
<I18nProvider localeData={ defaultI18n.getLocaleData() }> To make that happen, the
I'm not sure it's guaranteed that the library always knows the locale 🙂 All it needs to work is a {
"": {
"plural_forms": "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;",
"language": "cs_CZ",
"localeSlug":"cs"
}
} But I don't know if it's 100% guaranteed in practice that this special key will always be there. Without it, the library will incorrectly format plurals, because it doesn't have information about the target language's grammar and will use English rules as default. But other than that, it will work. Once the i18n.getLocaleData()[ '' ].localeSlug or, preferrably, there can be convenience getters for the All these would be a valuable enhancements to
|
@jsnajdr, I like the suggested approach, but want to add that |
This would be great! My original idea was something like
Just to clarify @jsnajdr, did you mean the
Thanks, good to know. We're probably relying on the locale slug too much. We use it to add
So it sounds like it's ok for our a8c specific functions (like |
Yes, I always meant |
db7d3ed
to
f24a319
Compare
packages/react-i18n/src/index.tsx
Outdated
_nx, | ||
_x, | ||
isRTL, | ||
i18nLocale: localeSlug, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add sprintf
here too? - it doesn't make sense to leave it out
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The I18n
interface doesn’t include sprintf
because it’s a dumb formatting utility, it doesn’t need access to any locale data. I suppose it might be convenient, but it doesn’t feel right to me to provide something with a hook that can be gotten from an import
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The @wordpress/i18n
api does include sprintf though, and thats what we're trying to mirror / expose / augment here as a hook, that's why see it as worth including, adding it all into the hook makes usage more consistent and easier to explain / demonstrate.
it doesn’t feel right to me to provide something with a hook that can be gotten from an import.
Agree in general, this situation for me is more about providing a consistent experience when using l10n functions. I would even argue it isn't worth exposing by wordpress/i18n at all - its just a simple wrapper around another library - but I suspect it was included for this consistency reason to ensure everyone had all the tools in a one stop shop sort of way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the record, don't mind too much either way, go with your gut
import { useI18n, sprintf } from '@automattic/react-i18n'
const { __, _x } = useI18n()
vs
import { useI18n } from '@automattic/react-i18n'
const { __, _x, sprintf } = useI18n()
9122f05
to
a2e1496
Compare
@lsl What do you think about these changes? I've removed |
packages/react-i18n/src/index.tsx
Outdated
* | ||
* @returns The context value with bound translation functions | ||
*/ | ||
function makeContextValue( localeData?: LocaleData ): I18nReact { | ||
function makeContextValue( localeData?: LocaleData, localeSlug?: string ): I18nReact { | ||
const i18nLocale = localeSlug ?? localeData?.[ '' ]?.localeSlug ?? 'en'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neither accessing localeSlug or the en
fallback work here, localeSlug is non standard and en fallback can't be assumed otherwise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(the en fallback above is fine, I just don't think it makes sense in this package)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed. The useI18n()
hook guarantees that it'll always return a value for i18nLocale
. However maybe that's not realistic. Perhaps we should change the return type of useI18n()
to this:
export interface I18nReact {
__: I18n[ '__' ];
_n: I18n[ '_n' ];
_nx: I18n[ '_nx' ];
_x: I18n[ '_x' ];
isRTL: I18n[ 'isRTL' ];
i18nLocale?: string;
}
Note the ? on the i18nLocale
prop. That way we'd fall back to undefined
instead of 'en'
.
Another option I've been thinking about is completely removing the i18nLocale
prop from useI18n()
. react-i18n
is supposed to be something we could push upstream, and since having the locale slug available in the locale data is non-standard, it probably won't survive the review process.
We've been explicitly referring to the locale slug a lot in gutenboarding, but that's a special case because the user is logged out, and they can provide the locale in the url. That's not usually how things work. Perhaps the locale slug can be provided to a new thing, like a <LocaleProvider>
, that's part of an a8c-specific package. i18n-utils
I guess. That way we can depend on it for our a8c helper functions like localizeUrl()
and we know we can provide it at app boot time because of the idiosyncrasies of our WordPress environment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think an optional locale slug value works - users of the prop will have to deal with that case everywhere its used, the default value needs to be decided by the consumer of react-i18n. In a lot of cases that will be english but its an assumption we can't force on everyone.
This another other option sounds really good - feels much cleaner and I like stepping away from making decisions about what a locale is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#47446 - I like this solution to break apart the locale slug from the locale data, but we need some changes to break away from calypso-i18n
#47446 (review)
cc @Automattic/i18n might want to be aware of this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should go with #47446. It probably needs to merge first so this one can be updated without breaking the build.
useI18n()
hook use the global translation functions from @wordpress/i18n
useI18n()
hook can use the global translation functions from @wordpress/i18n
As of #47446 the |
a2e1496
to
0969d39
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per #47352 (comment)
Requesting changes to block this PR until #47446 is merged.
5899257
to
de7947d
Compare
We may be able to live with i18nLocale
always being 'en'
when using the default translation functions, so that we aren't blocked waiting on a decision about whether @wordpress/i18n
will expose the raw locale data.
de7947d
to
e4947af
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good 👍 Doing something about the i18nLocale
being always en
would be desirable, but it's up to you to decide what to do and when. Thanks for improving the react-i18n
library!
packages/react-i18n/src/index.tsx
Outdated
const i18nLocale = localeData?.[ '' ]?.localeSlug ?? 'en'; | ||
|
||
if ( ! localeData ) { | ||
return { __, _n, _nx, _x, isRTL, i18nLocale }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed on a P2, the i18nLocale
's default value en
will be wrong if the upstream global i18n
instance is actually localized.
A good alternative would be to not pass the i18nLocale
prop in this case at all, or completely remove it from the context value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to remove i18nLocale
since currently there's currently nothing depending on it. Not ruling out that it won't eventually make it's way back in some form though.
<LaunchContext.Provider value={ { siteId: window._currentSiteId } }> | ||
<LaunchModal onClose={ closeSidebar } /> | ||
</LaunchContext.Provider> | ||
<I18nProvider> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't even need to mount the provider here: the default context value, derived from undefined
localeData
, will be used in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good thinking, I'd somehow missed this in the midst of all these changes. I actually like this behaviour 😎
There's no way to know the correct locale slug when `localeData` is left undefined, so just removing it since there's currently no uses of it. The current locale slug might come back to react-i18n in the future once there's a standard way to get access to the current locale slug.
e4947af
to
5e1c63d
Compare
Changes proposed in this Pull Request
@automattic/react-i18n
works by providing locale data somewhere near the root of your component tree (using<I18nProvider>
), and using theuseI18n()
hook in your components to get access to translation functions that use the provided locale data.However we don't always have access to the locale data. In the ETK, core initialises
@wordpress/i18n
with the locale data and we don't get access to it. That means__
from@wordpress/i18n
works, but__
fromuseI18n()
does not.This PR
adds achanges the<GlobalI18nProvider>
provider that is useful<I18nProvider>
provider so it is useful in situations where we don't have access to the raw locale data. When this provider is used,useI18n()
will provide access to the global translation functions from@wordpress/i18n
.You still need to provide the current locale to(doing #47446 instead)<GlobalI18nProvider>
somehow. You may also need to provide the current locale to<I18nProvider>
somehow. That's because@wordpress/i18n
doesn't give access to what the current locale is for some reason andreact-i18n
does.In this PR I've tested it out by translating a few strings in the launch flow
and I've gotten the current locale by having the server render it to a global. I previously thought I'd be able to grab the locale slug fromdocument.documentElement.lang
but unfortunately it doesn't always match the locale slug (e.g. sometimes the locale isfr
and the<html lang="...">
attribute isfr_CA
)Testing instructions
en