Skip to content

Commit

Permalink
translation expo module
Browse files Browse the repository at this point in the history
  • Loading branch information
mozzius committed May 18, 2024
1 parent 5343910 commit 7263777
Show file tree
Hide file tree
Showing 12 changed files with 185 additions and 10 deletions.
6 changes: 6 additions & 0 deletions modules/expo-bluesky-translate/expo-module.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"platforms": ["ios"],
"ios": {
"modules": ["ExpoBlueskyTranslateModule"]
}
}
4 changes: 4 additions & 0 deletions modules/expo-bluesky-translate/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export {
ExpoBlueskyTranslateView,
isAvailable,
} from './src/ExpoBlueskyTranslateView'
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import ExpoModulesCore
import SwiftUI

// Thanks to Andrew Levy for this code snippet
// https://github.com/andrew-levy/swiftui-react-native/blob/d3fbb2abf07601ff0d4b83055e7717bb980910d6/ios/Common/ExpoView%2BUIHostingController.swift

extension ExpoView {
func setupHostingController(_ hostingController: UIHostingController<some View>) {
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
hostingController.view.backgroundColor = .clear

addSubview(hostingController.view)
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: self.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: self.bottomAnchor),
hostingController.view.leftAnchor.constraint(equalTo: self.leftAnchor),
hostingController.view.rightAnchor.constraint(equalTo: self.rightAnchor),
])
}
}
21 changes: 21 additions & 0 deletions modules/expo-bluesky-translate/ios/ExpoBlueskyTranslate.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Pod::Spec.new do |s|
s.name = 'ExpoBlueskyTranslate'
s.version = '1.0.0'
s.summary = 'Uses SwiftUI translation to translate text.'
s.description = 'Uses SwiftUI translation to translate text.'
s.author = ''
s.homepage = 'https://docs.expo.dev/modules/'
s.platforms = { :ios => '13.4' }
s.source = { git: '' }
s.static_framework = true

s.dependency 'ExpoModulesCore'

# Swift/Objective-C compatibility
s.pod_target_xcconfig = {
'DEFINES_MODULE' => 'YES',
'SWIFT_COMPILATION_MODE' => 'wholemodule'
}

s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import ExpoModulesCore
import Foundation
import SwiftUI

public class ExpoBlueskyTranslateModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoBlueskyTranslate")
View(ExpoBlueskyTranslateView.self) {
Events("onEvent")
Prop("text") { (view: ExpoBlueskyTranslateView, text: String) in
view.props.text = text
}
Prop("isPresented") { (view: ExpoBlueskyTranslateView, isPresented: Bool) in
view.props.isPresented = isPresented
}
}
}
}
30 changes: 30 additions & 0 deletions modules/expo-bluesky-translate/ios/ExpoBlueskyTranslateView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import ExpoModulesCore
import Foundation
import SwiftUI

class TranslateViewProps: ObservableObject {
@Published var text: String = ""
@Published var isPresented: Bool = false
@Published var children: [UIView]?
@Published var onEvent: EventDispatcher
init(onEvent: EventDispatcher) {
self.onEvent = onEvent
}
}

class ExpoBlueskyTranslateView: ExpoView {
let props: TranslateViewProps
let onEvent = EventDispatcher()

override func didUpdateReactSubviews() {
let subChildren = self.reactSubviews()
props.children = subChildren
}

required init(appContext: AppContext? = nil) {
props = TranslateViewProps(onEvent: onEvent)
let hostingController = UIHostingController(rootView: TranslateView(props: props))
super.init(appContext: appContext)
setupHostingController(hostingController)
}
}
33 changes: 33 additions & 0 deletions modules/expo-bluesky-translate/ios/TranslateView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import SwiftUI
import Translation

struct TranslateView: View {
@ObservedObject var props: TranslateViewProps

var body: some View {
if #available(iOS 17.4, *) {
VStack {
ForEach(props.children?.indices ?? 0..<0, id: \.self) { index in
UIViewRepresentableWrapper(view: props.children?[index] ?? UIView())
.frame(
width: props.children?[index].frame.width,
height: props.children?[index].frame.height)
}
}
.translationPresentation(
isPresented: $props.isPresented,
text: props.text
)
}
}
}

