Skip to content

Commit 8ca6ef2

Browse files
Remove @shopify/react-i18n
1 parent 51ac217 commit 8ca6ef2

File tree

19 files changed

+79
-190
lines changed

19 files changed

+79
-190
lines changed

packages/ui-extensions-dev-console/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
},
1414
"dependencies": {
1515
"@shopify/polaris-icons": "^8.0.0",
16-
"@shopify/react-i18n": "^7.5.0",
1716
"@shopify/ui-extensions-server-kit": "5.4.0",
1817
"copy-to-clipboard": "^3.3.3",
1918
"qrcode.react": "^4.2.0",

packages/ui-extensions-dev-console/src/App.tsx

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {Toast} from '@/foundation/Toast'
44
import {Theme} from '@/foundation/Theme'
55
import {ModalContainer} from '@/foundation/ModalContainer'
66
import {ExtensionServerProvider, isValidSurface} from '@shopify/ui-extensions-server-kit'
7-
import {I18nContext, I18nManager} from '@shopify/react-i18n'
87
import React from 'react'
98

109
function getConnectionUrl() {
@@ -25,26 +24,16 @@ const extensionServerOptions = {
2524
surface: isValidSurface(surface) ? surface : undefined,
2625
}
2726

28-
const i18nManager = new I18nManager({
29-
locale: 'en',
30-
onError(error) {
31-
// eslint-disable-next-line no-console
32-
console.error(error)
33-
},
34-
})
35-
3627
function App() {
3728
return (
3829
<ExtensionServerProvider options={extensionServerOptions}>
39-
<I18nContext.Provider value={i18nManager}>
40-
<Theme>
41-
<Layout>
42-
<Routes />
43-
<Toast />
44-
<ModalContainer />
45-
</Layout>
46-
</Theme>
47-
</I18nContext.Provider>
30+
<Theme>
31+
<Layout>
32+
<Routes />
33+
<Toast />
34+
<ModalContainer />
35+
</Layout>
36+
</Theme>
4837
</ExtensionServerProvider>
4938
)
5039
}

packages/ui-extensions-dev-console/src/components/Modal/components/Header/components/CloseButton/CloseButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import en from './translations/en.json'
22
import {IconButton} from '@/components/IconButton/IconButton'
33
import React from 'react'
44
import {XIcon} from '@shopify/polaris-icons'
5-
import {useI18n} from '@shopify/react-i18n'
5+
import {useI18n} from '@/hooks/useI18n'
66

77
interface CloseButtonProps {
88
pressed?: boolean

packages/ui-extensions-dev-console/src/foundation/Layout/Layout.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as styles from './Layout.module.scss'
33
import {isAppPreview} from '@/utilities/app-preview'
44
import React from 'react'
55
import {WrenchIcon} from '@shopify/polaris-icons'
6-
import {useI18n} from '@shopify/react-i18n'
6+
import {useI18n} from '@/hooks/useI18n'
77

88
interface Props {
99
children: React.ReactNode
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import React from 'react'
2+
3+
type TranslationDictionary = Record<string, unknown>
4+
type Replacements = Record<string, string | number | React.ReactNode>
5+
6+
interface I18nTranslator {
7+
translate(key: string, replacements?: Replacements): any
8+
}
9+
10+
function getNestedValue(obj: TranslationDictionary, key: string): string | undefined {
11+
const result = key.split('.').reduce<unknown>((current, segment) => {
12+
if (current != null && typeof current === 'object') {
13+
return (current as TranslationDictionary)[segment]
14+
}
15+
return undefined
16+
}, obj)
17+
return typeof result === 'string' ? result : undefined
18+
}
19+
20+
function interpolate(template: string, replacements?: Replacements): React.ReactNode {
21+
if (!replacements) return template
22+
23+
const hasReactNodes = Object.values(replacements).some((value) => React.isValidElement(value))
24+
25+
if (!hasReactNodes) {
26+
return template.replace(/\{(\w+)\}/g, (match, key: string) =>
27+
key in replacements ? String(replacements[key]) : match,
28+
)
29+
}
30+
31+
const parts: React.ReactNode[] = []
32+
const regex = /\{(\w+)\}/g
33+
let lastIndex = 0
34+
let match: RegExpExecArray | null
35+
36+
while ((match = regex.exec(template)) !== null) {
37+
if (match.index > lastIndex) {
38+
parts.push(template.slice(lastIndex, match.index))
39+
}
40+
const key = match[1]!
41+
parts.push(key in replacements ? replacements[key] : match[0])
42+
lastIndex = regex.lastIndex
43+
}
44+
45+
if (lastIndex < template.length) {
46+
parts.push(template.slice(lastIndex))
47+
}
48+
49+
return React.createElement(React.Fragment, null, ...parts)
50+
}
51+
52+
export function useI18n({fallback}: {id: string; fallback: TranslationDictionary}): [I18nTranslator] {
53+
return [
54+
{
55+
translate(key: string, replacements?: Replacements) {
56+
const template = getNestedValue(fallback, key)
57+
if (template == null) return key
58+
return interpolate(template, replacements)
59+
},
60+
},
61+
]
62+
}

packages/ui-extensions-dev-console/src/sections/Extensions/Extensions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {useApp} from './hooks/useApp'
99
import {isEmbedded} from '@/utilities/embedded'
1010
import {isAppPreview} from '@/utilities/app-preview'
1111
import React from 'react'
12-
import {useI18n} from '@shopify/react-i18n'
12+
import {useI18n} from '@/hooks/useI18n'
1313

1414
export function Extensions() {
1515
const [i18n] = useI18n({

packages/ui-extensions-dev-console/src/sections/Extensions/components/AppHomeRow/AppHomeRow.test.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import {AppHomeRow} from '.'
2-
import en from './translations/en.json'
32
import {PreviewLink, QRCodeModal} from '..'
43
import {DefaultProviders} from 'tests/DefaultProviders'
5-
import {mockI18n} from 'tests/mock-i18n'
64
import {Button} from '@/components'
75
import React from 'react'
86

@@ -19,8 +17,6 @@ vi.mock('@/components', () => ({
1917
Button: (props: any) => props.children,
2018
}))
2119

22-
mockI18n(en)
23-
2420
describe('<AppHomeRow/>', () => {
2521
const defaultState = {
2622
app: {url: 'mock.url', title: 'Mock App Title'},

packages/ui-extensions-dev-console/src/sections/Extensions/components/AppHomeRow/AppHomeRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {useExtensionServerOptions} from '../../hooks/useExtensionServerOptions.j
77
import {Button} from '@/components'
88
import React, {useState} from 'react'
99

10-
import {useI18n} from '@shopify/react-i18n'
10+
import {useI18n} from '@/hooks/useI18n'
1111

1212
export function AppHomeRow() {
1313
const [showModal, setShowModal] = useState(false)

packages/ui-extensions-dev-console/src/sections/Extensions/components/ExtensionRow/ExtensionRow.test.tsx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import {ExtensionRow} from '.'
2-
import en from './translations/en.json'
32
import {QRCodeModal} from '..'
43
import {DefaultProviders} from 'tests/DefaultProviders'
5-
import {mockI18n} from 'tests/mock-i18n'
64
import {Button} from '@/components'
75
import React from 'react'
86

@@ -19,8 +17,6 @@ vi.mock('..', () => ({
1917
Status: () => null,
2018
}))
2119

22-
mockI18n(en)
23-
2420
describe('<ExtensionRow/>', () => {
2521
const legacyAdminExtension = mockExtension({type: 'product_subscription', surface: 'admin'})
2622
const legacyPosExtension = mockExtension({type: 'pos_ui_extension', surface: 'point_of_sale'})

packages/ui-extensions-dev-console/src/sections/Extensions/components/ExtensionRow/ExtensionRow.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import {QRCodeModal, Row, Status} from '..'
55
import {useExtension} from '../../hooks/useExtension'
66
import {Button} from '@/components/Button'
77
import React, {useState} from 'react'
8-
import {useI18n} from '@shopify/react-i18n'
8+
import {useI18n} from '@/hooks/useI18n'
99
import {ExtensionPayload, ExtensionPoint, isUIExtension} from '@shopify/ui-extensions-server-kit'
1010

1111
interface Props {

0 commit comments

Comments
 (0)