-
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
Extract Gutenboarding language picker into @automattic/language-picker #46020
Conversation
Using this inside a modal from |
@simison I love that idea! When we eventually implement the resulting component into the Calypso modal we can try to swap the |
7b34ee8
to
301004e
Compare
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser: App Entrypoints (~3 bytes added 📈 [gzipped])
Common code that is always downloaded and parsed every time the app is loaded, no matter which route is used. Sections (~80 bytes added 📈 [gzipped])
Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to. Async-loaded Components (~115 bytes added 📈 [gzipped])
React components that are loaded lazily, when a certain part of UI is displayed for the first time. 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. |
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.
This looks good and I tested it with /new?flags=gutenboarding/language-picker
turned on and it works well.
I just couldn't get the storybook working, can you please re-test that?
Also, did you consider adding this to packages/components
rather than its own package? I think either way would be ok so no pressure to change it.
package.json
Outdated
@@ -154,6 +154,7 @@ | |||
"whybundled:server": "whybundled client/stats-server.json", | |||
"composite-checkout-demo": "webpack-dev-server --config ./packages/composite-checkout/webpack.config.demo.js --mode development", | |||
"components:storybook:start": "start-storybook -c packages/components/.storybook", | |||
"language-picker:storybook:start": "start-storybook -c packages/language-picker/.storybook", |
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.
when I run this, I get an error on the storybook page in the browser "Exports is read only"
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.
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 not sure why this suddenly isn't working 🤔 Reading the error below:
./packages/language-picker/node_modules/@automattic/react-i18n/node_modules/@wordpress/is-shallow-equal/lib/objects.js/<@http://localhost:50609/vendors~main.74bd29d19c2e02c9b421.bundle.js:213500:1
It appears to be an issue within a dependency. The storybook worked before so I'm wondering if at some point I changed something while working on it that caused it to break (like updating the dependencies 🤔)
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.
FWIW it works well for me now.
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.
This is exciting, thank you for the great work @saramarcondes!
I've left some comments, but this is a really great start! Let me know what you think.
package.json
Outdated
@@ -154,6 +154,7 @@ | |||
"whybundled:server": "whybundled client/stats-server.json", | |||
"composite-checkout-demo": "webpack-dev-server --config ./packages/composite-checkout/webpack.config.demo.js --mode development", | |||
"components:storybook:start": "start-storybook -c packages/components/.storybook", | |||
"language-picker:storybook:start": "start-storybook -c packages/language-picker/.storybook", |
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.
@@ -0,0 +1,2 @@ | |||
export * from './language-picker'; | |||
export { default } from './language-picker'; |
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.
Not sure what we're trying to do here, could you please elaborate?
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.
export * from '...'
does not export the default, so if you have both named and default exports you need two separate export statements (unless there's another way that I'm not aware of). In this case we need to export the default (the component) and the named exports (the Language
and LanguageGroup
types)
|
||
return ( | ||
<> | ||
<div className="language-picker__regions-label">{ __( 'regions' ) }</div> |
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 see we're using @wordpress/i18n
here. This relies on the locale data to be already set. AFAIK, CalypsoI18nProvider
currently does that for both Calypso-style localizations and Gutenberg-style localizations. But using that in a package assumes that this is somehow handled already in the consumer of the package. What are your thoughts about this?
also cc @automattic/i18n about it
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.
If there's no provider, @automattic/react-i18n
will use @worpdress/i18n
instance with empty locale data, and therefore string won't get translated.
A good proposal for @automattic/react-i18n
might be to fall back to the default @wordpress/i18n
instance instead of creating an empty one, but that's a different subject.
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, I've also explained more about that problem in #46020 (comment)
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've given this a bit more thought, and I think going with this makes sense. After all, it's not a component package's responsibility to take care of managing locale data itself. It should be the responsibility of the component consumer, or application.
So, @saramarcondes, I think going with @wordpress/i18n
makes sense here, and is an acceptable trade-off. It aligns with our long-term goal, which is to use @wordpress
packages for everything.
I have a small suggestion here. It might end up to be confusing for the user to see that we're using both @wordpress/i18n
and @automattic/react-i18n
, so it might be a better idea to always go with @automattic/react-i18n
, and use either the useI18n
hook or the withI18n
high-order component. Both of them internally use @wordpress/i18n
, so the idea here is to be consistent, while still keeping the opportunity to add additional package features and improvements to @automattic/react-i18n
and benefit from them instantly. Let me know what you think.
I'd recommend one final thing: documenting in the package README that this package makes use of @wordpress/i18n
and relies on the fact that the consumer of the package (the app in this case) is already providing the locale data. For Calypso, this is happening in the <CalypsoI18nProvider />
, which does invoke setLocaleData()
with the locale data coming from i18n-calypso
.
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.
Thanks again!
I'll update the README as you suggested.
One thing though, the package no longer uses react-i18n
, only wordpress/i18n
. Do you feel that it should be using react-i18n
? (Admittedly I only changed it because using react-i18n
was breaking the storybook in a mysterious 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.
I wouldn't say it's a hard requirement as to which one to use. react-i18n
is handy, because it adds some syntactic features on top of @wordpress/i18n
, but since it is generally a wrapper around @wordpress/i18n
, it doesn't really matter. It basically boils down to:
- Use
react-i18n
if you need to use the HoC and/or the React hook. - Use
@wordpress/i18n
if you don't need to use any of the above.
Theoretically, it can turn out to be a blocker if react-i18n
uses an older or newer version of @wordpress/i18n
, but this shouldn't be a difficult problem to solve, as we have full control over reach-i18n
, especially if it happens in Calypso.
|
||
export type LanguageGroup = { | ||
id: string; | ||
name: ( translate: I18n[ '__' ] ) => string; |
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.
Not sure why we're renaming __()
to __translate()
here. Perhaps we should be explicit that we're using @wordpress/i18n
?
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.
This isn't renaming, it's the type annotation. i18n-calypso ultimately uses @wordpress/i18n
does it not? translate
is basically the same as the I18n
function __
, right?
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.
Forgive me if I've been unclear in my comment, but this is indeed renaming, even if it happens under the hood.
i18n-calypso
actually does not use @wordpress/i18n
. It is a custom library that was built before @wordpress/i18n
and uses a different mechanism for handling localization and translations. This is separate from the fact that the CalypsoI18nProvider
provides locale data for both @wordpress/i18n
and i18n-calypso
.
So actually, __()
is the @wordpress/i18n
, but translate()
is the i18n-calypso
function. Both are localization functions, and for simple translations they work the same way, but they still have a lot of functional differences. For example translate()
supports some additional features (for example arguments, components, context), while for @wordpress/i18n
you need to use different functions sprintf()
or _x()
for example.
And by expecting __()
but naming the argument translate
, we're essentially confusing the package user as to what kind of argument to provide and how it's being used. It's also possible to introduce bugs because of that behavior.
Finally, I believe that the actual translation mechanism shouldn't be handled (or enforced) by the package. I've talked about this a bit more in https://github.com/Automattic/wp-calypso/pull/46020/files#r504487702.
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.
Oh gosh, I misremembered. The original language picker uses @automattic/react-i18n
which does use @wordpress/i18n
, which was why I chose that type.
I understand the issue now is that we have two separate functions, translate
and __
. The solution in your other comment makes perfect sense to me. Thank you for your patience!
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 agree the name is a bit misleading to use translate
or even __
given the different contexts i18n-calypso
, @wordpress/i18n
and @automattic/react-i18n
. It may be best to name it something generic like translationFunction
. What we're describing is the shape of the name
function in the LanguageGroup
type, but folks will be free to name it whatever they want:
const lg: LanguageGroup = {
// The name of the translation function passed to my name function
// V
name( translateMyName ) {
return translateMyName("name");
}
};
Regarding the type, it's probably more appropriate to use I18nReact["__"]
from @automattic/react-i18n
as the type of the function because that's ultimately where the function will come from. It's passing the @wordpress/i18n
__
type through so it's not too important. @wordpress/i18n
__
is unfortunately generic right now (Function
type) but something that can be improved Gutenberg-side.
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.
@wordpress/i18n
__
is unfortunately generic right now (Function
type) but something that can be improved Gutenberg-side.
PR to improve function types: WordPress/gutenberg#26171
|
||
export type LanguageGroup = { | ||
id: string; | ||
name: ( translate: I18n[ '__' ] ) => string; |
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.
It feels a bit off to pass translate
as an argument here. Did we mean to use it directly in the code? A function that returns a string should be enough IMHO.
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 language groups are defined in a static file, not inside any specific context. I'm not sure how we could have translated names without passing translate to the static file unless we changed the way language groups are defined (as in, defining them in a specific runtime context rather than just a generic module). What are your thoughts for the alternatives to make this work with translated names still?
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'd expect that we would just use a function that returns a string. See https://github.com/Automattic/wp-calypso/blob/try/extract-language-picker/client/lib/plans/plans-list.js#L25 for example.
By going with this approach, we:
- Ensure that localization functions will be invoked as late as possible, which is necessary to be sure we've loaded all the locale data already.
- Avoid the necessity to pass a specific localization function as an argument.
- Stay flexible and not enforce a specific i18n framework. By expecting just a function that returns a string, we let the package consumer decide what i18n tools to use, vs forcing them to use a particular one.
Let me know if that makes sense.
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.
Yes, thank you for the explanation and example!
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.
@tyxla Does this also apply to localization that happens within the component itself (as in the case of the Regions label?) Would we just expect the consumer to dependency inject an i18n provider that had the signature string => string
? Or is it safe to import __
directly from @wordpress/i18n
as long as it is invoked as late as possible, as you said (like during rendering)?
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.
is it safe to import __ directly from @wordpress/i18n as long as it is invoked as late as possible, as you said (like during rendering)?
I'd say it's safe to do that. That's why we wrap them in functions, so invoking them late is a good warranty that it'll be done after the locale data has already loaded.
Note: I'm not saying it's a perfect solution. We've been limited in Calypso by that for a while now, too, and we're likely to stay with that limitation in the future.
That being said, I think it's an acceptable trade-off.
@roo2 The reason I didn't put it into |
}, | ||
]; | ||
|
||
export const _default = () => { |
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.
How is this _default
export expected to be used?
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.
This creates a "Default" example in Storybook. This is the same pattern followed by Gutenberg's usage of Storybook:
], | ||
"types": "dist/types", | ||
"dependencies": { | ||
"@automattic/react-i18n": "file:../react-i18n", |
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.
We should import using the version
"@automattic/react-i18n": "file:../react-i18n", | |
"@automattic/react-i18n": "^1.0.0-alpha.0", |
onSelectLanguage: ( language: Language ) => void; | ||
languages: Language[]; | ||
languageGroups: LanguageGroup[]; | ||
defaultLananguageGroupId: string; |
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.
There's a typo here: defaultLananguageGroupId
-> defaultLanguageGroupId
.
defaultLananguageGroupId: string; | |
defaultLanguageGroupId: string; |
onSelectLanguage, | ||
languages, | ||
languageGroups, | ||
defaultLananguageGroupId, |
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.
defaultLananguageGroupId, | |
defaultLanguageGroupId, |
languageGroups, | ||
defaultLananguageGroupId, | ||
}: Props ) => { | ||
const [ filter, setFilter ] = useState( defaultLananguageGroupId ); |
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.
const [ filter, setFilter ] = useState( defaultLananguageGroupId ); | |
const [ filter, setFilter ] = useState( defaultLanguageGroupId ); |
</div> | ||
<LanguagePicker | ||
languageGroups={ LANGUAGE_GROUPS } | ||
defaultLananguageGroupId={ DEFAULT_LANGUAGE_GROUP } |
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.
defaultLananguageGroupId={ DEFAULT_LANGUAGE_GROUP } | |
defaultLanguageGroupId={ DEFAULT_LANGUAGE_GROUP } |
onSelectLanguage={ ( language ) => console.log( language ) } | ||
languageGroups={ LANGUAGE_GROUPS } | ||
languages={ LANGUAGES } | ||
defaultLananguageGroupId="popular" |
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.
defaultLananguageGroupId="popular" | |
defaultLanguageGroupId="popular" |
onSelectLanguage, | ||
languages, | ||
languageGroups, | ||
defaultLananguageGroupId, |
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.
Additionally, I wonder if we can't always just default to the first item in languageGroups
. That's not only one prop less, it also complies with the WordPress philosophy: decisions, not options.
|
||
return ( | ||
<> | ||
<div className="language-picker__regions-label">{ __( 'regions' ) }</div> |
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've given this a bit more thought, and I think going with this makes sense. After all, it's not a component package's responsibility to take care of managing locale data itself. It should be the responsibility of the component consumer, or application.
So, @saramarcondes, I think going with @wordpress/i18n
makes sense here, and is an acceptable trade-off. It aligns with our long-term goal, which is to use @wordpress
packages for everything.
I have a small suggestion here. It might end up to be confusing for the user to see that we're using both @wordpress/i18n
and @automattic/react-i18n
, so it might be a better idea to always go with @automattic/react-i18n
, and use either the useI18n
hook or the withI18n
high-order component. Both of them internally use @wordpress/i18n
, so the idea here is to be consistent, while still keeping the opportunity to add additional package features and improvements to @automattic/react-i18n
and benefit from them instantly. Let me know what you think.
I'd recommend one final thing: documenting in the package README that this package makes use of @wordpress/i18n
and relies on the fact that the consumer of the package (the app in this case) is already providing the locale data. For Calypso, this is happening in the <CalypsoI18nProvider />
, which does invoke setLocaleData()
with the locale data coming from i18n-calypso
.
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.
This is looking great overall!
There's one blocker here: the language groups no longer work, because they expect us to pass a translate function as an argument to the language group name function, but we no longer do that.
@import '~@wordpress/base-styles/mixins'; | ||
@import '~@wordpress/base-styles/variables'; | ||
|
||
.language-picker__language-group { |
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.
Same as #46424 - do you think it makes sense to have a common wrapping class for all styles in this package, to make sure all styles are properly encapsulated and have a smaller chance to bleed to outside elements?
width: 100%; | ||
} | ||
|
||
.language-picker__language-group > span { |
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.
Nit: I wonder if this span
can have its own className
that will always be there; so we could target it by class name and not by element name.
|
||
export type LanguageGroup = { | ||
id: string; | ||
name: () => string; |
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.
Unfortunately, we're going to hit into an issue with this now:
Because the existing LANGUAGE_GROUPS
constant expects that their name will get a translation function as an argument, and we're no longer passing it here, it's going to fail.
We should either:
- Address this in the constant definition, by using
__()
there directly, vs expecting a translation function. Can you think of any downside to this approach, @Automattic/i18n @yuliyan? - Create a wrapper constant that uses
LANGUAGE_GROUPS
but predefines thename
by passing__()
as an argument to the function.
I personally prefer the first approach - ideally, it shouldn't be too hard to replace the instances of languageGroup.name( translate )
to languageGroup.name(
__` ) - I expect those to be only in the language picker component anyway.
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.
That makes sense (I thought I had fixed this but I guess I got the Storybook example and the live constants confused 😖)
Something I'm still confused about is whether we need to include the text domain global variable as described by @alshakero in the recent P2 here: pbAok1-1Ao-p2
If we do need to include the __i18n_text_domain__
variable in the component (both here and in search) then do we need to include it in these constants as well?
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.
@tyxla After making this change actually there is a new but subtle bug. When selecting English from the langauge picker in Gutenboarding (accessed via /new?flags=gutenboarding/language-picker
) it does not change the region languages to English (whereas for other languages it does work and in production it indeed will change to English when English is selected).
To reproduce:
- Go to
/new?flags=gutenboarding/language-picker
on this branch - Click the language picker from the upper right hand corner
- Select a languag other than English. Reopen the language picker and note that the regions are now listed in the langauge you selected.
- Now select English. Reopen the language picker and note that the regions are still listed in the previous language you selected.
- Repeat this several times going between languages that are not English and note that the regions change every time to the newly selected language except for when you choose English.
In production selecting English will behave the same as the rest of the languages.
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.
Something I'm still confused about is whether we need to include the text domain global variable as described by alshakero in the recent P2 here: pbAok1-1Ao-p2
@Automattic/ganon are exploring these questions currently.
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.
@Automattic/ganon are exploring these questions currently.
Latest WIP from @p-jackson here #46557
a0a1d3c
to
fd48015
Compare
fd48015
to
c181730
Compare
@tyxla I've pushed an update to this branch that fixes the translation issues I outlined previously. It makes some rather big changes that I'm not super comfortable with. I'd love your input. I was not able to get it working the way we had it before. The way that we're doing things now will require us to change the Calypso implementation to use I also removed storybook from this package because In any case. I'm hoping that my changes regarding translations make sense. See if you can find a different way to address the bug if you'd like, or if you can find the root cause for English not getting activated for the component's |
I've taken a look at the approach and concluded there isn't an easy way around it right now. If we fall back to using So to work around it, we should pass a That being said, feel free to add some documentation in the code to make sure that what we're doing is clear to our future selves. I've dismissed my previous review, and from my perspective, this is good to go. Ideally, I'd like to get a ✅ from @Automattic/ganon before merging. Nice work and thanks for the hard work here 👏 |
Using the The |
I was talking about a different trade-off here (passing |
I don't have anything to add. Maybe @andrewserong @p-jackson or @roo2 have. That said, we'll be testing integration as part of the i18n Gutenboarding effort, so we'll report anything we see then. Thanks to everyone for their work on 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.
Tested and worked as expected. LGTM!
The __i18n_text_domain__
constant is only really needed if we intend to include @automattic/language-picker
in a WordPress plugin, e.g. the Editing Toolkit. Otherwise leaving it out is fine and it'll default to using the default text domain. This is what Calypso and Gutenboarding use, so it'll work fine.
You've probably seen it, but __i18n_text_domain__
is defined here for Calypso and here for the Editing Toolkit. So this package is usable in either of those contexts now. If you try and install this package in a context that doesn't define __i18n_text_domain__
then this package will crash. But that's fine for now right?
I left a couple of nit picks but they're optional really, I think this is good to go as is, we can iterate on i18n stuff as we go IMO.
languageGroups: LanguageGroup[]; | ||
}; | ||
|
||
const LanguagePicker = ( { onSelectLanguage, languages, languageGroups }: Props ) => { |
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.
Optional: you can fix the eslint warning about defining module boundaries by using the React.FC
type.
const LanguagePicker = ( { onSelectLanguage, languages, languageGroups }: Props ) => { | |
const LanguagePicker: React.FC< Props > = ( { onSelectLanguage, languages, languageGroups } ) => { |
import { LanguageGroup } from './language-picker'; | ||
import { I18nReact } from '@automattic/react-i18n'; |
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.
Minor nit pick: using import type
makes it easier for tooling to optimise the case where a package is only geing imported for a type.
import { LanguageGroup } from './language-picker'; | |
import { I18nReact } from '@automattic/react-i18n'; | |
import type { LanguageGroup } from './language-picker'; | |
import type { I18nReact } from '@automattic/react-i18n'; |
Not a big deal, it just stood out to me because I thought we had an eslint warning about this. Eslint appears to be working in this new package though so I must be mistaken.
Indeed, high five! Great team effort, folks 🙌 |
Thanks for the feedback @p-jackson. I'll have another follow-up PR to implement this language picker into Calypso and will address the issues you've pointed out there, if that's okay with you! Otherwise I can open a fast-follow PR to specifically address these if you think they should be taken care of sooner. |
@saramarcondes I don't think there's a need, they're the sort of tidy ups that can go whenever |
Changes proposed in this Pull Request
@wordpress/components
into@automattic/language-picker
allowing us to use it both in Gutenboarding and in Calypso.Testing instructions
/new/language-modal
and confirm that it matches visually and behaviorally with production.