-
Notifications
You must be signed in to change notification settings - Fork 685
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
Venia Localization w/ i18n #669
Comments
As for me, I used react-i18next since i18n have nice documentation, scale and flexible |
Would like to see some direction on this as well. We've been backlogging the question internally, but the business is pushing for direction as we're wiring up more code without localization. |
Agreed with @brendanfalkowski . My question is whether store-view switching can also be implemented at this point? So not only the language preference, but also the rest of Magento store view configs? |
@vitalics @brendanfalkowski Thanks for the library suggestions. This issue has come up a lot recently, so I'm going to start researching the translation landscape again. Ultimately, I'd like to come up with a spike or story for our team (or a community member) to work on. Basic approachDepending on how the libraries out there work, we may not need any of them. The basics of translation should follow a familiar pattern:
// one way of doing things
const textMap = new Map()
.set("jp", <span>日本語</span>)
.set("en", <span>English</span>)
const Foo = props => {
const lang = useLanguageContext()
const text = textMap().get(lang)
return <button>{text}</button>
} Open questionsHere a few of the architectural choices we'll need to make, though: 1. Should we support elements or only strings? Elements would extremely powerful for rendering different things for different languages, but wouldn't be serializable to JSON. 2. If we support only strings, should we store them as JSON or JavaScript? Retrieving strings as JSON would allow us to pull translated values from the database, but if they're stored in the repository there's not much advantage to JSON. Meanwhile, storing them in the repository, as code, opens up a lot of new possibilities, including elements as values. 3. Since we'll have to load a language's values dynamically, should we store and load those values individually (on a per-component basis) or as a batch (on a per-language basis)? Loading items individually would minimize and distribute payloads, but it would make many parts of the site render asynchronously. Loading items as a batch would optimize rendering, but it would result in overserving, and centralizing translation could be complex. |
Just my two cents from our project: Just as an example "I accept the %terms% and confirm that I have read and understood the %cancellation% and the %privacy%." where you want to replace the placeholders with I'd not allow to use the translation for complete component replacement, I think this could be done by exposing a For the library it could make sense to store the translations on component basis. In our storefront, we don't do this, but it also is no library so it doesn't get used by other applications. Like this components would be really easy to pull in other applications, but it also would be very tricky to use existing translations like @fooman noted. |
Currently working on a solution for this, should have something to demo in the next week or two. Fetches translated phrases from Magento backend at build, generates translation json files and and uses i18next for the translation engine. |
@chris-brabender interesting - how does it serve the languages for runtime? |
Just want to add, that as the developer of the PWA I don't want to have to edit Magento translation files just to add some custom translations for example. If it would be like this I'd have to setup a development instance just to add translation strings, this would make no sense in my opinion! |
@niklas-wolf wouldn't you need a development instance to grab other data like products, categories, system configs, etc. etc.? 🤔 |
btw, may I give it a try? Which solution should we take here? https://github.com/i18next/react-i18next? |
Yes but this can be managed by backend devs. As a frontend dev it would be very annoying to have to touch the backend instance just for translations. I see why it’s handy to use Magento translations in some way, as there is much that already exists. But I think there should at least be an option to add translation strings on the frontend side. |
I think I see your point, @niklas-wolf. You want to be able to adjust, add new translations from the custom PWA theme, let's say. Whereas the main translations come from the backend (as an option). |
I agree with @niklaswolf. I think that the phrases that are in the components should be translated by PWA Studio and those who came from Magento should be translated by the modules with the store language, with that Magento will translate it on the APIs using the default "__" method. |
@chris-brabender, that sounds promising! Would this be something you could show on fridays community sync ? |
@Jordaneisenburger, @LucasCalazans what if the theme (pwa) wants to adjust the translation that comes from the Magento? How this can be covered? |
So I haven't seen @chris-brabender 's code but I assume there would be some sort of deep merge |
@chris-brabender any news about your implementation? I'm available to contribute to this issue. Also, about the libraries, what do you guys think is best to use? https://github.com/i18next/react-i18next In my opinion, i18next/react-i18next may be better because it supports translations with tags (https://react.i18next.com/guides/the-drawbacks-of-other-i18n-solutions#can-you-translate-combined-jsx-nodes-in-one-sentence) |
@vasilii-b Maybe it could be done by a response code. Normally we have a code inside the response body that says what is the message. |
Hey all here is a preview of where I am at right now with the implementation. General concept:
GraphQL
Localization hook
Router
Video Walkthrough Notes:
|
We have started our implementation of Use
|
I'd like to add some considerations: Pro using IDs:in the past developers where not aware that the initial en_US translation doubled up as the lookup for translations. This lead to the following scenario: initial string: translations happen Now someone comes along and doesn't like "This is an en_US string". The correct approach to changing it would be "This is an en_US string", "This is an improved en_US string" what did happen was "This is an improved en_US string", "This is an improved en_US string" breaking all existing translations. Con using IDs:Existing community tooling and existing translations would be harder to re-use. Ideally PWA Studio would re-use as much of the already existing translations provided by the Magento community as to not require another huge undertaking for the community. As a mitigation for this Con I am hoping some extra tooling can be created that translates "This is an en_US string", "This is an en_US string" to "component.translatedString", "This is an en_US string" - it won't be context aware but may be good enough for a first iteration. |
My two cents. Lessons from managing ~5000 translations across 3 languages for my most complicated project.
My gut says an ID-based system would be more resilient for us because of (4) and (8). I'm not sure if making it component-based (not global) would be an improvement or not. |
Not sure this is a con - we may want to start with global strings and only specify context when necessary.
@fooman I understand the concern here but as far as I know we haven't been using existing translations/strings for the UI so any matches would be coincidence. If we use the That said, it may be trivial to implement a tool that generates some initial translation files for PWA Studio based purely on matches of string values. The following assumes we use the
|
For developers whose primary language is English the It is interesting to hear that translations rarely need to be context-aware. I definitely considered this a con. In that case, I like the "global.greeting": "Welcome to Foo Store!"
"signIn.greeting": "Welcome to Foo Store, {username}!" idea, but unfortunately I'd expect the subtle context differences needed in translation to be only uncovered at the time of translation. In other words, after a developer would have needed to decide whether to create a separate key or not. As a developer, the |
From internal discussions / comments along with @fooman and @brendanfalkowski comments we're going to move ahead with using ID's based on the component name then the description of the string. If anyone has a big reasoning as to why we shouldn't do this we can alter path with good enough reasoning. |
I guess this goes at the heart of my request. Is there any way to make this less of a coincidence? So after the process you outlined to find if we can translate via a coincidental legacy string can we include another pass to see if we really must introduce a new string. Practical example here If there really is a must for Venia to use "You have placed no orders." I would suggest adding "You don't have any orders yet." in venia-ui and supply the "You don't have any orders yet." translation in venia-concept. With the venia-ui strings being used to perform the legacy lookups/matching. |
Much of the pwa copy is just UI direction or our own best guess. I don't see why we can't attempt to reuse existing copy. However the system were opting for is context aware whereas existing copy may not be, at least not to PWA Studio. This could present a challenge to reuse. Perhaps we should open an issue to suss out some tooling and explore our options. Just need some existing translation files and time :) |
Existing translations are here https://crowdin.com/project/magento-2 or better yet the final csv output files can be found here https://github.com/magento-l10n?utf8=%E2%9C%93&q=%5Elanguage- https://github.com/magento-l10n/language-nl_NL/blob/master/nl_NL.csv for example is showing as 99% translated. |
@davemacaulay Just a suggestion, because I'm going to type this 10,000 times by next year. The component/prop naming is a handful.
would be better as:
Would also accept |
@brendanfalkowski we opted to not abstract or alias the functions so the You can certainly create a wrapping component or import with an alias to reduce your keystrokes, but we believe holding true to the original frameworks API will assist developers in their day to day and make it much easier to discover solutions to problems using our favorite developer resource, Google! |
@davemacaulay I understood that reference: gripes go up the chain of command. https://www.youtube.com/watch?v=dKbdE5LOGNQ I should be complaining to |
I am not entirely sold on the id's implementation to be honest. If, for example, I want to update all Apply buttons to french, I need to do it 100 times in my translation file for each component? Eg:
One one side it means I can target things specifically but creates a lot of overhead doesn't it? Also means we can't re-use a lot of the translation files we already have without a lot of work to update them to the id based identifier. |
@chris-brabender I spent a little time on this script that can scan over whatever files you need to generate new translation json files for you assuming there are hits in the legacy files. It also can show you what keys/strings did not have matches. I was hoping to take a lot of the manual work out of the process, and as @fooman mentioned we could go further with it and do some sort of fuzzy search for the missed strings to see if there is existing legacy copy that we can use in place of the string in pwa studio. |
@chris-brabender I think for known common strings we just wouldn't namespace them. So things like "Apply", "Default", "Save" could have generic global ID's like |
@chris-brabender @davemacaulay I'd suggest taking this one step further:
Make everything global by default, and only introduce namespaces if you actually find conflicts in usage. That'll help with maximum re-use and won't step on extensions who choose to namespace. I'd also personally hate seeing cross-component imports like |
Most design is completed and remaining features will be delivered very soon. Closing in favor of those PRs and internal issues. |
Has someone taken on replacing strings with in all jsx files as well as producing a matching en_EN.json? I can take on that, if it’s not already done. |
That work should have been done, but it is possible we missed some. Would certainly welcome any pull requests for strings we missed! |
This issue is for the following packages:
venia-concept
pwa-buildpack
peregrine
pwa-devdocs
upward-js
upward-spec
This issue is a:
Environment
node -v
)npm -v
)Description
As a store owner and implementer, I want to be able to translation text/strings within the storefront to multiple languages (i18n). Currently, all text such as labels, etc. are hard coded in the React components.
This would also include a language switcher but that could be an enhancement after we get translations working.
Expected result:
Venia comes with multiple languages supported out of box (English, Spanish, Japanese, etc.). An implementer will have a way of translation all strings to different languages.
Possible solutions:
There are a variety of different solutions. https://github.com/yahoo/react-intl is one
The text was updated successfully, but these errors were encountered: