[TS migration] Migrate 'Localize' lib to TypeScript #29742
[TS migration] Migrate 'Localize' lib to TypeScript #29742arosiclair merged 18 commits intoExpensify:mainfrom
Conversation
There was a problem hiding this comment.
Could we create a type for LocaleListener object itself and use it?
// types.ts
type LocaleListener = {
connect: LocaleListenerConnect;
};
// index.native.ts
const localeListener: LocaleListener = {
connect: BaseLocaleListener.connect;
};
export default localeListener;In this way we ensure the default export structure is safely typed.
|
@getusha We would appreciate if you could work on the reviewer checklist this week as this PR is blocking other migration PRs, thanks! |
Reviewer Checklist
Screenshots/VideosiOS: Native |
|
We did not find an internal engineer to review this PR, trying to assign a random engineer to #24919 as well as to this PR... Please reach out for help on Slack if no one gets assigned! |
| } | ||
|
|
||
| return translateLocal(phrase, variables); | ||
| return translateLocal(phrase as TranslationPaths, variables as never); |
There was a problem hiding this comment.
Why are we casting variables as never here?
There was a problem hiding this comment.
@arosiclair We're casting variables as never to bypass TypeScript's strict type checking. translateIfPhraseKey is being used dynamically, e.g., with errors that comes from the backend which we don't have static types for.
It allows translateIfPhraseKey to call the strictly typed translateLocal function without type errors. Yep, it does reduce type safety for variables, but looking at the implementation of translation and translationLocal it shouldn't be an issue.
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚀 Deployed to staging by https://github.com/arosiclair in version: 1.3.96-0 🚀
|
|
Looks like this PR caused this regression and the stacktrace So we just need to add a lineNumber to the accessibilityLabel |
|
🚀 Deployed to production by https://github.com/puneetlath in version: 1.3.96-15 🚀
|
|
🚀 Deployed to production by https://github.com/puneetlath in version: 1.3.97-7 🚀
|
| function translate(desiredLanguage = CONST.LOCALES.DEFAULT, phraseKey, phraseParameters = {}) { | ||
| const languageAbbreviation = desiredLanguage.substring(0, 2); | ||
| let translatedPhrase; | ||
|
|
||
| function translate<TKey extends TranslationPaths>(desiredLanguage: 'en' | 'es' | 'es-ES' | 'es_ES', phraseKey: TKey, ...phraseParameters: PhraseParameters<Phrase<TKey>>): string { |
There was a problem hiding this comment.
The translate function used to take 3 arguments and the third one being an object containing the parameters to be used by the translation phrase. Now the third argument is using the rest syntax and it's an array. Was that change intended?
Also previously the 3rd argument had a default value and now it does not which caused #34668 and #30949
There was a problem hiding this comment.
Yes it was an intended change, now this function can take 2 arguments for translations like:
translate('en', 'common.error.invalidAmount');
// function translate<"common.error.invalidAmount">(desiredLanguage: 'en' | 'es' | 'es-ES' | 'es_ES', phraseKey: "common.error.invalidAmount", ...phraseParameters: never[]): string3 arguments if translation takes additional argument:
translate('en', 'common.error.characterLimit', {limit: 10});
// function translate<"common.error.characterLimit">(desiredLanguage: 'en' | 'es' | 'es-ES' | 'es_ES', phraseKey: "common.error.characterLimit", phraseParameters_0: CharacterLimitParams): string4 and more arguments if translation takes more than one argument:
//src/languages/en.ts
test: (arg1: string, arg2: string) => `This is a test ${arg1} ${arg2}`,
translate('en', 'common.error.test', "arg1", "arg2");
// function translate<"common.error.test">(desiredLanguage: 'en' | 'es' | 'es-ES' | 'es_ES', phraseKey: "common.error.test", arg1: string, arg2: string): stringAlso previously the 3rd argument had a default value and now it does not which caused #34668 and #30949
Translation functions that takes arguments should always receive them, so I think this just uncovered these bugs 😅
Otherwise we'd add the missing parameters for translation that takes parameters.
I think we should always add missing parameters to translate function
There was a problem hiding this comment.
Do you know if we can have typescript help us with that? i.e. yield an error if we are missing to pass parameters to a translation function
There was a problem hiding this comment.
That's already implemented @s77rt, but only in .ts/.tsx files





Details
Migrate 'Localize' lib file to TypeScript
Fixed Issues
$ #24919
Tests
Need to test if everything is translated properly:
Offline tests
QA Steps
Need to test if everything is translated properly:
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)myBool && <MyComponent />.src/languages/*files and using the translation methodWaiting for Copylabel for a copy review on the original GH to get the correct copy.STYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)/** comment above it */thisproperly so there are no scoping issues (i.e. foronClick={this.submit}the methodthis.submitshould be bound tothisin the constructor)thisare necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);ifthis.submitis never passed to a component event handler likeonClick)StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG))Avataris modified, I verified thatAvataris working as expected in all cases)ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Web
web.mp4
Mobile Web - Chrome
Mobile Web - Safari
Desktop
iOS
ios.mov
Android
android.mp4