Skip to content

Commit

Permalink
refactor: add t, useTranslation helpers to use translations
Browse files Browse the repository at this point in the history
  • Loading branch information
sidvishnoi committed Jul 5, 2024
1 parent cd8f0cc commit 985957a
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 14 deletions.
7 changes: 7 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@
"react-hooks/exhaustive-deps": "error",
"react/react-in-jsx-scope": "off",
"react/jsx-uses-react": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"@typescript-eslint/no-explicit-any": "off"
},
"overrides": [
Expand Down
8 changes: 5 additions & 3 deletions src/background/services/tabEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { MonetizationService } from './monetization'
import { StorageService } from './storage'
import { IsTabMonetizedPayload } from '@/shared/messages'
import { getTabId } from '../utils'
import { tFactory } from '@/shared/helpers'

const runtime = browser.runtime
const ICONS = {
Expand Down Expand Up @@ -62,15 +63,16 @@ export class TabEvents {
sender?: Runtime.MessageSender
) => {
const { enabled } = await this.storage.get(['enabled'])
const t = tFactory(this.browser)

let title = this.browser.i18n.getMessage('appName')
let title = t('appName')
let iconData = enabled ? ICONS.default : ICONS.warning
if (enabled && payload) {
const { value: isTabMonetized } = payload
iconData = isTabMonetized ? ICONS.active : ICONS.inactive
const tabStateText = isTabMonetized
? this.browser.i18n.getMessage('monetizationActiveShort')
: this.browser.i18n.getMessage('monetizationInactiveShort')
? t('monetizationActiveShort')
: t('monetizationInactiveShort')
title = `${title} - ${tabStateText}`
}
const tabId = sender && getTabId(sender)
Expand Down
11 changes: 7 additions & 4 deletions src/popup/Popup.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { MainLayout } from '@/popup/components/layout/MainLayout'
import { PopupContextProvider } from './lib/context'
import { PopupContextProvider, TranslationContextProvider } from './lib/context'
import { LazyMotion, domAnimation } from 'framer-motion'
import React from 'react'
import browser from 'webextension-polyfill'
import { ProtectedRoute } from '@/popup/components/ProtectedRoute'
import {
RouteObject,
Expand Down Expand Up @@ -49,9 +50,11 @@ const router = createMemoryRouter(routes)
export const Popup = () => {
return (
<LazyMotion features={domAnimation} strict>
<PopupContextProvider>
<RouterProvider router={router} />
</PopupContextProvider>
<TranslationContextProvider browser={browser}>
<PopupContextProvider>
<RouterProvider router={router} />
</PopupContextProvider>
</TranslationContextProvider>
</LazyMotion>
)
}
7 changes: 3 additions & 4 deletions src/popup/components/SiteNotMonetized.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import React from 'react'
import browser from 'webextension-polyfill'
import { WarningSign } from '@/popup/components/Icons'
import { useTranslation } from '@/popup/lib/context'

export const SiteNotMonetized = () => {
const t = useTranslation()
return (
<div className="flex h-full items-center justify-center gap-2 p-4 text-lg">
<div className="flex-shrink-0">
<WarningSign className="size-6 text-medium" />
</div>
<h3 className="text-medium">
{browser.i18n.getMessage('siteNotMonetized')}
</h3>
<h3 className="text-medium">{t('siteNotMonetized')}</h3>
</div>
)
}
27 changes: 25 additions & 2 deletions src/popup/lib/context.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react'
import browser from 'webextension-polyfill'
import browser, { type Browser } from 'webextension-polyfill'
import { getContextData } from '@/popup/lib/messages'
import { DeepNonNullable, PopupStore } from '@/shared/types'
import { tFactory } from '@/shared/helpers'
import type { DeepNonNullable, PopupStore } from '@/shared/types'
import {
ContentToBackgroundAction,
type ContentToBackgroundMessage
Expand Down Expand Up @@ -161,3 +162,25 @@ export function PopupContextProvider({ children }: PopupContextProviderProps) {
</PopupStateContext.Provider>
)
}

const TranslationContext = React.createContext<ReturnType<typeof tFactory>>(
(v: string) => v
)

export const TranslationContextProvider = ({
browser,
children
}: {
browser: Browser
children: React.ReactNode
}) => {
const t = tFactory(browser)

return (
<TranslationContext.Provider value={t}>
{children}
</TranslationContext.Provider>
)
}

export const useTranslation = () => React.useContext(TranslationContext)
4 changes: 3 additions & 1 deletion src/popup/pages/MissingHostPermission.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import React from 'react'
import browser from 'webextension-polyfill'
import { PERMISSION_HOSTS } from '@/shared/defines'
import { WarningSign } from '@/popup/components/Icons'
import { useTranslation } from '@/popup/lib/context'

export const Component = () => {
const t = useTranslation()
return (
<div className="rounded-md bg-orange-50 p-4 text-sm">
<div className="flex">
Expand All @@ -13,7 +15,7 @@ export const Component = () => {
<div className="ml-3 flex flex-col gap-2">
<h3 className="font-medium text-orange-800">Permission needed</h3>
<div className="text-orange-700">
<p>{browser.i18n.getMessage('hostsPermissionsNeeded')}</p>
<p>{t('hostsPermissionsNeeded')}</p>
</div>
</div>
</div>
Expand Down
15 changes: 15 additions & 0 deletions src/shared/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { SuccessResponse } from '@/shared/messages'
import { WalletAddress } from '@interledger/open-payments/dist/types'
import { cx, CxOptions } from 'class-variance-authority'
import { twMerge } from 'tailwind-merge'
import type { Browser } from 'webextension-polyfill'
import type { ExcludeFirst } from './types'

export const cn = (...inputs: CxOptions) => {
return twMerge(cx(inputs))
Expand Down Expand Up @@ -192,3 +194,16 @@ export function convert(value: bigint, source: number, target: number) {
export function bigIntMax(a: string, b: string) {
return BigInt(a) > BigInt(b) ? a : b
}

/**
* Helper over calling cumbersome `this.browser.i18n.getMessage(key)` with added
* benefit that it type-checks if key exists in message.json
*/
export function t<
T extends keyof typeof import('../_locales/en/messages.json')
>(browser: Pick<Browser, 'i18n'>, key: T, substitutions?: string | string[]) {
return browser.i18n.getMessage(key, substitutions)
}
export function tFactory(browser: Pick<Browser, 'i18n'>) {
return (...args: ExcludeFirst<Parameters<typeof t>>) => t(browser, ...args)
}
3 changes: 3 additions & 0 deletions src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,6 @@ export type PopupStore = Omit<
export type DeepNonNullable<T> = {
[P in keyof T]?: NonNullable<T[P]>
}

export type ExcludeFirst<T extends [f: unknown, ...rest: unknown[]]> =
T extends [infer _F, ...infer Rest] ? Rest : never

0 comments on commit 985957a

Please sign in to comment.