Skip to content

Commit

Permalink
Added i18n support
Browse files Browse the repository at this point in the history
  • Loading branch information
thedanielforum committed Oct 21, 2021
1 parent 62aec1f commit 9548b43
Show file tree
Hide file tree
Showing 18 changed files with 971 additions and 42 deletions.
11 changes: 11 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"presets": ["next/babel"],
"plugins": [
[
"formatjs",
{
"ast": true
}
]
]
}
10 changes: 10 additions & 0 deletions compiled-lang/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"CHu6Xm": "Total Spend (month)",
"HXoCik": "Settings",
"M4hPoZ": "Dashboard",
"a9m3iY": "{amount} $",
"bQAtuf": "Loading...",
"jyUN7v": "Overview",
"kDqURM": "Logout",
"yMjntE": "Dashboard"
}
9 changes: 9 additions & 0 deletions compiled-lang/ja.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"HXoCik": "セッティング",
"M4hPoZ": "ホーム",
"a9m3iY": "{amount} 円",
"bQAtuf": "ローディング中",
"jyUN7v": "Overview",
"kDqURM": "ログアウト",
"yMjntE": "ホーム"
}
20 changes: 18 additions & 2 deletions components/DailySpendCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Fragment, memo } from "react";
import { useIntl } from "react-intl";
import { gql, useQuery } from "@apollo/client";
import { DateTime } from "luxon";

Expand All @@ -13,6 +14,8 @@ const GET_AMOUNT_MAX = gql`
`;

const DailySpendCard: React.FC = () => {
const intl = useIntl();

const { loading, error, data } = useQuery(GET_AMOUNT_MAX, {
variables: { from: DateTime.local().startOf("month").toString() },
});
Expand Down Expand Up @@ -44,12 +47,25 @@ const DailySpendCard: React.FC = () => {
<h6 className="text-uppercase text-muted mb-2">Daily spend</h6>
{loading ? (
<div className="spinner-border spinner-border-sm" role="status">
<span className="visually-hidden">Loading...</span>
<span className="visually-hidden">
{intl.formatMessage({
defaultMessage: "Loading...",
description: "default loading",
})}
</span>
</div>
) : (
<Fragment>
<span className="h2 mb-0">
{getAmount().toLocaleString()}
{intl.formatMessage(
{
defaultMessage: "{amount} $",
description: "monetary amount readout",
},
{
amount: intl.formatNumber(getAmount()),
}
)}
</span>
{false && (
<span
Expand Down
19 changes: 16 additions & 3 deletions components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @next/next/no-html-link-for-pages */
import { forwardRef } from "react";
import { useRouter } from "next/router";
import { useIntl } from "react-intl";
import { useAuthUser } from "next-firebase-auth";
import Link from "next/link";
import { Navbar as StrapNavbar, Nav, Dropdown } from "react-bootstrap";
Expand All @@ -9,6 +10,7 @@ import { classNames } from "../utils";

const Navbar: React.FC = () => {
const router = useRouter();
const intl = useIntl();
const user = useAuthUser();

if (!user.id) {
Expand Down Expand Up @@ -38,11 +40,19 @@ const Navbar: React.FC = () => {
</Dropdown.Toggle>
<Dropdown.Menu className="dropdown-menu-end mt-3">
<Link href="/settings">
<a className="dropdown-item">Settings</a>
<a className="dropdown-item">
{intl.formatMessage({
defaultMessage: "Settings",
description: "navbar dropdown option",
})}
</a>
</Link>
<hr className="dropdown-divider" />
<a onClick={() => user.signOut()} className="dropdown-item">
Logout
{intl.formatMessage({
defaultMessage: "Logout",
description: "navbar dropdown option",
})}
</a>
</Dropdown.Menu>
</Dropdown>
Expand All @@ -56,7 +66,10 @@ const Navbar: React.FC = () => {
router.asPath === "/" && "active"
)}
>
Dashboard
{intl.formatMessage({
defaultMessage: "Dashboard",
description: "navbar",
})}
</a>
</Link>
</Nav>
Expand Down
29 changes: 25 additions & 4 deletions components/TotalSpendCard.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { memo } from "react";
import { useIntl } from "react-intl";
import { DateTime } from "luxon";
import { gql, useQuery } from "@apollo/client";

Expand All @@ -13,6 +14,8 @@ const GET_AMOUNT_MAX = gql`
`;

const TotalSpendCard: React.FC = () => {
const intl = useIntl();

const { loading, error, data } = useQuery(GET_AMOUNT_MAX, {
variables: { from: DateTime.local().startOf("month").toString() },
});
Expand All @@ -26,7 +29,7 @@ const TotalSpendCard: React.FC = () => {
data.aggregateTransaction &&
data.aggregateTransaction.amountSum
) {
return data.aggregateTransaction.amountSum.toLocaleString();
return data.aggregateTransaction.amountSum;
}
return 0;
};
Expand All @@ -38,14 +41,32 @@ const TotalSpendCard: React.FC = () => {
<div className="row align-items-center gx-0">
<div className="col">
<h6 className="text-uppercase text-muted mb-2">
Total Spend (month)
{intl.formatMessage({
defaultMessage: "Total Spend (month)",
description: "TotalSpendCard title",
})}
</h6>
{loading ? (
<div className="spinner-border spinner-border-sm" role="status">
<span className="visually-hidden">Loading...</span>
<span className="visually-hidden">
{intl.formatMessage({
defaultMessage: "Loading...",
description: "default loading",
})}
</span>
</div>
) : (
<span className="h2 mb-0">{getAmount()}</span>
<span className="h2 mb-0">
{intl.formatMessage(
{
defaultMessage: "{amount} $",
description: "monetary amount readout",
},
{
amount: intl.formatNumber(getAmount()),
}
)}
</span>
)}
</div>
</div>
Expand Down
36 changes: 36 additions & 0 deletions helpers/loadIntlMessages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import fs from "fs/promises";
import path from "path";

type LoadI18nMessagesProps = {
locale: string;
defaultLocale: string;
};

type MessageConfig = { [key: string]: string };

export default async function loadI18nMessages({
locale,
defaultLocale,
}: LoadI18nMessagesProps): Promise<MessageConfig> {
// If the default locale is being used we can skip it
if (locale === defaultLocale) {
return {};
}

if (locale !== defaultLocale) {
const languagePath = path.join(
process.cwd(),
`compiled-lang/${locale}.json`
);
try {
const contents = await fs.readFile(languagePath, "utf-8");
return JSON.parse(contents);
} catch (error) {
console.info(
'Could not load compiled language files. Please run "npm run i18n:compile" first"'
);
console.error(error);
}
}
return {};
}
34 changes: 34 additions & 0 deletions lang/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"CHu6Xm": {
"defaultMessage": "Total Spend (month)",
"description": "TotalSpendCard title"
},
"HXoCik": {
"defaultMessage": "Settings",
"description": "navbar dropdown option"
},
"M4hPoZ": {
"defaultMessage": "Dashboard",
"description": "navbar"
},
"a9m3iY": {
"defaultMessage": "{amount} $",
"description": "monetary amount readout"
},
"bQAtuf": {
"defaultMessage": "Loading...",
"description": "default loading"
},
"jyUN7v": {
"defaultMessage": "Overview",
"description": "index header subTitle"
},
"kDqURM": {
"defaultMessage": "Logout",
"description": "navbar dropdown option"
},
"yMjntE": {
"defaultMessage": "Dashboard",
"description": "index header title"
}
}
30 changes: 30 additions & 0 deletions lang/ja.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"HXoCik": {
"defaultMessage": "セッティング",
"description": "navbar dropdown option"
},
"M4hPoZ": {
"defaultMessage": "ホーム",
"description": "navbar"
},
"jyUN7v": {
"defaultMessage": "Overview",
"description": "index header subTitle"
},
"kDqURM": {
"defaultMessage": "ログアウト",
"description": "navbar dropdown option"
},
"yMjntE": {
"defaultMessage": "ホーム",
"description": "index header title"
},
"bQAtuf": {
"defaultMessage": "ローディング中",
"description": "default loading"
},
"a9m3iY": {
"defaultMessage": "{amount} 円",
"description": "monetary amount readout"
}
}
15 changes: 14 additions & 1 deletion next.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
/** @type {import('next').NextConfig} */
module.exports = {
reactStrictMode: true,
}
i18n: {
locales: ["en", "ja"],
defaultLocale: "en",
localeDetection: true,
},
webpack(config, { dev, ...other }) {
if (!dev) {
// https://formatjs.io/docs/guides/advanced-usage#react-intl-without-parser-40-smaller
config.resolve.alias["@formatjs/icu-messageformat-parser"] =
"@formatjs/icu-messageformat-parser/no-parser";
}
return config;
},
};
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
"version": "0.1.0",
"private": true,
"scripts": {
"predev": "npm run i18n:compile",
"dev": "next dev",
"prebuild": "npm run i18n:compile",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"i18n:extract": "formatjs extract 'pages/**/*.ts*' 'components/**/*.ts*' --out-file lang/en.json",
"i18n:compile": "formatjs compile-folder lang compiled-lang"
},
"dependencies": {
"@apollo/client": "^3.4.16",
Expand All @@ -29,17 +33,22 @@
"react-dom": "17.0.2",
"react-firebaseui": "^5.0.2",
"react-hotkeys-hook": "^3.4.3",
"react-intl": "^5.20.13",
"react-select": "^5.1.0",
"sass": "^1.42.1",
"sweetalert2": "^11.1.9",
"sweetalert2-react-content": "^4.2.0",
"yup": "^0.32.9"
},
"devDependencies": {
"@formatjs/cli": "^4.3.2",
"@types/luxon": "^2.0.5",
"@types/node": "^16.11.1",
"@types/react": "17.0.27",
"babel-plugin-formatjs": "^10.3.10",
"eslint": "7.32.0",
"eslint-config-next": "11.1.2",
"eslint-plugin-formatjs": "^2.17.9",
"typescript": "4.4.3"
}
}
18 changes: 16 additions & 2 deletions pages/404.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import type { NextPage } from "next";
import { useIntl } from "react-intl";
import Link from "next/link";
import loadIntlMessages from "../helpers/loadIntlMessages";
import { InferGetStaticPropsType } from "next";

export async function getStaticProps(ctx: any) {
return {
props: {
intlMessages: await loadIntlMessages(ctx),
},
};
}

type HomePageProps = InferGetStaticPropsType<typeof getStaticProps>;

const Err404 = (props: HomePageProps) => {
const intl = useIntl();

const Err404: NextPage = () => {
return (
<main>
<div className="container mx-auto">
Expand Down
Loading

0 comments on commit 9548b43

Please sign in to comment.