struct UIViewRepresentableWrapper: UIViewRepresentable {
let view: UIView

func makeUIView(context: Context) -> UIView {
return view
}

func updateUIView(_ uiView: UIView, context: Context) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export type ExpoBlueskyTranslateProps = {
text: string
isPresented?: boolean
children: React.ReactNode
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from 'react'
import {Platform} from 'react-native'
import {requireNativeViewManager} from 'expo-modules-core'

import {ExpoBlueskyTranslateProps} from './ExpoBlueskyTranslate.types'

const NativeView: React.ComponentType<ExpoBlueskyTranslateProps> =
requireNativeViewManager('ExpoBlueskyTranslate')

export function ExpoBlueskyTranslateView(props: ExpoBlueskyTranslateProps) {
return <NativeView {...props} />
}

export const isAvailable = Number(Platform.Version) >= 17.4
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {ExpoBlueskyTranslateProps} from './ExpoBlueskyTranslate.types'

export function ExpoBlueskyTranslateView(_: ExpoBlueskyTranslateProps) {
return null
}

export const isAvailable = false
2 changes: 2 additions & 0 deletions modules/expo-scroll-forwarder/src/ExpoScrollForwarderView.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react'

import {ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types'

export function ExpoScrollForwarderView({
children,
}: React.PropsWithChildren<ExpoScrollForwarderViewProps>) {
Expand Down
33 changes: 23 additions & 10 deletions src/view/com/post-thread/PostThreadItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ import {useSession} from 'state/session'
import {PostThreadFollowBtn} from 'view/com/post-thread/PostThreadFollowBtn'
import {atoms as a} from '#/alf'
import {RichText} from '#/components/RichText'
import {
ExpoBlueskyTranslateView,
isAvailable as isNativeTranslateAvailable,
} from '../../../../modules/expo-bluesky-translate'
import {ContentHider} from '../../../components/moderation/ContentHider'
import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe'
import {PostAlerts} from '../../../components/moderation/PostAlerts'
Expand Down Expand Up @@ -318,6 +322,7 @@ let PostThreadItemLoaded = ({
</ContentHider>
<ExpandedPostDetails
post={post}
text={record?.text || ''}
translatorUrl={translatorUrl}
needsTranslation={needsTranslation}
/>
Expand Down Expand Up @@ -620,32 +625,40 @@ function PostOuterWrapper({

function ExpandedPostDetails({
post,
text,
needsTranslation,
translatorUrl,
}: {
post: AppBskyFeedDefs.PostView
text: string
needsTranslation: boolean
translatorUrl: string
}) {
const pal = usePalette('default')
const {_} = useLingui()
const openLink = useOpenLink()
const onTranslatePress = React.useCallback(
() => openLink(translatorUrl),
[openLink, translatorUrl],
)
const [presented, setPresented] = React.useState(false)
const onTranslatePress = React.useCallback(() => {
if (isNativeTranslateAvailable) {
setPresented(true)
} else {
openLink(translatorUrl)
}
}, [openLink, translatorUrl])
return (
<View style={[s.flexRow, s.mt2, s.mb10]}>
<Text style={pal.textLight}>{niceDate(post.indexedAt)}</Text>
{needsTranslation && (
<>
<Text style={pal.textLight}> &middot; </Text>
<Text
style={pal.link}
title={_(msg`Translate`)}
onPress={onTranslatePress}>
<Trans>Translate</Trans>
</Text>
<ExpoBlueskyTranslateView text={text} isPresented={presented}>
<Text
style={pal.link}
title={_(msg`Translate`)}
onPress={onTranslatePress}>
<Trans>Translate</Trans>
</Text>
</ExpoBlueskyTranslateView>
</>
)}
</View>
Expand Down

0 comments on commit 7263777

Please sign in to comment.