diff --git a/src/components/AdhocOrderCard.tsx b/src/components/AdhocOrderCard.tsx
index 72c8985e..9780a5a8 100644
--- a/src/components/AdhocOrderCard.tsx
+++ b/src/components/AdhocOrderCard.tsx
@@ -18,6 +18,7 @@ import MultipleCustomerAvatars from './MultipleCustomerAvatars';
import LoadingText from './LoadingText';
import LoadingOverlay from './LoadingOverlay';
import Badge from './Badge';
+import { useLanguage } from '../contexts/LanguageContext';
const INFO_FIELD_VALUE_MIN_HEIGHT = 30;
export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
@@ -27,6 +28,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
const { location } = useLocation();
const { isDarkMode } = useAppTheme();
const [isAccepting, setIsAccepting] = useState(false);
+ const { t } = useLanguage();
const destination = useMemo(() => {
const pickup = order.getAttribute('payload.pickup');
@@ -44,13 +46,13 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
}, [location, destination]);
const handleAccept = useCallback(async () => {
- Alert.alert('Accept Ad-Hoc order?', 'By accepting this ad-hoc order it will become assigned to you and the order will start immediatley.', [
+ Alert.alert(t('common.cancel'), t('AdhocOrderCard.byAcceptingThisAdHocOrderItWillBecomeAssignedToYouAndTheOrderWillStartImmediatley'), [
{
- text: 'Cancel',
+ text: t('common.cancel'),
style: 'cancel',
},
{
- text: 'Accept',
+ text: t('AdhocOrderCard.acceptOrder'),
onPress: async () => {
setIsAccepting(true);
@@ -70,13 +72,13 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
}, [order, setIsAccepting]);
const handleDismiss = useCallback(() => {
- Alert.alert('Dismiss Ad-Hoc order?', 'By dimissing this ad-hoc order it will no longer display as an available order.', [
+ Alert.alert(t('common.cancel'), t('AdhocOrderCard.byDimissingThisAdHocOrderItWillNoLongerDisplayAsAnAvailableOrder'), [
{
- text: 'Cancel',
+ text: t('common.cancel'),
style: 'cancel',
},
{
- text: 'OK',
+ text: t('common.close'),
onPress: () => {
if (typeof onDismiss === 'function') {
onDismiss(order);
@@ -88,7 +90,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
return (
-
+
{
- Order Available Nearby: {formatMeters(distance)}
+ {t('AdhocOrderCard.orderAvailableNearby')}: {formatMeters(distance)}
@@ -126,7 +128,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
{formatWhatsAppTimestamp(new Date(order.getAttribute('created_at')))}
- {formatMeters(distance)} away
+ {formatMeters(distance)} {t('AdhocOrderCard.away')}
@@ -139,7 +141,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
icon={faLocationDot}
iconColor={theme['$textPrimary'].val}
waypoint={destination.serialize()}
- title='Pickup Destination'
+ title={t('AdhocOrderCard.pickupDestination')}
titleStyle={{ fontWeight: 'bold', fontSize: 14, textTransform: 'uppercase' }}
/>
@@ -147,7 +149,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
@@ -155,7 +157,7 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
- Dismiss Order
+ {t('AdhocOrderCard.dismissOrder')}
@@ -165,4 +167,4 @@ export const AdhocOrderCard = ({ order, onPress, onAccept, onDismiss }) => {
);
};
-export default AdhocOrderCard;
+export default AdhocOrderCard;
\ No newline at end of file
diff --git a/src/components/Buttons.tsx b/src/components/Buttons.tsx
index cadd95ba..b0fc82ee 100644
--- a/src/components/Buttons.tsx
+++ b/src/components/Buttons.tsx
@@ -5,22 +5,25 @@ import { faFacebook, faInstagram, faGoogle, faApple } from '@fortawesome/free-br
import { faPhone } from '@fortawesome/free-solid-svg-icons';
import LinearGradient from 'react-native-linear-gradient';
import { useTheme } from 'tamagui';
+import { useLanguage } from '../contexts/LanguageContext';
export const PhoneLoginButton = ({ onPress, ...props }) => {
const theme = useTheme();
+ const { t } = useLanguage();
return (
);
};
export const AppleLoginButton = ({ onPress, ...props }) => {
const theme = useTheme();
+ const { t } = useLanguage();
return (
)}
{comment.editable && (
{isDeleting ? : }
- Delete
+ {t('common.delete')}
)}
@@ -148,7 +150,7 @@ const Comment = ({ comment: _comment, reloadComments, isCommentInvalid }) => {
@@ -187,4 +189,4 @@ const Comment = ({ comment: _comment, reloadComments, isCommentInvalid }) => {
);
};
-export default Comment;
+export default Comment;
\ No newline at end of file
diff --git a/src/components/CommentThread.tsx b/src/components/CommentThread.tsx
index 1e3da6cc..e0b648e3 100644
--- a/src/components/CommentThread.tsx
+++ b/src/components/CommentThread.tsx
@@ -5,12 +5,14 @@ import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faPaperPlane, faRotate } from '@fortawesome/free-solid-svg-icons';
import useAppTheme from '../hooks/use-app-theme';
import Comment from './Comment';
+import { useLanguage } from '../contexts/LanguageContext';
const CommentThread = ({ comments: initialComments = [], subject, onReloadComments, isReloading }) => {
const { isDarkMode } = useAppTheme();
const theme = useTheme();
const [comments, setComments] = useState(initialComments);
const [input, setInput] = useState('');
+ const { t } = useLanguage();
const reloadComments = useCallback(async () => {
if (typeof onReloadComments === 'function') {
@@ -21,7 +23,7 @@ const CommentThread = ({ comments: initialComments = [], subject, onReloadCommen
const isCommentInvalid = (comment) => {
if (!comment || comment.trim().length < 2) {
- Alert.alert('Invalid Comment', 'Comment must be at least 2 characters.');
+ Alert.alert(t('common.error'), t('CommentThread.commentMustBeAtLeast2Characters'));
return true;
}
return false;
@@ -52,7 +54,7 @@ const CommentThread = ({ comments: initialComments = [], subject, onReloadCommen
@@ -91,4 +93,4 @@ const CommentThread = ({ comments: initialComments = [], subject, onReloadCommen
);
};
-export default CommentThread;
+export default CommentThread;
\ No newline at end of file
diff --git a/src/components/CurrentDestinationSelect.tsx b/src/components/CurrentDestinationSelect.tsx
index b3509d6b..a645de97 100644
--- a/src/components/CurrentDestinationSelect.tsx
+++ b/src/components/CurrentDestinationSelect.tsx
@@ -12,6 +12,7 @@ import PlaceMapView from './PlaceMapView';
import Badge from './Badge';
import Spacer from './Spacer';
import useAppTheme from '../hooks/use-app-theme';
+import { useLanguage } from '../contexts/LanguageContext';
const CurrentDestinationSelect = ({ onChange, destination, waypoints = [], snapTo = '100%', isLoading = false, ...props }) => {
const { isDarkMode } = useAppTheme();
@@ -20,6 +21,7 @@ const CurrentDestinationSelect = ({ onChange, destination, waypoints = [], snapT
const bottomSheetRef = useRef(null);
const snapPoints = useMemo(() => [snapTo], [snapTo]);
const desinationStatus = destination.getAttribute('status');
+ const { t } = useLanguage();
const openBottomSheet = () => {
bottomSheetRef.current?.snapToPosition(snapTo);
@@ -53,7 +55,7 @@ const CurrentDestinationSelect = ({ onChange, destination, waypoints = [], snapT
) : (
- {destination.getAttribute('name') ?? 'Current Destination'}
+ {destination.getAttribute('name') ?? t('CurrentDestinationSelect.selectDestination')}
{formattedAddressFromPlace(destination)}
@@ -96,7 +98,7 @@ const CurrentDestinationSelect = ({ onChange, destination, waypoints = [], snapT
- Select destination
+ {t('CurrentDestinationSelect.selectDestination')}
{waypoint.getAttribute('name') ?? waypoint.getAttribute('street1')}
- {isDestination && (Destination)}
+ {isDestination && {t('CurrentDestinationSelect.destination')}}
{typeof waypoint.getAttribute('status') === 'string' && (
@@ -200,4 +202,4 @@ const CurrentDestinationSelect = ({ onChange, destination, waypoints = [], snapT
);
};
-export default CurrentDestinationSelect;
+export default CurrentDestinationSelect;
\ No newline at end of file
diff --git a/src/components/DestinationChangedAlert.tsx b/src/components/DestinationChangedAlert.tsx
index 124d16fe..7588f4ca 100644
--- a/src/components/DestinationChangedAlert.tsx
+++ b/src/components/DestinationChangedAlert.tsx
@@ -5,6 +5,7 @@ import { YStack, XStack, Text, Button, useTheme } from 'tamagui';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faCheck } from '@fortawesome/free-solid-svg-icons';
import WaypointList from './WaypointList';
+import { useLanguage } from '../contexts/LanguageContext';
interface DestinationChangedAlertProps {
visible: boolean;
@@ -16,6 +17,7 @@ interface DestinationChangedAlertProps {
const DestinationChangedAlert: React.FC = ({ visible, previousDestination, currentDestination, onClose }) => {
const theme = useTheme();
+ const { t } = useLanguage();
const prevAddress = previousDestination?.getAttribute('address');
const currAddress = currentDestination?.getAttribute('address');
@@ -27,13 +29,13 @@ const DestinationChangedAlert: React.FC = ({ visib
- Waypoint Completed
+ {t('DestinationChangedAlert.waypointCompleted')}
- Activity for waypoint {prevAddress} is complete.
+ {t('DestinationChangedAlert.waypointCompleted')} for waypoint {prevAddress} is complete.
Your current destination has changed to {currAddress}.
@@ -48,7 +50,7 @@ const DestinationChangedAlert: React.FC = ({ visib
- Continue
+ {t('DestinationChangedAlert.continue')}
@@ -58,4 +60,4 @@ const DestinationChangedAlert: React.FC = ({ visib
);
};
-export default DestinationChangedAlert;
+export default DestinationChangedAlert;
\ No newline at end of file
diff --git a/src/components/FuelReportForm.tsx b/src/components/FuelReportForm.tsx
index de3d9e1c..b676495a 100644
--- a/src/components/FuelReportForm.tsx
+++ b/src/components/FuelReportForm.tsx
@@ -12,11 +12,13 @@ import { getDriverFuelReportStatuses, FuelReportStatus } from '../constants/Enum
import BottomSheetSelect from '../components/BottomSheetSelect';
import UnitInput from '../components/UnitInput';
import MoneyInput from '../components/MoneyInput';
+import { useLanguage } from '../contexts/LanguageContext';
const FuelReportForm = ({ value = {}, onSubmit, isSubmitting = false, submitText = 'Publish Fuel Report' }) => {
const theme = useTheme();
const navigation = useNavigation();
const insets = useSafeAreaInsets();
+ const { t } = useLanguage();
const [fuelReport, setFuelReport] = useState({
status: FuelReportStatus.DRAFT,
odometer: '',
@@ -60,7 +62,7 @@ const FuelReportForm = ({ value = {}, onSubmit, isSubmitting = false, submitText
- Status
+ {t('FuelReportForm.status')}
handleUpdateFuelReport('status', value)}
- title='Select Fuel Report Status'
+ title={t('FuelReportForm.selectFuelReportStatus')}
humanize={true}
portalHost='FuelReportFormPortal'
snapTo='100%'
@@ -77,13 +79,13 @@ const FuelReportForm = ({ value = {}, onSubmit, isSubmitting = false, submitText
- Odometer
+ {t('FuelReportForm.odometer')}
handleUpdateFuelReport('odometer', text)}
keyboardType='phone-pad'
- placeholder='Input your current odometer...'
+ placeholder={t('FuelReportForm.inputYourCurrentOdometer')}
borderWidth={1}
color='$textPrimary'
borderColor='$borderColor'
@@ -93,7 +95,7 @@ const FuelReportForm = ({ value = {}, onSubmit, isSubmitting = false, submitText
- Volume
+ {t('FuelReportForm.volume')}
- Cost
+ {t('FuelReportForm.cost')}
@@ -147,4 +149,4 @@ const FuelReportForm = ({ value = {}, onSubmit, isSubmitting = false, submitText
);
};
-export default FuelReportForm;
+export default FuelReportForm;
\ No newline at end of file
diff --git a/src/components/InstanceLinkHandler.tsx b/src/components/InstanceLinkHandler.tsx
index e1a8ac12..4121e330 100644
--- a/src/components/InstanceLinkHandler.tsx
+++ b/src/components/InstanceLinkHandler.tsx
@@ -5,6 +5,7 @@ import { useConfig } from '../contexts/ConfigContext';
import { setString } from '../hooks/use-storage';
import { get } from '../utils';
import { toast } from '../utils/toast';
+import { useLanguage } from '../contexts/LanguageContext';
function getUrlParams(url) {
const params = {};
@@ -29,6 +30,7 @@ function getUrlParams(url) {
const InstanceLinkHandler = ({}) => {
const { logout } = useAuth();
const { setInstanceLinkConfig } = useConfig();
+ const { t } = useLanguage();
const handleSetupInstanceLink = useCallback(
(url) => {
@@ -45,9 +47,9 @@ const InstanceLinkHandler = ({}) => {
logout();
// Notify
- toast.success('Instance link was successful!');
+ toast.success(t('InstanceLinkHandler.instanceLinkWasSuccessful'));
},
- [logout, setInstanceLinkConfig]
+ [logout, setInstanceLinkConfig, t]
);
useEffect(() => {
@@ -60,4 +62,4 @@ const InstanceLinkHandler = ({}) => {
}, []);
};
-export default InstanceLinkHandler;
+export default InstanceLinkHandler;
\ No newline at end of file
diff --git a/src/components/IssueForm.tsx b/src/components/IssueForm.tsx
index a0c48997..b5ef604e 100644
--- a/src/components/IssueForm.tsx
+++ b/src/components/IssueForm.tsx
@@ -10,11 +10,13 @@ import { uppercase } from '../utils/format';
import { getIssueTypes, getIssuePriorities, getIssueStatuses, getIssueCategories, IssueStatus, IssuePriority } from '../constants/Enums';
import BottomSheetSelect from '../components/BottomSheetSelect';
import TextAreaSheet from '../components/TextAreaSheet';
+import { useLanguage } from '../contexts/LanguageContext';
const IssueForm = ({ value = {}, onSubmit, isSubmitting = false, submitText = 'Publish Issue' }) => {
const theme = useTheme();
const navigation = useNavigation();
const insets = useSafeAreaInsets();
+ const { t } = useLanguage();
const [issue, setIssue] = useState({
status: IssueStatus.PENDING,
priority: IssuePriority.LOW,
@@ -56,7 +58,7 @@ const IssueForm = ({ value = {}, onSubmit, isSubmitting = false, submitText = 'P
- Issue Type
+ {t('IssueForm.issueType')}
handleUpdateIssue('type', value)}
- title='Select Issue Type'
+ title={t('IssueForm.selectIssueType')}
humanize={true}
portalHost='IssueFormPortal'
snapTo='100%'
@@ -73,13 +75,13 @@ const IssueForm = ({ value = {}, onSubmit, isSubmitting = false, submitText = 'P
- Issue Category
+ {t('IssueForm.issueCategory')}
handleUpdateIssue('category', value)}
- title='Select Issue Category'
+ title={t('IssueForm.selectIssueCategory')}
humanize={true}
portalHost='IssueFormPortal'
snapTo='100%'
@@ -88,7 +90,7 @@ const IssueForm = ({ value = {}, onSubmit, isSubmitting = false, submitText = 'P
- Issue Priority
+ {t('IssueForm.issuePriority')}
handleUpdateIssue('priority', value)}
- title='Select Issue Priority'
+ title={t('IssueForm.selectIssuePriority')}
humanize={true}
portalHost='IssueFormPortal'
snapTo='100%'
@@ -105,7 +107,7 @@ const IssueForm = ({ value = {}, onSubmit, isSubmitting = false, submitText = 'P
- Issue Status
+ {t('IssueForm.issueStatus')}
handleUpdateIssue('status', value)}
- title='Select Issue Status'
+ title={t('IssueForm.selectIssueStatus')}
humanize={true}
portalHost='IssueFormPortal'
snapTo='100%'
@@ -122,13 +124,13 @@ const IssueForm = ({ value = {}, onSubmit, isSubmitting = false, submitText = 'P
- Issue Report
+ {t('IssueForm.issueReport')}
handleUpdateIssue('report', value)}
- title='Issue Report'
- placeholder='Type your issue report...'
+ title={t('IssueForm.issueReport')}
+ placeholder={t('IssueForm.typeYourIssueReport')}
portalHost='IssueFormPortal'
snapTo='100%'
onBottomSheetPositionChanged={setIsBottomSheetPresenting}
@@ -158,4 +160,4 @@ const IssueForm = ({ value = {}, onSubmit, isSubmitting = false, submitText = 'P
);
};
-export default IssueForm;
+export default IssueForm;
\ No newline at end of file
diff --git a/src/components/LocationPicker.tsx b/src/components/LocationPicker.tsx
index ba4f8d25..c484d369 100644
--- a/src/components/LocationPicker.tsx
+++ b/src/components/LocationPicker.tsx
@@ -12,6 +12,7 @@ import useStorage from '../hooks/use-storage';
import useCurrentLocation from '../hooks/use-current-location';
import useSavedLocations from '../hooks/use-saved-locations';
import useAppTheme from '../hooks/use-app-theme';
+import { useLanguage } from '../contexts/LanguageContext';
const LocationPicker = ({
onPressAddNewLocation,
@@ -32,6 +33,7 @@ const LocationPicker = ({
const [isDropdownOpen, setDropdownOpen] = useState(false);
const [triggerPosition, setTriggerPosition] = useState({ x: 28, y: 0, width: 0, height: 20 });
const triggerRef = useRef(null);
+ const { t } = useLanguage();
// Get screen width and calculate 75% of it
const screenWidth = Dimensions.get('window').width;
@@ -116,7 +118,7 @@ const LocationPicker = ({
triggerTextStyle,
]}
>
- {currentLocation ? (currentLocation.isAttributeFilled('name') ? currentLocation.getAttribute('name') : formattedAddressFromPlace(currentLocation)) : 'Loading...'}
+ {currentLocation ? (currentLocation.isAttributeFilled('name') ? currentLocation.getAttribute('name') : formattedAddressFromPlace(currentLocation)) : t('common.loading')}
▼
@@ -196,7 +198,7 @@ const LocationPicker = ({
>
- Add New Location
+ {t('LocationPicker.addNewLocation')}
@@ -208,4 +210,4 @@ const LocationPicker = ({
);
};
-export default LocationPicker;
+export default LocationPicker;
\ No newline at end of file
diff --git a/src/components/MoneyInput.tsx b/src/components/MoneyInput.tsx
index b49a708f..d8851ede 100644
--- a/src/components/MoneyInput.tsx
+++ b/src/components/MoneyInput.tsx
@@ -8,6 +8,7 @@ import { faPenToSquare } from '@fortawesome/free-solid-svg-icons';
import { Portal } from '@gorhom/portal';
import { debounce } from '../utils';
import { currencies, getCurrency } from '../utils/currencies';
+import { useLanguage } from '../contexts/LanguageContext';
const MoneyInput = ({
value: _value,
@@ -25,6 +26,7 @@ const MoneyInput = ({
onBottomSheetClosed,
}) => {
const theme = useTheme();
+ const { t } = useLanguage();
const [selectedCurrency, setSelectedCurrency] = useState(defaultCurrency);
const [value, setValue] = useState(_value);
const [searchTerm, setSearchTerm] = useState('');
@@ -122,7 +124,7 @@ const MoneyInput = ({
= ({ customers = [], size = 25 }) => {
+ const { t } = useLanguage();
+
// Display a friendly message when no customers exist
if (customers.length === 0) {
return (
- No customers
+ {t('MultipleCustomerAvatars.noCustomers')}
);
}
@@ -49,4 +52,4 @@ export const MultipleCustomerAvatars: React.FC = (
);
};
-export default MultipleCustomerAvatars;
+export default MultipleCustomerAvatars;
\ No newline at end of file
diff --git a/src/components/OrderActivitySelect.tsx b/src/components/OrderActivitySelect.tsx
index 4b311a52..5a7a9513 100644
--- a/src/components/OrderActivitySelect.tsx
+++ b/src/components/OrderActivitySelect.tsx
@@ -14,6 +14,7 @@ import useAppTheme from '../hooks/use-app-theme';
import PlaceMapView from './PlaceMapView';
import Spacer from './Spacer';
import Badge from './Badge';
+import { useLanguage } from '../contexts/LanguageContext';
const OrderActivitySelect = forwardRef(({ onChange, waypoint, activities = [], snapTo = '100%', isLoading = false, activityLoading, portalHost = 'MainPortal', ...props }, ref) => {
const theme = useTheme();
@@ -21,6 +22,7 @@ const OrderActivitySelect = forwardRef(({ onChange, waypoint, activities = [], s
const { isDarkMode } = useAppTheme();
const bottomSheetRef = useRef(null);
const snapPoints = useMemo(() => [snapTo], [snapTo]);
+ const { t } = useLanguage();
// Expose methods to the parent via ref.
useImperativeHandle(
@@ -85,7 +87,7 @@ const OrderActivitySelect = forwardRef(({ onChange, waypoint, activities = [], s
space='$2'
>
- Requires proof of delivery
+ {t('OrderActivitySelect.requiresProofOfDelivery')}
)}
@@ -115,13 +117,13 @@ const OrderActivitySelect = forwardRef(({ onChange, waypoint, activities = [], s
- Select activity
+ {t('OrderActivitySelect.selectActivity')}
{waypoint && (
- Updating activity for:
+ {t('OrderActivitySelect.updatingActivityFor')}
{
const theme = useTheme();
const { isDarkMode } = useAppTheme();
const { trackerData } = useOrderResource(order, { loadEta: false });
+ const { t } = useLanguage();
const waypointCustomers = useMemo(() => {
const waypoints = order.getAttribute('payload.waypoints', []) ?? [];
return waypoints
@@ -81,7 +83,7 @@ export const OrderCard = ({ order, onPress }) => {
- {waypointCustomers.length > 0 ? 'Customers:' : 'Customer:'}
+ {waypointCustomers.length > 0 ? t('OrderCard.customers') : t('OrderCard.customer')}
{waypointCustomers.length > 0 ? (
@@ -102,7 +104,7 @@ export const OrderCard = ({ order, onPress }) => {
>
) : (
- N/A
+ {t('OrderCard.nA')}
)}
>
@@ -111,11 +113,11 @@ export const OrderCard = ({ order, onPress }) => {
- Date Scheduled:
+ {t('OrderCard.dateScheduled')}
{
- POD Required:
+ {t('OrderCard.podRequired')}
{
- Dispatched At:
+ {t('OrderCard.dispatchedAt')}
{
- ETA:
+ {t('OrderCard.eta')}
{
- ECT:
+ {t('OrderCard.ect')}
@@ -183,4 +185,4 @@ export const OrderCard = ({ order, onPress }) => {
);
};
-export default OrderCard;
+export default OrderCard;
\ No newline at end of file
diff --git a/src/components/OrderCustomerCard.tsx b/src/components/OrderCustomerCard.tsx
index 4ad73ef1..c160de50 100644
--- a/src/components/OrderCustomerCard.tsx
+++ b/src/components/OrderCustomerCard.tsx
@@ -2,9 +2,11 @@ import { YStack, XStack, Text, Avatar, Separator, Button, useTheme } from 'tamag
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faPhone, faEnvelope, faMessage } from '@fortawesome/free-solid-svg-icons';
import FastImage from 'react-native-fast-image';
+import { useLanguage } from '../contexts/LanguageContext';
const OrderCustomerCard = ({ customer }) => {
const theme = useTheme();
+ const { t } = useLanguage();
return (
@@ -33,19 +35,19 @@ const OrderCustomerCard = ({ customer }) => {
- Call
+ {t('OrderCustomerCard.call')}
- Email
+ {t('OrderCustomerCard.email')}
- Chat
+ {t('OrderCustomerCard.chat')}
@@ -53,4 +55,4 @@ const OrderCustomerCard = ({ customer }) => {
);
};
-export default OrderCustomerCard;
+export default OrderCustomerCard;
\ No newline at end of file
diff --git a/src/components/OrderDocumentFiles.tsx b/src/components/OrderDocumentFiles.tsx
index b0c9ba7c..a48b786f 100644
--- a/src/components/OrderDocumentFiles.tsx
+++ b/src/components/OrderDocumentFiles.tsx
@@ -11,10 +11,12 @@ import FastImage from 'react-native-fast-image';
import FileViewer from 'react-native-file-viewer';
import RNFS from 'react-native-fs';
import Share from 'react-native-share';
+import { useLanguage } from '../contexts/LanguageContext';
const DOCUMENT_COLUMN_WIDTH = 100;
const OrderDocumentFiles = ({ order }) => {
const theme = useTheme();
+ const { t } = useLanguage();
const files = order.getAttribute('files', []);
const isImageFile = (file) => {
@@ -53,17 +55,17 @@ const OrderDocumentFiles = ({ order }) => {
if (isImageFile(file)) {
// Save image to the Photos Gallery using CameraRoll
await CameraRoll.save(localFile, { type: 'photo' });
- Alert.alert('Download Complete', 'Image saved to your Photos Gallery.');
+ Alert.alert(t('common.done'), t('OrderDocumentFiles.imageSavedToYourPhotosGallery'));
} else {
// For non-image files, open the share dialog so the user can choose what to do
await Share.open({ url: 'file://' + localFile });
}
} else {
- Alert.alert('Download Failed', `Status Code: ${downloadResult.statusCode}`);
+ Alert.alert(t('OrderDocumentFiles.downloadFailed'), `Status Code: ${downloadResult.statusCode}`);
}
} catch (error) {
console.warn('Error downloading file:', error);
- Alert.alert('Error', 'There was an error downloading the file.');
+ Alert.alert(t('common.error'), t('OrderDocumentFiles.thereWasAnErrorDownloadingTheFile'));
}
};
@@ -71,7 +73,7 @@ const OrderDocumentFiles = ({ order }) => {
if (files.length === 0) {
return (
- No Documents or Files.
+ {t('OrderDocumentFiles.noDocumentsOrFiles')}
);
}
@@ -106,13 +108,13 @@ const OrderDocumentFiles = ({ order }) => {
- View
+ {t('OrderDocumentFiles.view')}
downloadFile(file)} bg='$info' borderWidth={1} borderColor='$infoBorder' justifyContent='flex-start'>
- Download
+ {t('OrderDocumentFiles.download')}
@@ -124,4 +126,4 @@ const OrderDocumentFiles = ({ order }) => {
return ;
};
-export default OrderDocumentFiles;
+export default OrderDocumentFiles;
\ No newline at end of file
diff --git a/src/components/OrderPayloadEntities.tsx b/src/components/OrderPayloadEntities.tsx
index 5b17be3d..9df3080e 100644
--- a/src/components/OrderPayloadEntities.tsx
+++ b/src/components/OrderPayloadEntities.tsx
@@ -8,10 +8,12 @@ import FastImage from 'react-native-fast-image';
import { WaypointCircle } from './OrderWaypointList';
import OrderCustomerCard from './OrderCustomerCard';
import { formatCurrency } from '../utils/format';
+import { useLanguage } from '../contexts/LanguageContext';
const ENTITY_COLUMN_WIDTH = 100;
const OrderPayloadEntities = ({ order, onPress }) => {
const theme = useTheme();
+ const { t } = useLanguage();
const waypoints = order.getAttribute('payload.waypoints', []) ?? [];
const entities = order.getAttribute('payload.entities', []) ?? [];
const isMultiDropOrder = waypoints.length > 0;
@@ -48,7 +50,7 @@ const OrderPayloadEntities = ({ order, onPress }) => {
if (entities.length === 0 && entitiesByDestination.length === 0) {
return (
- Empty Payload.
+ {t('OrderPayloadEntities.emptyPayload')}
);
}
@@ -127,4 +129,4 @@ const OrderPayloadEntities = ({ order, onPress }) => {
return } />;
};
-export default OrderPayloadEntities;
+export default OrderPayloadEntities;
\ No newline at end of file
diff --git a/src/components/OrderProofOfDelivery.tsx b/src/components/OrderProofOfDelivery.tsx
index 57a7d5d0..b2503286 100644
--- a/src/components/OrderProofOfDelivery.tsx
+++ b/src/components/OrderProofOfDelivery.tsx
@@ -10,6 +10,7 @@ import { format } from 'date-fns';
import FastImage from 'react-native-fast-image';
import useStorage from '../hooks/use-storage';
import useFleetbase from '../hooks/use-fleetbase';
+import { useLanguage } from '../contexts/LanguageContext';
const PROOF_COLUMN_WIDTH = 160;
@@ -21,6 +22,7 @@ const OrderProofOfDelivery = ({ order, subject }) => {
const [proofs, setProofs] = useStorage(`${id}_proofs`, []);
const [isLoading, setIsLoading] = useState(false);
const [fullscreenImage, setFullscreenImage] = useState(null);
+ const { t } = useLanguage();
const loadOrderProof = useCallback(async () => {
if (!adapter) return;
@@ -107,7 +109,7 @@ const OrderProofOfDelivery = ({ order, subject }) => {
if (proofs.length === 0) {
return (
- No Proof of Delivery Captured.
+ {t('OrderProofOfDelivery.noProofOfDeliveryCaptured')}
);
}
@@ -147,4 +149,4 @@ const OrderProofOfDelivery = ({ order, subject }) => {
);
};
-export default OrderProofOfDelivery;
+export default OrderProofOfDelivery;
\ No newline at end of file
diff --git a/src/components/PastOrderCard.tsx b/src/components/PastOrderCard.tsx
index 13f2a493..2cb15ed0 100644
--- a/src/components/PastOrderCard.tsx
+++ b/src/components/PastOrderCard.tsx
@@ -15,12 +15,14 @@ import OrderWaypointList, { WaypointItem } from './OrderWaypointList';
import MultipleCustomerAvatars from './MultipleCustomerAvatars';
import LoadingText from './LoadingText';
import Badge from './Badge';
+import { useLanguage } from '../contexts/LanguageContext';
const INFO_FIELD_VALUE_MIN_HEIGHT = 30;
export const PastOrderCard = ({ order, onPress }) => {
const theme = useTheme();
const { isDarkMode } = useAppTheme();
const { trackerData } = useOrderResource(order, { loadEta: false });
+ const { t } = useLanguage();
const destination = useMemo(() => {
const pickup = order.getAttribute('payload.pickup');
@@ -85,7 +87,7 @@ export const PastOrderCard = ({ order, onPress }) => {
icon={faLocationDot}
iconColor={theme['$textPrimary'].val}
waypoint={destination.serialize()}
- title='Current Destination'
+ title={t('PastOrderCard.currentDestination')}
titleStyle={{ fontWeight: 'bold', fontSize: 14, textTransform: 'uppercase' }}
/>
@@ -95,4 +97,4 @@ export const PastOrderCard = ({ order, onPress }) => {
);
};
-export default PastOrderCard;
+export default PastOrderCard;
\ No newline at end of file
diff --git a/src/components/PhoneInput.tsx b/src/components/PhoneInput.tsx
index 90beba50..2e5151d5 100644
--- a/src/components/PhoneInput.tsx
+++ b/src/components/PhoneInput.tsx
@@ -6,6 +6,7 @@ import { useTheme, View, Text, Button, XStack, YStack, Input } from 'tamagui';
import { Portal } from '@gorhom/portal';
import { getCountryByPhoneCode, getCountryByISO2, parsePhoneNumber, debounce } from '../utils';
import useAppTheme from '../hooks/use-app-theme';
+import { useLanguage } from '../contexts/LanguageContext';
function getDefaultValues(value = null, fallbackCountry = 'US') {
if (typeof value === 'string' && value.startsWith('+')) {
@@ -31,6 +32,7 @@ const countryList = Object.entries(countries).map(([code, details]) => ({
}));
const PhoneInput = ({ value, onChange, bg, width = '100%', defaultCountryCode = 'US', size = '$5', wrapperProps = {} }) => {
+ const { t } = useLanguage();
const defaultValue = getDefaultValues(value, defaultCountryCode);
const theme = useTheme();
const { isDarkMode } = useAppTheme();
@@ -91,7 +93,7 @@ const PhoneInput = ({ value, onChange, bg, width = '100%', defaultCountryCode =
size={size}
ref={phoneInputRef}
flex={1}
- placeholder='Enter phone number'
+ placeholder={t('PhoneInput.enterPhoneNumber')}
keyboardType='phone-pad'
value={phoneNumber}
onChangeText={setPhoneNumber}
@@ -123,7 +125,7 @@ const PhoneInput = ({ value, onChange, bg, width = '100%', defaultCountryCode =
void;
@@ -11,6 +12,7 @@ type QrCodeScannerProps = {
};
export const QrCodeScanner: React.FC = ({ onScan, width = '100%', height = '100%', overlayStyle = {}, scanCooldown = 3000 }) => {
+ const { t } = useLanguage();
const device = useCameraDevice('back');
const [isScanning, setIsScanning] = useState(true);
const cooldownRef = useRef(null);
@@ -51,7 +53,7 @@ export const QrCodeScanner: React.FC = ({ onScan, width = '1
if (!device) {
return (
- No camera available
+ {t('QrCodeScanner.noCameraAvailable')}
);
}
@@ -87,4 +89,4 @@ const styles = StyleSheet.create({
},
});
-export default QrCodeScanner;
+export default QrCodeScanner;
\ No newline at end of file
diff --git a/src/components/UnitInput.tsx b/src/components/UnitInput.tsx
index fd93b42d..d0c0e366 100644
--- a/src/components/UnitInput.tsx
+++ b/src/components/UnitInput.tsx
@@ -8,6 +8,7 @@ import { faPenToSquare } from '@fortawesome/free-solid-svg-icons';
import { Portal } from '@gorhom/portal';
import { debounce } from '../utils';
import unit from '../constants/Units';
+import { useLanguage } from '../contexts/LanguageContext';
const getDefaultUnit = (type, defaultValue) => {
if (typeof type === 'string' && type.startsWith('volume')) {
@@ -38,6 +39,7 @@ const UnitInput = ({
onBottomSheetClosed,
}) => {
const theme = useTheme();
+ const { t } = useLanguage();
const [selectedUnit, setSelectedUnit] = useState(getDefaultUnit(type, defaultUnit));
const [value, setValue] = useState(_value);
const [searchTerm, setSearchTerm] = useState('');
@@ -141,7 +143,7 @@ const UnitInput = ({
(
- Navigator
+ {(() => {
+ const { t } = useLanguage();
+ return t('DriverNavigator.navigator');
+ })()}
),
headerRight: (props) => ,
@@ -301,12 +305,13 @@ const DriverReportTab = createNativeStackNavigator({
CreateFuelReport: {
screen: CreateFuelReportScreen,
options: ({ route, navigation }) => {
+ const { t } = useLanguage();
return {
presentation: 'modal',
headerTitle: '',
headerLeft: (props) => (
- Create a new Fuel Report
+ {t('DriverNavigator.createANewFuelReport')}
),
headerRight: (props) => navigation.goBack()} />,
@@ -322,13 +327,14 @@ const DriverReportTab = createNativeStackNavigator({
options: ({ route, navigation }) => {
const params = route.params || {};
const fuelReport = params.fuelReport;
+ const { t } = useLanguage();
return {
presentation: 'modal',
headerTitle: '',
headerLeft: (props) => (
- Edit Fuel Report from {format(new Date(fuelReport.created_at), 'MMM dd, yyyy HH:mm')}
+ {t('common.edit')} Fuel Report from {format(new Date(fuelReport.created_at), 'MMM dd, yyyy HH:mm')}
),
headerRight: (props) => navigation.goBack()} />,
@@ -365,12 +371,13 @@ const DriverReportTab = createNativeStackNavigator({
CreateIssue: {
screen: CreateIssueScreen,
options: ({ route, navigation }) => {
+ const { t } = useLanguage();
return {
presentation: 'modal',
headerTitle: '',
headerLeft: (props) => (
- Create a new Issue
+ {t('DriverNavigator.createANewIssue')}
),
headerRight: (props) => navigation.goBack()} />,
@@ -386,13 +393,14 @@ const DriverReportTab = createNativeStackNavigator({
options: ({ route, navigation }) => {
const params = route.params || {};
const issue = params.issue;
+ const { t } = useLanguage();
return {
presentation: 'modal',
headerTitle: '',
headerLeft: (props) => (
- Edit Issue from {format(new Date(issue.created_at), 'MMM dd, yyyy HH:mm')}
+ {t('common.edit')} Issue from {format(new Date(issue.created_at), 'MMM dd, yyyy HH:mm')}
),
headerRight: (props) => navigation.goBack()} />,
@@ -506,19 +514,22 @@ const DriverNavigator = createBottomTabNavigator({
return {
headerTitle: '',
- headerLeft: (props) => (
-
-
-
-
- Navigator
+ headerLeft: (props) => {
+ const { t } = useLanguage();
+ return (
+
+
+
+
+ {t('DriverNavigator.navigator')}
+
+
+
+ v{DeviceInfo.getVersion()} #{DeviceInfo.getBuildNumber()}
-
-
- v{DeviceInfo.getVersion()} #{DeviceInfo.getBuildNumber()}
-
-
- ),
+
+ );
+ },
headerRight: (props) => (
@@ -582,4 +593,4 @@ const DriverNavigator = createBottomTabNavigator({
screens: createTabScreens(),
});
-export default DriverNavigator;
+export default DriverNavigator;
\ No newline at end of file
diff --git a/src/navigation/stacks/CoreStack.tsx b/src/navigation/stacks/CoreStack.tsx
index 273d9282..658512f1 100644
--- a/src/navigation/stacks/CoreStack.tsx
+++ b/src/navigation/stacks/CoreStack.tsx
@@ -7,6 +7,7 @@ import { Text } from 'tamagui';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
import { faTimes } from '@fortawesome/free-solid-svg-icons';
import HeaderButton from '../../components/HeaderButton';
+import { useLanguage } from '../../contexts/LanguageContext';
export const Boot = {
screen: BootScreen,
@@ -29,12 +30,13 @@ export const LocationPermission = {
export const InstanceLink = {
screen: InstanceLinkScreen,
options: ({ navigation }) => {
+ const { t } = useLanguage();
return {
headerTitle: '',
presentation: 'modal',
headerLeft: (props) => (
- Connection Config
+ {t('CoreStack.connectionConfig')}
),
headerRight: (props) => navigation.goBack()} />,
@@ -57,4 +59,4 @@ const CoreStack = {
InstanceLink,
};
-export default CoreStack;
+export default CoreStack;
\ No newline at end of file
diff --git a/src/screens/ChatHomeScreen.tsx b/src/screens/ChatHomeScreen.tsx
index d3917a34..f7bb9636 100644
--- a/src/screens/ChatHomeScreen.tsx
+++ b/src/screens/ChatHomeScreen.tsx
@@ -10,6 +10,7 @@ import { useChat } from '../contexts/ChatContext';
import { useAuth } from '../contexts/AuthContext';
import useSocketClusterClient from '../hooks/use-socket-cluster-client';
import ChatParticipantAvatar from '../components/ChatParticipantAvatar';
+import { useLanguage } from '../contexts/LanguageContext';
const ChatHomeScreen = () => {
const theme = useTheme();
@@ -19,6 +20,7 @@ const ChatHomeScreen = () => {
const { listen } = useSocketClusterClient();
const listenerRef = useRef({});
const loadedRef = useRef(false);
+ const { t } = useLanguage();
const handleOpenChannel = (channel) => {
setCurrentChannel(channel);
@@ -29,7 +31,7 @@ const ChatHomeScreen = () => {
const lastParticipant = last(channel.participants);
const otherParticipant = channel.participants.find((participant) => participant.user !== driver.getAttribute('user')) ?? lastParticipant;
const lastMessageReceived = channel.last_message ? channel.last_message.created_at : channel.created_at;
- let lastMessageContent = 'No messages';
+ let lastMessageContent = t('ChatHomeScreen.noMessages') || 'No messages';
if (channel.last_message?.content) {
if (channel.participants.length > 2) {
@@ -152,7 +154,7 @@ const ChatHomeScreen = () => {
- Chats
+ {t('ChatHomeScreen.chats')}
@@ -176,4 +178,4 @@ const ChatHomeScreen = () => {
);
};
-export default ChatHomeScreen;
+export default ChatHomeScreen;
\ No newline at end of file
diff --git a/src/screens/ChatParticipantsScreen.tsx b/src/screens/ChatParticipantsScreen.tsx
index 88f90388..1259b683 100644
--- a/src/screens/ChatParticipantsScreen.tsx
+++ b/src/screens/ChatParticipantsScreen.tsx
@@ -12,10 +12,12 @@ import { useAuth } from '../contexts/AuthContext';
import useSocketClusterClient from '../hooks/use-socket-cluster-client';
import ChatParticipantAvatar from '../components/ChatParticipantAvatar';
import BottomSheetSelect from '../components/BottomSheetSelect';
+import { useLanguage } from '../contexts/LanguageContext';
const ChatParticipantsScreen = ({ route }) => {
const theme = useTheme();
const navigation = useNavigation();
+ const { t } = useLanguage();
const { sendMessage, reloadChannel, removeParticipant, addParticipant, getAvailableParticipants, getChannelCurrentParticipant } = useChat();
const { listen } = useSocketClusterClient();
const [channel, setChannel] = useState(route.params.channel);
@@ -54,15 +56,15 @@ const ChatParticipantsScreen = ({ route }) => {
const handleRemoveParticipant = useCallback(
(participant) => {
Alert.alert(
- 'Confirmation',
- 'Are you sure you wish to remove this participant from the chat?',
+ t('common.confirmation'),
+ t('ChatParticipantsScreen.areYouSureYouWishToRemoveThisParticipantFromTheChat'),
[
{
- text: 'Cancel',
+ text: t('common.cancel'),
style: 'cancel',
},
{
- text: 'Remove Participant',
+ text: t('ChatParticipantsScreen.remove'),
onPress: async () => {
synchronouslyRemoveParticipant(participant);
await removeParticipant(channel, participant);
@@ -127,7 +129,7 @@ const ChatParticipantsScreen = ({ route }) => {
- Remove
+ {t('common.remove')}
)}
@@ -151,7 +153,7 @@ const ChatParticipantsScreen = ({ route }) => {
- Participants
+ {t('ChatParticipantsScreen.participants')}
@@ -160,7 +162,7 @@ const ChatParticipantsScreen = ({ route }) => {
- Add Participant
+ {t('ChatParticipantsScreen.addParticipant')}
@@ -201,7 +203,7 @@ const ChatParticipantsScreen = ({ route }) => {
);
}}
- title='Select Participant'
+ title={t('ChatParticipantsScreen.selectParticipant')}
virtual={true}
renderInPlace={false}
portalHost='ChatParticipantsPortal'
@@ -211,4 +213,4 @@ const ChatParticipantsScreen = ({ route }) => {
);
};
-export default ChatParticipantsScreen;
+export default ChatParticipantsScreen;
\ No newline at end of file
diff --git a/src/screens/CreateAccountScreen.tsx b/src/screens/CreateAccountScreen.tsx
index 753b4b1c..fc9ab8c5 100644
--- a/src/screens/CreateAccountScreen.tsx
+++ b/src/screens/CreateAccountScreen.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useState } from 'react';
import { useNavigation } from '@react-navigation/native';
-import { SafeAreaView, Pressable, Keyboard, StyleSheet } from 'react-native';
+import { SafeAreaView, Pressable, Keyboard, StyleSheet, Alert } from 'react-native';
import { Spinner, XStack, Text, YStack, useTheme, Button } from 'tamagui';
import { toast, ToastPosition } from '@backpackapp-io/react-native-toast';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
@@ -11,8 +11,10 @@ import PhoneInput from '../components/PhoneInput';
import BackButton from '../components/BackButton';
import Input from '../components/Input';
import LinearGradient from 'react-native-linear-gradient';
+import { useLanguage } from '../contexts/LanguageContext';
const CreateAccountScreen = ({ route }) => {
+ const { t } = useLanguage();
const params = route.params || {};
const navigation = useNavigation();
const theme = useTheme();
@@ -26,7 +28,7 @@ const CreateAccountScreen = ({ route }) => {
}
if (!isValidPhoneNumber(phone)) {
- return toast.error('Invalid phone number provided.');
+ return toast.error(t('CreateAccountScreen.invalidPhoneNumberProvided'));
}
try {
@@ -49,17 +51,17 @@ const CreateAccountScreen = ({ route }) => {
- Create Account
+ {t('CreateAccountScreen.createAccount')}
- setName(text)} placeholder='Enter your name' />
+ setName(text)} placeholder={t('CreateAccountScreen.enterYourName')} />
setPhone(phoneNumber)} />
{isSendingCode ? : }
- Send Verification Code
+ {t('CreateAccountScreen.sendVerificationCode')}
@@ -71,7 +73,7 @@ const CreateAccountScreen = ({ route }) => {
- Have an account already? Login
+ {t('CreateAccountScreen.haveAnAccountAlreadyLogin')}
@@ -80,4 +82,4 @@ const CreateAccountScreen = ({ route }) => {
);
};
-export default CreateAccountScreen;
+export default CreateAccountScreen;
\ No newline at end of file
diff --git a/src/screens/CreateAccountVerifyScreen.tsx b/src/screens/CreateAccountVerifyScreen.tsx
index 8d414a5c..dcb6e629 100644
--- a/src/screens/CreateAccountVerifyScreen.tsx
+++ b/src/screens/CreateAccountVerifyScreen.tsx
@@ -8,6 +8,7 @@ import { faCheck, faArrowRotateRight } from '@fortawesome/free-solid-svg-icons';
import { OtpInput } from 'react-native-otp-entry';
import { useAuth } from '../contexts/AuthContext';
import LinearGradient from 'react-native-linear-gradient';
+import { useLanguage } from '../contexts/LanguageContext';
const CreateAccountVerifyScreen = ({ route }) => {
const navigation = useNavigation();
@@ -15,6 +16,7 @@ const CreateAccountVerifyScreen = ({ route }) => {
const { phone, verifyAccountCreation, isVerifyingCode } = useAuth();
const [code, setCode] = useState(null);
const name = route.params.name;
+ const { t } = useLanguage();
const handleVerifyCode = async (code) => {
if (isVerifyingCode) {
@@ -25,7 +27,7 @@ const CreateAccountVerifyScreen = ({ route }) => {
await verifyAccountCreation(phone, code, { name, phone });
} catch (error) {
console.warn('Error verifying account creation code:', error);
- toast.error(error.message);
+ toast.error(t('common.error'));
}
};
@@ -40,7 +42,7 @@ const CreateAccountVerifyScreen = ({ route }) => {
- Code sent to {phone}
+ {t('CreateAccountVerifyScreen.verifyCode')} sent to {phone}
{
handleVerifyCode(code)} bg='$primary' width='100%' opacity={isVerifyingCode ? 0.75 : 1} disabled={isVerifyingCode} rounded>
{isVerifyingCode ? : }
- Verify Code
+ {t('CreateAccountVerifyScreen.verifyCode')}
@@ -61,7 +63,7 @@ const CreateAccountVerifyScreen = ({ route }) => {
- Retry
+ {t('common.retry')}
@@ -69,4 +71,4 @@ const CreateAccountVerifyScreen = ({ route }) => {
);
};
-export default CreateAccountVerifyScreen;
+export default CreateAccountVerifyScreen;
\ No newline at end of file
diff --git a/src/screens/CreateChatChannelScreen.tsx b/src/screens/CreateChatChannelScreen.tsx
index 7b96f41c..aa112778 100644
--- a/src/screens/CreateChatChannelScreen.tsx
+++ b/src/screens/CreateChatChannelScreen.tsx
@@ -13,6 +13,7 @@ import { useAuth } from '../contexts/AuthContext';
import useSocketClusterClient from '../hooks/use-socket-cluster-client';
import ChatParticipantAvatar from '../components/ChatParticipantAvatar';
import Spacer from '../components/Spacer';
+import { useLanguage } from '../contexts/LanguageContext';
const CreateChatChannelScreen = ({ route }) => {
const theme = useTheme();
@@ -25,6 +26,7 @@ const CreateChatChannelScreen = ({ route }) => {
const [channelName, setChannelName] = useState('');
const [isLoading, setIsLoading] = useState('');
const availableParticipantsLoadedRef = useRef(false);
+ const { t } = useLanguage();
const handleSelectParticipant = (participant) => {
setSelectedParticipants((prevSelected) => [...prevSelected, participant.id]);
@@ -36,21 +38,21 @@ const CreateChatChannelScreen = ({ route }) => {
const handleCreateChat = useCallback(async () => {
if (!channelName.trim()) {
- return Alert.alert('Chat channel name is required.');
+ return Alert.alert(t('common.error'), t('CreateChatChannelScreen.chatChannelNameIsRequired'));
}
setIsLoading(true);
try {
await createChannel({ name: channelName, participants: [driver.getAttribute('user'), ...selectedParticipants] });
- toast.success(`New chat channel created: ${channelName}`);
+ toast.success(t('CreateChatChannelScreen.createNewChat'));
navigation.goBack();
} catch (err) {
console.warn('Error creating new chat channel:', err);
} finally {
setIsLoading(false);
}
- }, [channelName, createChannel, navigation]);
+ }, [channelName, createChannel, navigation, driver, selectedParticipants, t]);
const isSelected = useCallback(
(participant) => {
@@ -73,7 +75,7 @@ const CreateChatChannelScreen = ({ route }) => {
loadAvailableParticipants();
availableParticipantsLoadedRef.current = true;
}
- }, []);
+ }, [getAvailableParticipants]);
const renderParticipant = ({ item: participant }) => {
return (
@@ -95,14 +97,14 @@ const CreateChatChannelScreen = ({ route }) => {
- Unselect
+ {t('CreateChatChannelScreen.unselect')}
) : (
handleSelectParticipant(participant)}>
- Select
+ {t('common.select')}
)}
@@ -126,7 +128,7 @@ const CreateChatChannelScreen = ({ route }) => {
- Create new Chat
+ {t('CreateChatChannelScreen.createNewChat')}
@@ -134,12 +136,12 @@ const CreateChatChannelScreen = ({ route }) => {
- Channel Name
+ {t('CreateChatChannelScreen.channelName')}
{
- Select Participants:
+ {t('CreateChatChannelScreen.selectParticipants')}
@@ -169,7 +171,7 @@ const CreateChatChannelScreen = ({ route }) => {
{isLoading ? : }
- Create new Chat
+ {t('CreateChatChannelScreen.createNewChat')}
@@ -178,4 +180,4 @@ const CreateChatChannelScreen = ({ route }) => {
);
};
-export default CreateChatChannelScreen;
+export default CreateChatChannelScreen;
\ No newline at end of file
diff --git a/src/screens/DriverDashboardScreen.tsx b/src/screens/DriverDashboardScreen.tsx
index 2b898d6d..e1adf327 100644
--- a/src/screens/DriverDashboardScreen.tsx
+++ b/src/screens/DriverDashboardScreen.tsx
@@ -6,6 +6,7 @@ import { humanize } from 'inflected';
import { get } from '../utils';
import OdometerNumber from '../components/OdometerNumber';
import useAppTheme from '../hooks/use-app-theme';
+import { useLanguage } from '../contexts/LanguageContext';
const WidgetContainer = ({ px = '$4', py = '$4', children, ...props }) => {
const { isDarkMode } = useAppTheme();
@@ -21,6 +22,7 @@ const DriverDashboardScreen = () => {
const navigation = useNavigation();
const { isTracking, location } = useLocation();
const { allActiveOrders } = useOrderManager();
+ const { t } = useLanguage();
return (
@@ -29,7 +31,7 @@ const DriverDashboardScreen = () => {
- Tracking:
+ {t('DriverDashboardScreen.tracking')}
{isTracking ? 'Yes' : 'No'}
@@ -38,7 +40,7 @@ const DriverDashboardScreen = () => {
- Location:
+ {t('DriverDashboardScreen.location')}
{['latitude', 'longitude', 'heading', 'altitude'].map((key, index) => {
@@ -58,7 +60,7 @@ const DriverDashboardScreen = () => {
- Active Orders
+ {t('DriverDashboardScreen.activeOrders')}
@@ -68,7 +70,7 @@ const DriverDashboardScreen = () => {
- Speed
+ {t('DriverDashboardScreen.speed')}
@@ -81,4 +83,4 @@ const DriverDashboardScreen = () => {
);
};
-export default DriverDashboardScreen;
+export default DriverDashboardScreen;
\ No newline at end of file
diff --git a/src/screens/DriverFleetScreen.tsx b/src/screens/DriverFleetScreen.tsx
index 7fdab489..b5b3323f 100644
--- a/src/screens/DriverFleetScreen.tsx
+++ b/src/screens/DriverFleetScreen.tsx
@@ -1,17 +1,19 @@
import { useNavigation } from '@react-navigation/native';
import { Text, YStack, useTheme } from 'tamagui';
+import { useLanguage } from '../contexts/LanguageContext';
const DriverFleetScreen = () => {
const theme = useTheme();
const navigation = useNavigation();
+ const { t } = useLanguage();
return (
- DriverFleetScreen
+ {t('DriverFleetScreen.driverfleetscreen')}
);
};
-export default DriverFleetScreen;
+export default DriverFleetScreen;
\ No newline at end of file
diff --git a/src/screens/DriverReportScreen.tsx b/src/screens/DriverReportScreen.tsx
index 381a0620..b025d423 100644
--- a/src/screens/DriverReportScreen.tsx
+++ b/src/screens/DriverReportScreen.tsx
@@ -15,6 +15,7 @@ import Badge from '../components/Badge';
import Spacer from '../components/Spacer';
import useStorage from '../hooks/use-storage';
import useFleetbase from '../hooks/use-fleetbase';
+import { useLanguage } from '../contexts/LanguageContext';
const DriverReportScreen = () => {
const theme = useTheme();
@@ -26,9 +27,10 @@ const DriverReportScreen = () => {
const [fuelReports, setFuelReports] = useStorage(`${driver?.id}_fuel_reports`, []);
const [currentTab, setCurrentTab] = useStorage('current_reports_tab', 'issue');
const [isRefreshing, setIsRefreshing] = useState(false);
+ const { t } = useLanguage();
const reportOptions = [
- { value: 'issue', label: 'Issues' },
- { value: 'fuel-report', label: 'Fuel Reports' },
+ { value: 'issue', label: t('DriverReportScreen.issueOn') === 'Issue on:' ? 'Issues' : t('DriverReportScreen.issueOn') },
+ { value: 'fuel-report', label: t('DriverReportScreen.fuelReported') === 'Fuel Reported:' ? 'Fuel Reports' : t('DriverReportScreen.fuelReported') },
];
const currentIndex = reportOptions.findIndex((option) => option.value === currentTab);
const content = useMemo(() => (currentTab === 'issue' ? issues : fuelReports), [currentTab, issues, fuelReports]);
@@ -98,7 +100,7 @@ const DriverReportScreen = () => {
- Issue on:
+ {t('DriverReportScreen.issueOn')}
{format(new Date(issue.created_at), 'MMM dd, yyyy HH:mm')}
@@ -107,16 +109,16 @@ const DriverReportScreen = () => {
- Status:
+ {t('DriverReportScreen.status')}
- Priority:
+ {t('DriverReportScreen.priority')}
- Report:
+ {t('DriverReportScreen.report')}
{issue.report}
@@ -126,22 +128,22 @@ const DriverReportScreen = () => {
- Type:
+ {t('DriverReportScreen.type')}
{titleize(issue.type) ?? 'N/A'}
- Category:
+ {t('DriverReportScreen.category')}
{titleize(issue.category) ?? 'N/A'}
- Vehicle:
+ {t('DriverReportScreen.vehicle')}
{issue.vehicle_name ?? 'N/A'}
- Reporter:
+ {t('DriverReportScreen.reporter')}
{issue.reporter_name ?? 'N/A'}
@@ -171,7 +173,7 @@ const DriverReportScreen = () => {
>
- Fuel Reported:
+ {t('DriverReportScreen.fuelReported')}
{format(new Date(fuelReport.created_at), 'MMM dd, yyyy HH:mm')}
@@ -181,7 +183,7 @@ const DriverReportScreen = () => {
- Status:
+ {t('DriverReportScreen.status')}
@@ -200,17 +202,17 @@ const DriverReportScreen = () => {
- Odometer:
+ {t('DriverReportScreen.odometer')}
{fuelReport.odometer ?? 'N/A'}
- Volume:
+ {t('DriverReportScreen.volume')}
{`${fuelReport.volume} ${fuelReport.metric_unit}` ?? 'N/A'}
- Cost:
+ {t('DriverReportScreen.cost')}
{formatCurrency(fuelReport.amount, fuelReport.currency) ?? 'N/A'}
@@ -247,7 +249,7 @@ const DriverReportScreen = () => {
ListEmptyComponent={
- No {reportOptions[currentIndex].label}
+ {t('common.select')} {reportOptions[currentIndex].label}
}
@@ -261,7 +263,7 @@ const DriverReportScreen = () => {
- Create a new {singularize(reportOptions[currentIndex].label)}
+ {t('common.edit')} a new {singularize(reportOptions[currentIndex].label)}
@@ -270,4 +272,4 @@ const DriverReportScreen = () => {
);
};
-export default DriverReportScreen;
+export default DriverReportScreen;
\ No newline at end of file
diff --git a/src/screens/EditAccountPropertyScreen.tsx b/src/screens/EditAccountPropertyScreen.tsx
index 1131dc14..05c184b3 100644
--- a/src/screens/EditAccountPropertyScreen.tsx
+++ b/src/screens/EditAccountPropertyScreen.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useState, useCallback } from 'react';
import { useNavigation } from '@react-navigation/native';
-import { SafeAreaView, Pressable, Keyboard, StyleSheet } from 'react-native';
+import { SafeAreaView, Pressable, Keyboard, StyleSheet, Alert } from 'react-native';
import { Spinner, Text, YStack, XStack, Button, useTheme } from 'tamagui';
import { toast, ToastPosition } from '@backpackapp-io/react-native-toast';
import { useAuth } from '../contexts/AuthContext';
@@ -8,20 +8,23 @@ import { usePromiseWithLoading } from '../hooks/use-promise-with-loading';
import BackButton from '../components/BackButton';
import PhoneInput from '../components/PhoneInput';
import Input from '../components/Input';
+import { useLanguage } from '../contexts/LanguageContext';
const RenderAccountProperty = ({ property, value, onChange }) => {
+ const { t } = useLanguage();
return (
{property.component === 'phone-input' ? (
) : (
-
+
)}
);
};
const EditAccountPropertyScreen = ({ route }) => {
+ const { t } = useLanguage();
const property = route.params.property;
const theme = useTheme();
const navigation = useNavigation();
@@ -34,12 +37,12 @@ const EditAccountPropertyScreen = ({ route }) => {
try {
const updatedCustomer = await runWithLoading(customer.update({ [property.key]: value }));
setCustomer(updatedCustomer);
- toast.success(`${property.name} changes saved.`);
+ toast.success(t('EditAccountPropertyScreen.' + property.name) + ' changes saved.');
navigation.goBack();
} catch (error) {
toast.error(error.message);
}
- }, [customer, runWithLoading]);
+ }, [customer, runWithLoading, setCustomer, value, property.name]);
return (
@@ -47,7 +50,7 @@ const EditAccountPropertyScreen = ({ route }) => {
- {property.name}
+ {t('EditAccountPropertyScreen.' + property.name)}
@@ -60,7 +63,7 @@ const EditAccountPropertyScreen = ({ route }) => {
{isLoading() && }
- Save
+ {t('common.save')}
@@ -69,4 +72,4 @@ const EditAccountPropertyScreen = ({ route }) => {
);
};
-export default EditAccountPropertyScreen;
+export default EditAccountPropertyScreen;
\ No newline at end of file
diff --git a/src/screens/EditLocationCoordScreen.tsx b/src/screens/EditLocationCoordScreen.tsx
index b23c7258..39316e5d 100644
--- a/src/screens/EditLocationCoordScreen.tsx
+++ b/src/screens/EditLocationCoordScreen.tsx
@@ -9,6 +9,7 @@ import LocationMarker from '../components/LocationMarker';
import useSavedLocations from '../hooks/use-saved-locations';
import usePromiseWithLoading from '../hooks/use-promise-with-loading';
import useFleetbase from '../hooks/use-fleetbase';
+import { useLanguage } from '../contexts/LanguageContext';
const LOCATION_MARKER_SIZE = { height: 70, width: 40 };
const styles = StyleSheet.create({
@@ -22,6 +23,7 @@ const styles = StyleSheet.create({
});
const EditLocationCoordScreen = ({ route }) => {
+ const { t } = useLanguage();
const params = route.params || {};
const navigation = useNavigation();
const theme = useTheme();
@@ -138,12 +140,12 @@ const EditLocationCoordScreen = ({ route }) => {
{isLoading() && }
- Save Position
+ {t('EditLocationCoordScreen.savePosition')}
- Reset
+ {t('common.reset')}
@@ -151,4 +153,4 @@ const EditLocationCoordScreen = ({ route }) => {
);
};
-export default EditLocationCoordScreen;
+export default EditLocationCoordScreen;
\ No newline at end of file
diff --git a/src/screens/EditLocationScreen.tsx b/src/screens/EditLocationScreen.tsx
index c8dad510..9e5d6100 100644
--- a/src/screens/EditLocationScreen.tsx
+++ b/src/screens/EditLocationScreen.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useState, useMemo } from 'react';
import { useNavigation } from '@react-navigation/native';
-import { SafeAreaView, ScrollView } from 'react-native';
+import { SafeAreaView, ScrollView, Alert } from 'react-native';
import { Spinner, Text, YStack, XStack, Button, Input, useTheme } from 'tamagui';
import { toast, ToastPosition } from '@backpackapp-io/react-native-toast';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
@@ -16,14 +16,17 @@ import useFleetbase from '../hooks/use-fleetbase';
import { useAppTheme } from '../hooks/use-app-theme';
import ExpandableSelect from '../components/ExpandableSelect';
import PlaceMapView from '../components/PlaceMapView';
+import { useLanguage } from '../contexts/LanguageContext';
const LocationPropertyInput = ({ value, onChange, placeholder }) => {
+ const { t } = useLanguage();
+
return (
{
};
const EditLocationScreen = ({ route }) => {
+ const { t } = useLanguage();
const params = route.params || { redirectTo: 'AddressBook' };
const navigation = useNavigation();
const theme = useTheme();
@@ -120,7 +124,7 @@ const EditLocationScreen = ({ route }) => {
const handleSavePlace = async () => {
try {
await runWithLoading(addLocation(getUpdatedPlace(), makeDefault), 'saving');
- toast.success('Address saved.', { position: ToastPosition.bottom });
+ toast.success(t('EditLocationScreen.addressSaved'), { position: ToastPosition.bottom });
handleRedirect();
} catch (error) {
console.log('Error saving address details:', error);
@@ -133,7 +137,7 @@ const EditLocationScreen = ({ route }) => {
if (restoredInstance && restoredInstance.isSaved) {
try {
await runWithLoading(updateDefaultLocationPromise(restoredInstance), 'defaulting');
- toast.success(`${restoredInstance.getAttribute('name')} is now your default location.`, { position: ToastPosition.bottom });
+ toast.success(`${restoredInstance.getAttribute('name')} ${t('EditLocationScreen.makeDefaultAddress').toLowerCase()}.`, { position: ToastPosition.bottom });
handleRedirect();
} catch (error) {
console.log('Error making address default location:', error);
@@ -150,7 +154,7 @@ const EditLocationScreen = ({ route }) => {
if (restoredInstance && restoredInstance.isSaved) {
try {
await runWithLoading(deleteLocation(restoredInstance), 'deleting');
- toast.success(`${restoredInstance.getAttribute('name')} was deleted.`, { position: ToastPosition.bottom });
+ toast.success(`${restoredInstance.getAttribute('name')} ${t('common.delete').toLowerCase()}d.`, { position: ToastPosition.bottom });
// If the deleted place was the current location and there’s another saved location, make it the default
if (isCurrentLocation && nextPlace) {
@@ -173,18 +177,18 @@ const EditLocationScreen = ({ route }) => {
try {
setPlace({ ...place, type });
} catch (error) {
- toast.error('Unable to select location type.', { position: ToastPosition.bottom });
+ toast.error(t('EditLocationScreen.unableToSelectLocationType'), { position: ToastPosition.bottom });
}
};
const types = [
- { id: 1, title: 'Apartment', type: 'apartment', icon: },
- { id: 2, title: 'House', type: 'house', icon: },
- { id: 3, title: 'Office', type: 'office', icon: },
- { id: 4, title: 'Hotel', type: 'hotel', icon: },
- { id: 5, title: 'Hospital', type: 'hospital', icon: },
- { id: 6, title: 'School', type: 'school', icon: },
- { id: 7, title: 'Other', type: 'other', icon: },
+ { id: 1, title: t('EditLocationScreen.apartment') || 'Apartment', type: 'apartment', icon: },
+ { id: 2, title: t('EditLocationScreen.house') || 'House', type: 'house', icon: },
+ { id: 3, title: t('EditLocationScreen.office') || 'Office', type: 'office', icon: },
+ { id: 4, title: t('EditLocationScreen.hotel') || 'Hotel', type: 'hotel', icon: },
+ { id: 5, title: t('EditLocationScreen.hospital') || 'Hospital', type: 'hospital', icon: },
+ { id: 6, title: t('EditLocationScreen.school') || 'School', type: 'school', icon: },
+ { id: 7, title: t('EditLocationScreen.other') || 'Other', type: 'other', icon: },
];
return (
@@ -194,7 +198,7 @@ const EditLocationScreen = ({ route }) => {
- Address
+ {t('EditLocationScreen.address')}
@@ -206,7 +210,7 @@ const EditLocationScreen = ({ route }) => {
- Location Type
+ {t('EditLocationScreen.locationType')}
@@ -217,80 +221,80 @@ const EditLocationScreen = ({ route }) => {
- Address Details
+ {t('EditLocationScreen.addressDetails')}
- Add additional address details.
+ {t('EditLocationScreen.addAdditionalAddressDetails')}
- Address label or name
+ {t('EditLocationScreen.addressLabelOrName')}
-
+
- Street address or P.O. Box
+ {t('EditLocationScreen.streetAddressOrPOBox')}
-
+
- Apt, suite, unit, building, floor, etc.
+ {t('EditLocationScreen.aptSuiteUnitBuildingFloorEtc')}
-
+
- Optional
+ {t('EditLocationScreen.optional')}
- Neighborhood
+ {t('EditLocationScreen.neighborhood')}
-
+
- Optional
+ {t('EditLocationScreen.optional')}
- City or town
+ {t('EditLocationScreen.cityOrTown')}
-
+
- Optional
+ {t('EditLocationScreen.optional')}
- Postal or zip code
+ {t('EditLocationScreen.postalOrZipCode')}
-
+
- Optional
+ {t('EditLocationScreen.optional')}
- Additional instructions for the courier
+ {t('EditLocationScreen.additionalInstructionsForTheCourier')}
-
+
- Optional
+ {t('EditLocationScreen.optional')}
- Where exactly should we meet you?
+ {t('EditLocationScreen.whereExactlyShouldWeMeetYou')}
@@ -318,7 +322,7 @@ const EditLocationScreen = ({ route }) => {
>
{isLoading('defaulting') && }
- Make Default Address
+ {t('EditLocationScreen.makeDefaultAddress')}
)}
@@ -341,7 +345,7 @@ const EditLocationScreen = ({ route }) => {
>
{isLoading('deleting') && }
- Delete Address
+ {t('EditLocationScreen.deleteAddress')}
@@ -370,7 +374,7 @@ const EditLocationScreen = ({ route }) => {
>
{isLoading('saving') && }
- Save Address
+ {t('common.save')}
@@ -378,4 +382,4 @@ const EditLocationScreen = ({ route }) => {
);
};
-export default EditLocationScreen;
+export default EditLocationScreen;
\ No newline at end of file
diff --git a/src/screens/EntityScreen.tsx b/src/screens/EntityScreen.tsx
index a2ea6286..49cd575c 100644
--- a/src/screens/EntityScreen.tsx
+++ b/src/screens/EntityScreen.tsx
@@ -2,10 +2,12 @@ import { useNavigation } from '@react-navigation/native';
import { Image, Text, YStack, XStack, Separator, useTheme } from 'tamagui';
import { titleize } from 'inflected';
import { SectionHeader, SectionInfoLine } from '../components/Content';
+import { useLanguage } from '../contexts/LanguageContext';
const EntityScreen = ({ route }) => {
const theme = useTheme();
const navigation = useNavigation();
+ const { t } = useLanguage();
const params = route.params ?? {};
const entity = params.entity;
const waypoint = params.waypoint;
@@ -19,24 +21,24 @@ const EntityScreen = ({ route }) => {
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
);
};
-export default EntityScreen;
+export default EntityScreen;
\ No newline at end of file
diff --git a/src/screens/FleetScreen.tsx b/src/screens/FleetScreen.tsx
index bb2efc04..1b0ad9d7 100644
--- a/src/screens/FleetScreen.tsx
+++ b/src/screens/FleetScreen.tsx
@@ -1,17 +1,19 @@
import { useNavigation } from '@react-navigation/native';
import { Text, YStack, useTheme } from 'tamagui';
+import { useLanguage } from '../contexts/LanguageContext';
const FleetScreen = () => {
const theme = useTheme();
const navigation = useNavigation();
+ const { t } = useLanguage();
return (
- FleetScreen
+ {t('FleetScreen.fleetscreen')}
);
};
-export default FleetScreen;
+export default FleetScreen;
\ No newline at end of file
diff --git a/src/screens/FuelReportScreen.tsx b/src/screens/FuelReportScreen.tsx
index afde81f4..a0e72d51 100644
--- a/src/screens/FuelReportScreen.tsx
+++ b/src/screens/FuelReportScreen.tsx
@@ -16,6 +16,7 @@ import LoadingOverlay from '../components/LoadingOverlay';
import HeaderButton from '../components/HeaderButton';
import PlaceMapView from '../components/PlaceMapView';
import useFleetbase from '../hooks/use-fleetbase';
+import { useLanguage } from '../contexts/LanguageContext';
const FuelReportScreen = () => {
const theme = useTheme();
@@ -27,6 +28,7 @@ const FuelReportScreen = () => {
} = useTempStore();
const location = new Place({ id: fuelReport.id, location: fuelReport.location });
const [isLoading, setIsLoading] = useState(false);
+ const { t } = useLanguage();
const handleDeleteFuelReport = useCallback(() => {
const handleDelete = async () => {
@@ -42,11 +44,11 @@ const FuelReportScreen = () => {
}
};
- Alert.alert('Confirm Deletion', 'Are you sure you want to delete this Fuel Report?', [
- { text: 'Cancel', style: 'cancel' },
- { text: 'Delete Fuel Report', onPress: handleDelete },
+ Alert.alert(t('common.confirmDeletion'), t('FuelReportScreen.areYouSureYouWantToDeleteThisFuelReport'), [
+ { text: t('common.cancel'), style: 'cancel' },
+ { text: t('common.delete'), onPress: handleDelete },
]);
- }, [adapter]);
+ }, [adapter, fuelReport.id, navigation, t]);
return (
@@ -64,12 +66,12 @@ const FuelReportScreen = () => {
navigation.goBack()} />
-
+
- Odometer:
+ {t('FuelReportScreen.odometer')}
@@ -82,7 +84,7 @@ const FuelReportScreen = () => {
- Volume:
+ {t('FuelReportScreen.volume')}
@@ -95,7 +97,7 @@ const FuelReportScreen = () => {
- Vehicle:
+ {t('FuelReportScreen.vehicle')}
@@ -108,7 +110,7 @@ const FuelReportScreen = () => {
- Cost:
+ {t('FuelReportScreen.cost')}
@@ -121,7 +123,7 @@ const FuelReportScreen = () => {
- Status:
+ {t('FuelReportScreen.status')}
@@ -132,7 +134,7 @@ const FuelReportScreen = () => {
- Report Location:
+ {t('FuelReportScreen.reportLocation')}
@@ -144,4 +146,4 @@ const FuelReportScreen = () => {
);
};
-export default FuelReportScreen;
+export default FuelReportScreen;
\ No newline at end of file
diff --git a/src/screens/InstanceLinkScreen.tsx b/src/screens/InstanceLinkScreen.tsx
index b1f10abb..946a55a2 100644
--- a/src/screens/InstanceLinkScreen.tsx
+++ b/src/screens/InstanceLinkScreen.tsx
@@ -6,6 +6,7 @@ import { YStack, Text, Input, Switch, Button } from 'tamagui';
import { useConfig } from '../contexts/ConfigContext';
import { toBoolean } from '../utils';
import useAppTheme from '../hooks/use-app-theme';
+import { useLanguage } from '../contexts/LanguageContext';
const InstanceLinkScreen = () => {
const navigation = useNavigation();
@@ -17,6 +18,7 @@ const InstanceLinkScreen = () => {
const [socketClusterHost, setSocketClusterHost] = useState(instanceLinkConfig.SOCKETCLUSTER_HOST);
const [socketClusterPort, setSocketClusterPort] = useState(instanceLinkConfig.SOCKETCLUSTER_PORT);
const [socketClusterSecure, setSocketClusterSecure] = useState(toBoolean(instanceLinkConfig.SOCKETCLUSTER_SECURE));
+ const { t } = useLanguage();
const handleSave = useCallback(() => {
setInstanceLinkConfig('FLEETBASE_HOST', fleetbaseHost);
@@ -25,8 +27,8 @@ const InstanceLinkScreen = () => {
setInstanceLinkConfig('SOCKETCLUSTER_PORT', socketClusterPort);
setInstanceLinkConfig('SOCKETCLUSTER_SECURE', socketClusterSecure);
- Alert.alert('Instance connection config saved successfully.');
- }, [setInstanceLinkConfig, fleetbaseHost, fleetbaseKey, socketClusterHost, socketClusterPort, socketClusterSecure]);
+ Alert.alert(t('common.done'), t('InstanceLinkScreen.instanceConnectionConfigSavedSuccessfully'));
+ }, [setInstanceLinkConfig, fleetbaseHost, fleetbaseKey, socketClusterHost, socketClusterPort, socketClusterSecure, t]);
const handleReset = useCallback(() => {
clearInstanceLinkConfig();
@@ -35,8 +37,8 @@ const InstanceLinkScreen = () => {
setSocketClusterHost(null);
setSocketClusterPort(null);
setSocketClusterSecure(null);
- Alert.alert('Instance connection config reset successfully.');
- }, [clearInstanceLinkConfig, setFleetbaseHost, setFleetbaseKey, setSocketClusterHost, setSocketClusterPort, setSocketClusterSecure]);
+ Alert.alert(t('common.done'), t('InstanceLinkScreen.instanceConnectionConfigResetSuccessfully'));
+ }, [clearInstanceLinkConfig, setFleetbaseHost, setFleetbaseKey, setSocketClusterHost, setSocketClusterPort, setSocketClusterSecure, t]);
return (
@@ -44,12 +46,12 @@ const InstanceLinkScreen = () => {
- FLEETBASE HOST
+ {t('InstanceLinkScreen.fleetbaseHost')}
setFleetbaseHost(text)}
- placeholder='Input host of Fleetbase instance...'
+ placeholder={t('InstanceLinkScreen.inputHostOfFleetbaseInstance')}
borderWidth={1}
color='$textPrimary'
borderColor='$borderColor'
@@ -63,12 +65,12 @@ const InstanceLinkScreen = () => {
- FLEETBASE KEY
+ {t('InstanceLinkScreen.fleetbaseKey')}
setFleetbaseKey(text)}
- placeholder='Input API Key for Fleetbase instance...'
+ placeholder={t('InstanceLinkScreen.inputApiKeyForFleetbaseInstance')}
borderWidth={1}
color='$textPrimary'
borderColor='$borderColor'
@@ -82,12 +84,12 @@ const InstanceLinkScreen = () => {
- SOCKETCLUSTER HOST
+ {t('InstanceLinkScreen.socketclusterHost')}
setSocketClusterHost(text)}
- placeholder='Input SocketCluster host for Fleetbase instance...'
+ placeholder={t('InstanceLinkScreen.inputSocketclusterHostForFleetbaseInstance')}
borderWidth={1}
color='$textPrimary'
borderColor='$borderColor'
@@ -101,12 +103,12 @@ const InstanceLinkScreen = () => {
- SOCKETCLUSTER PORT
+ {t('InstanceLinkScreen.socketclusterPort')}
setSocketClusterPort(text)}
- placeholder='Input SocketCluster port for Fleetbase instance...'
+ placeholder={t('InstanceLinkScreen.inputSocketclusterPortForFleetbaseInstance')}
keyboardType='phone-pad'
borderWidth={1}
color='$textPrimary'
@@ -121,7 +123,7 @@ const InstanceLinkScreen = () => {
- SOCKETCLUSTER SECURE
+ {t('InstanceLinkScreen.socketclusterSecure')}
{
- Save Changes
+ {t('common.saveChanges') || t('InstanceLinkScreen.saveChanges') || t('common.save')}
- Reset
+ {t('common.reset') || t('InstanceLinkScreen.reset')}
@@ -155,4 +157,4 @@ const InstanceLinkScreen = () => {
);
};
-export default InstanceLinkScreen;
+export default InstanceLinkScreen;
\ No newline at end of file
diff --git a/src/screens/IssueScreen.tsx b/src/screens/IssueScreen.tsx
index 54a44523..df79a6a3 100644
--- a/src/screens/IssueScreen.tsx
+++ b/src/screens/IssueScreen.tsx
@@ -15,6 +15,7 @@ import LoadingOverlay from '../components/LoadingOverlay';
import HeaderButton from '../components/HeaderButton';
import PlaceMapView from '../components/PlaceMapView';
import useFleetbase from '../hooks/use-fleetbase';
+import { useLanguage } from '../contexts/LanguageContext';
const IssueScreen = () => {
const theme = useTheme();
@@ -26,6 +27,7 @@ const IssueScreen = () => {
} = useTempStore();
const location = new Place({ id: issue.id, location: issue.location });
const [isLoading, setIsLoading] = useState(false);
+ const { t } = useLanguage();
const handleDeleteIssue = useCallback(() => {
const handleDelete = async () => {
@@ -41,11 +43,11 @@ const IssueScreen = () => {
}
};
- Alert.alert('Confirm Deletion', 'Are you sure you want to delete this Issue?', [
- { text: 'Cancel', style: 'cancel' },
- { text: 'Delete Issue', onPress: handleDelete },
+ Alert.alert(t('common.confirmDeletion'), t('IssueScreen.areYouSureYouWantToDeleteThisIssue'), [
+ { text: t('common.cancel'), style: 'cancel' },
+ { text: t('common.delete'), onPress: handleDelete },
]);
- }, [adapter]);
+ }, [adapter, issue.id, navigation, t]);
return (
@@ -63,12 +65,12 @@ const IssueScreen = () => {
navigation.goBack()} />
-
+
- Type:
+ {t('IssueScreen.type')}
@@ -81,7 +83,7 @@ const IssueScreen = () => {
- Category:
+ {t('IssueScreen.category')}
@@ -94,7 +96,7 @@ const IssueScreen = () => {
- Vehicle:
+ {t('IssueScreen.vehicle')}
@@ -107,7 +109,7 @@ const IssueScreen = () => {
- Priority:
+ {t('IssueScreen.priority')}
@@ -118,7 +120,7 @@ const IssueScreen = () => {
- Status:
+ {t('IssueScreen.status')}
@@ -129,7 +131,7 @@ const IssueScreen = () => {
- Report:
+ {t('IssueScreen.report')}
@@ -142,7 +144,7 @@ const IssueScreen = () => {
- Report Location:
+ {t('IssueScreen.reportLocation')}
@@ -154,4 +156,4 @@ const IssueScreen = () => {
);
};
-export default IssueScreen;
+export default IssueScreen;
\ No newline at end of file
diff --git a/src/screens/PhoneLoginScreen.tsx b/src/screens/PhoneLoginScreen.tsx
index d502a9c3..4ed112a2 100644
--- a/src/screens/PhoneLoginScreen.tsx
+++ b/src/screens/PhoneLoginScreen.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useState, useCallback } from 'react';
import { useNavigation } from '@react-navigation/native';
-import { SafeAreaView, Pressable, Keyboard, StyleSheet } from 'react-native';
+import { SafeAreaView, Pressable, Keyboard, StyleSheet, Alert } from 'react-native';
import { Spinner, Input, Stack, Text, YStack, useTheme, Button } from 'tamagui';
import { toast, ToastPosition } from '@backpackapp-io/react-native-toast';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
@@ -10,6 +10,7 @@ import { useAuth } from '../contexts/AuthContext';
import useAppTheme from '../hooks/use-app-theme';
import PhoneInput from '../components/PhoneInput';
import LinearGradient from 'react-native-linear-gradient';
+import { useLanguage } from '../contexts/LanguageContext';
const PhoneLoginScreen = () => {
const navigation = useNavigation();
@@ -17,6 +18,7 @@ const PhoneLoginScreen = () => {
const { isDarkMode } = useAppTheme();
const { login, isSendingCode, phone: phoneState, loginMethod } = useAuth();
const [phone, setPhone] = useState(phoneState);
+ const { t } = useLanguage();
const handleSendVerificationCode = async () => {
if (isSendingCode) {
@@ -24,7 +26,7 @@ const PhoneLoginScreen = () => {
}
if (!isValidPhoneNumber(phone)) {
- return toast.error('Invalid phone number provided.');
+ return toast.error(t('PhoneLoginScreen.invalidPhoneNumberProvided'));
}
try {
@@ -49,13 +51,13 @@ const PhoneLoginScreen = () => {
- Login via SMS
+ {t('PhoneLoginScreen.loginViaSms')}
setPhone(phoneNumber)} />
{isSendingCode ? : }
- Send Verification Code
+ {t('PhoneLoginScreen.sendVerificationCode')}
@@ -70,7 +72,7 @@ const PhoneLoginScreen = () => {
- Home
+ {t('PhoneLoginScreen.home')}
@@ -79,4 +81,4 @@ const PhoneLoginScreen = () => {
);
};
-export default PhoneLoginScreen;
+export default PhoneLoginScreen;
\ No newline at end of file
diff --git a/src/screens/PhoneLoginVerifyScreen.tsx b/src/screens/PhoneLoginVerifyScreen.tsx
index 3a419972..df06daf6 100644
--- a/src/screens/PhoneLoginVerifyScreen.tsx
+++ b/src/screens/PhoneLoginVerifyScreen.tsx
@@ -1,6 +1,6 @@
import React, { useEffect, useState, useCallback } from 'react';
import { useNavigation } from '@react-navigation/native';
-import { SafeAreaView, Pressable, Keyboard, StyleSheet } from 'react-native';
+import { SafeAreaView, Pressable, Keyboard, StyleSheet, Alert } from 'react-native';
import { Spinner, Button, Input, Stack, Text, YStack, XStack, useTheme } from 'tamagui';
import { toast, ToastPosition } from '@backpackapp-io/react-native-toast';
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
@@ -9,22 +9,26 @@ import { OtpInput } from 'react-native-otp-entry';
import { useAuth } from '../contexts/AuthContext';
import { navigatorConfig } from '../utils';
import LinearGradient from 'react-native-linear-gradient';
+import { useLanguage } from '../contexts/LanguageContext';
const PhoneLoginVerifyScreen = () => {
const navigation = useNavigation();
const theme = useTheme();
const { phone, verifyCode, isVerifyingCode, loginMethod } = useAuth();
- const [code, setCode] = useState(null);
+ const [code, setCode] = useState(null);
+ const { t } = useLanguage();
- const handleVerifyCode = async (code) => {
+ const handleVerifyCode = async (code: string | null) => {
if (isVerifyingCode) {
return;
}
try {
- await verifyCode(code);
- } catch (error) {
- toast.error(error.message);
+ if (code) {
+ await verifyCode(code);
+ }
+ } catch (error: any) {
+ toast.error(t('common.error') + ': ' + error.message);
}
};
@@ -39,7 +43,7 @@ const PhoneLoginVerifyScreen = () => {
- Code sent to {phone}
+ {t('PhoneLoginVerifyScreen.verifyCode')} {phone}
{
handleVerifyCode(code)} bg='$primary' width='100%' opacity={isVerifyingCode ? 0.75 : 1} disabled={isVerifyingCode} rounded>
{isVerifyingCode ? : }
- Verify Code
+ {t('PhoneLoginVerifyScreen.verifyCode')}
@@ -60,7 +64,7 @@ const PhoneLoginVerifyScreen = () => {
- Retry
+ {t('common.retry')}
{loginMethod === 'email' && (
@@ -71,10 +75,10 @@ const PhoneLoginVerifyScreen = () => {
- Unable to send SMS.
+ {t('PhoneLoginVerifyScreen.unableToSendSms')}
- Your verification code was sent via {loginMethod}.
+ {t('PhoneLoginVerifyScreen.verifyCode')} was sent via {loginMethod}.
@@ -88,4 +92,4 @@ const PhoneLoginVerifyScreen = () => {
);
};
-export default PhoneLoginVerifyScreen;
+export default PhoneLoginVerifyScreen;
\ No newline at end of file
diff --git a/src/screens/TestScreen.tsx b/src/screens/TestScreen.tsx
index 3a9907f0..b9b7e78a 100644
--- a/src/screens/TestScreen.tsx
+++ b/src/screens/TestScreen.tsx
@@ -1,13 +1,16 @@
import { YStack, Text } from 'tamagui';
+import { useLanguage } from '../contexts/LanguageContext';
const TestScreen = () => {
+ const { t } = useLanguage();
+
return (
- Hello World
+ {t('TestScreen.helloWorld')}
);
};
-export default TestScreen;
+export default TestScreen;
\ No newline at end of file
diff --git a/src/screens/VehicleScreen.tsx b/src/screens/VehicleScreen.tsx
index 569b843f..38a252ca 100644
--- a/src/screens/VehicleScreen.tsx
+++ b/src/screens/VehicleScreen.tsx
@@ -1,17 +1,19 @@
import { useNavigation } from '@react-navigation/native';
import { Text, YStack, useTheme } from 'tamagui';
+import { useLanguage } from '../contexts/LanguageContext';
const VehicleScreen = () => {
const theme = useTheme();
const navigation = useNavigation();
+ const { t } = useLanguage();
return (
- VehicleScreen
+ {t('VehicleScreen.vehiclescreen')}
);
};
-export default VehicleScreen;
+export default VehicleScreen;
\ No newline at end of file
diff --git a/src/utils/localize.js b/src/utils/localize.js
index 96486459..f7390aff 100644
--- a/src/utils/localize.js
+++ b/src/utils/localize.js
@@ -1,7 +1,7 @@
import { getLangNameFromCode } from 'language-name-map';
import { getString } from '../utils/storage';
import { get, navigatorConfig } from '../utils';
-import en from '../../translations/en.json';
+import en from '../locales/en.js';
// import mn from '../../translations/mn.json';
import I18n from 'react-native-i18n';