-
Notifications
You must be signed in to change notification settings - Fork 4
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
Add Lingui support, take 2. #1376
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
ca04f99
Add lingui support, take 2.
toolness 6cbcc07
Fix lint_typescript GH action.
toolness 6c56d09
Internationalize an attribute.
toolness 292282b
Add ENABLE_WIP_LOCALES setting.
toolness bf232cb
Add some localization tests.
toolness 3cc0837
Add more tests.
toolness 236cd61
Hopefully fix broken tests.
toolness 6d06e75
Get rid of the default locale.
toolness dbf2259
Add comment about #1382.
toolness a99b9fe
Add docs, fallback component.
toolness c0c12b9
Add docs to README.
toolness 0bdf670
Merge branch 'master' into lingui-take-2
toolness File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import React, { useMemo } from "react"; | ||
import { Catalog } from "@lingui/core"; | ||
import loadable, { LoadableLibrary } from "@loadable/component"; | ||
import { I18nProvider } from "@lingui/react"; | ||
import i18n from "./i18n"; | ||
import { setupI18n as linguiSetupI18n } from "@lingui/core"; | ||
|
||
/** | ||
* We use code splitting to make sure that we only load the message | ||
* catalog needed for our currently selected locale. | ||
* | ||
* This defines the type of component whose children prop is a | ||
* callable that receives a Lingui message catalog as its only | ||
* argument. | ||
*/ | ||
export type LoadableCatalog = LoadableLibrary<Catalog>; | ||
|
||
const EnCatalog: LoadableCatalog = loadable.lib( | ||
() => import("../../locales/en/messages") as any | ||
); | ||
|
||
const EsCatalog: LoadableCatalog = loadable.lib( | ||
() => import("../../locales/es/messages") as any | ||
); | ||
|
||
/** | ||
* Returns a component that loads the Lingui message catalog for | ||
* the given string. | ||
*/ | ||
function getLinguiCatalogForLanguage(locale: string): LoadableCatalog { | ||
switch (locale) { | ||
case "en": | ||
return EnCatalog; | ||
case "es": | ||
return EsCatalog; | ||
} | ||
throw new Error(`Unsupported locale "${locale}"`); | ||
} | ||
|
||
const SetupI18n: React.FC< | ||
LinguiI18nProps & { | ||
locale: string; | ||
catalog: Catalog; | ||
} | ||
> = (props) => { | ||
const { locale, catalog } = props; | ||
|
||
// This useMemo() call might be overkill. -AV | ||
const ourLinguiI18n = useMemo(() => { | ||
li18n.load({ | ||
[locale]: catalog, | ||
}); | ||
li18n.activate(locale); | ||
return li18n; | ||
}, [locale, catalog]); | ||
|
||
return ( | ||
<I18nProvider language={locale} i18n={ourLinguiI18n}> | ||
{props.children} | ||
</I18nProvider> | ||
); | ||
}; | ||
|
||
export type LinguiI18nProps = { | ||
/** Children to render once localization data is loaded. */ | ||
children: React.ReactNode; | ||
}; | ||
|
||
/** | ||
* Loads the Lingui message catalog for the currently selected | ||
* locale, as dictated by our global i18n module. Children | ||
* will then be rendered with the catalog loaded and ready | ||
* to translate. | ||
* | ||
* While a loading message will appear while the catalog is being loaded, | ||
* because we do server-side rendering and pre-load JS bundles in the | ||
* server-rendered HTML output, the user won't see the message most | ||
* (possibly all) of the time. | ||
* | ||
* Note that this component is currently a singleton; more than one | ||
* instance of it should never exist in a component tree at once. | ||
*/ | ||
export const LinguiI18n: React.FC<LinguiI18nProps> = (props) => { | ||
const locale = i18n.locale; | ||
|
||
const Catalog = getLinguiCatalogForLanguage(locale); | ||
|
||
return ( | ||
<Catalog fallback={<p>Loading locale data...</p>}> | ||
{(catalog) => <SetupI18n {...props} locale={locale} catalog={catalog} />} | ||
</Catalog> | ||
); | ||
}; | ||
|
||
/** | ||
* A global instance of Lingui's I18n object, which can be used to perform | ||
* localization outside of React JSX. Note that this object is populated | ||
* by the <LinguiI18n> component, however, so it should only really be | ||
* used by components that exist below it in the hierarchy. | ||
*/ | ||
export const li18n = linguiSetupI18n(); | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import React from "react"; | ||
import i18n from "../i18n"; | ||
import ReactTestingLibraryPal from "./rtl-pal"; | ||
import { LinguiI18n, li18n } from "../i18n-lingui"; | ||
import { Trans, t } from "@lingui/macro"; | ||
import { wait } from "@testing-library/react"; | ||
|
||
describe("<LinguiI18n>", () => { | ||
afterEach(ReactTestingLibraryPal.cleanup); | ||
|
||
const helloWorldJSX = ( | ||
<LinguiI18n> | ||
<Trans>Hello world</Trans> | ||
</LinguiI18n> | ||
); | ||
|
||
it("Works in English", async () => { | ||
i18n.initialize("en"); | ||
const pal = new ReactTestingLibraryPal(helloWorldJSX); | ||
await wait(() => pal.rr.getByText("Hello world")); | ||
expect(li18n.language).toBe("en"); | ||
expect(li18n._(t`Hello world`)).toBe("Hello world"); | ||
}); | ||
|
||
it("works in Spanish", async () => { | ||
i18n.initialize("es"); | ||
const pal = new ReactTestingLibraryPal(helloWorldJSX); | ||
await wait(() => pal.rr.getByText("Hola mundo")); | ||
expect(li18n.language).toBe("es"); | ||
expect(li18n._(t`Hello world`)).toBe("Hola mundo"); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
const assert = require("assert"); | ||
|
||
const { nodeBabelOptions } = require("./frontend/webpack/base"); | ||
|
||
let { presets, plugins } = nodeBabelOptions; | ||
|
||
assert(presets && plugins); | ||
|
||
module.exports = { | ||
extractBabelOptions: { presets, plugins }, | ||
localeDir: "locales/", | ||
srcPathDirs: ["frontend/lib/"], | ||
format: "po", | ||
sourceLocale: "en", | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
msgid "" | ||
msgstr "" | ||
"POT-Creation-Date: 2020-05-05 12:34+0000\n" | ||
"Mime-Version: 1.0\n" | ||
"Content-Type: text/plain; charset=utf-8\n" | ||
"Content-Transfer-Encoding: 8bit\n" | ||
"X-Generator: @lingui/cli\n" | ||
"Language: en\n" | ||
"Project-Id-Version: \n" | ||
"Report-Msgid-Bugs-To: \n" | ||
"PO-Revision-Date: \n" | ||
"Last-Translator: \n" | ||
"Language-Team: \n" | ||
"Plural-Forms: \n" | ||
|
||
#: frontend/lib/norent/site.tsx:58 | ||
msgid "Build my Letter" | ||
msgstr "Build my Letter" | ||
|
||
#: frontend/lib/norent/faqs.tsx:70 | ||
msgid "FAQs" | ||
msgstr "FAQs" | ||
|
||
#: frontend/lib/tests/i18n-lingui.test.tsx:19 | ||
#: frontend/lib/tests/i18n-lingui.test.tsx:26 | ||
#: frontend/lib/tests/i18n-lingui.test.tsx:33 | ||
msgid "Hello world" | ||
msgstr "Hello world" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 made the Lingui I18n instance a global instead of always retrieving it from the component hierarchy because we found in Who Owns What that retrieving it for use outside of JSX tags like
<Trans>
was a huge hassle, as we constantly had to wrap components needing it in Lingui's<I18n>
orwithI18n()
. Since our locale setting is already global anyways (e.g. accessingRoutes.locale.home
always dynamically looks up the currently set locale) we might as well roll with it.Regardless, it looks like the in-development version of Lingui is introducing a
useLingui()
hook that will make things a lot easier in the future, and migrating to it from this setup should be straightforward.