add en/vi language

This commit is contained in:
Tran Anh Tuan
2025-11-15 16:58:07 +07:00
parent 1a534eccb0
commit e725819c01
31 changed files with 1843 additions and 232 deletions

View File

@@ -1,8 +1,13 @@
import EnIcon from "@/assets/icons/en_icon.png";
import VnIcon from "@/assets/icons/vi_icon.png";
import RotateSwitch from "@/components/rotate-switch";
import ScanQRCode from "@/components/ScanQRCode";
import { ThemedText } from "@/components/themed-text";
import { ThemedView } from "@/components/themed-view";
import SliceSwitch from "@/components/ui/slice-switch";
import { DOMAIN, TOKEN } from "@/constants";
import { login } from "@/controller/AuthController";
import { useI18n } from "@/hooks/use-i18n";
import { showErrorToast, showWarningToast } from "@/services/toast_service";
import {
getStorageItem,
@@ -25,7 +30,6 @@ import {
TouchableOpacity,
View,
} from "react-native";
export default function LoginScreen() {
const router = useRouter();
const [username, setUsername] = useState("");
@@ -33,6 +37,8 @@ export default function LoginScreen() {
const [loading, setLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
const [isShowingQRScanner, setIsShowingQRScanner] = useState(false);
const { t, setLocale, locale } = useI18n();
const [isVNLang, setIsVNLang] = useState(false);
const checkLogin = useCallback(async () => {
const token = await getStorageItem(TOKEN);
@@ -47,7 +53,6 @@ export default function LoginScreen() {
return;
}
const parsed = parseJwtToken(token);
// console.log("Parse Token: ", parsed);
const { exp } = parsed;
const now = Math.floor(Date.now() / 1000);
@@ -60,6 +65,10 @@ export default function LoginScreen() {
}
}, [router]);
useEffect(() => {
setIsVNLang(locale === "vi");
}, [locale]);
useEffect(() => {
checkLogin();
}, [checkLogin]);
@@ -131,6 +140,15 @@ export default function LoginScreen() {
}
};
const handleSwitchLanguage = (isVN: boolean) => {
if (isVN) {
setLocale("vi");
} else {
setLocale("en");
}
setIsVNLang(isVN);
};
return (
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
@@ -147,10 +165,7 @@ export default function LoginScreen() {
resizeMode="contain"
/>
<ThemedText type="title" style={styles.title}>
Hệ thống giám sát tàu
</ThemedText>
<ThemedText style={styles.subtitle}>
Đăng nhập đ tiếp tục
{t("common.app_name")}
</ThemedText>
</View>
@@ -158,10 +173,10 @@ export default function LoginScreen() {
<View style={styles.formContainer}>
{/* Username Input */}
<View style={styles.inputGroup}>
<ThemedText style={styles.label}>Tài khoản</ThemedText>
<ThemedText style={styles.label}>{t("auth.username")}</ThemedText>
<TextInput
style={styles.input}
placeholder="Nhập tài khoản"
placeholder={t("auth.username_placeholder")}
placeholderTextColor="#999"
value={username}
onChangeText={setUsername}
@@ -172,11 +187,11 @@ export default function LoginScreen() {
{/* Password Input */}
<View style={styles.inputGroup}>
<ThemedText style={styles.label}>Mật khẩu</ThemedText>
<ThemedText style={styles.label}>{t("auth.password")}</ThemedText>
<View className="relative">
<TextInput
style={styles.input}
placeholder="Nhập mật khẩu"
placeholder={t("auth.password_placeholder")}
placeholderTextColor="#999"
value={password}
onChangeText={setPassword}
@@ -228,7 +243,7 @@ export default function LoginScreen() {
{loading ? (
<ActivityIndicator color="#fff" size="small" />
) : (
<Text style={styles.loginButtonText}>Đăng nhập</Text>
<Text style={styles.loginButtonText}>{t("auth.login")}</Text>
)}
</TouchableOpacity>
@@ -255,18 +270,32 @@ export default function LoginScreen() {
</TouchableOpacity>
</View>
{/* Footer text */}
<View style={styles.footerContainer}>
<ThemedText style={styles.footerText}>
Chưa tài khoản?{" "}
<Text style={styles.linkText}>Đăng ngay</Text>
</ThemedText>
{/* Language Switcher */}
<View style={styles.languageSwitcherContainer}>
<RotateSwitch
initialValue={isVNLang}
onChange={handleSwitchLanguage}
size="sm"
offImage={EnIcon}
onImage={VnIcon}
/>
<SliceSwitch
size="sm"
leftIcon="moon"
leftIconColor="white"
rightIcon="sunny"
rightIconColor="orange"
activeBackgroundColor="black"
inactiveBackgroundColor="white"
inactiveOverlayColor="black"
activeOverlayColor="white"
/>
</View>
{/* Copyright */}
<View style={styles.copyrightContainer}>
<ThemedText style={styles.copyrightText}>
© {new Date().getFullYear()} - Sản phẩm của Mobifone
© {new Date().getFullYear()} - {t("common.footer_text")}
</ThemedText>
</View>
</View>
@@ -364,4 +393,46 @@ const styles = StyleSheet.create({
opacity: 0.6,
textAlign: "center",
},
languageSwitcherContainer: {
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignItems: "center",
marginTop: 24,
gap: 20,
},
languageSwitcherLabel: {
fontSize: 12,
fontWeight: "600",
textAlign: "center",
opacity: 0.8,
},
languageButtonsContainer: {
flexDirection: "row",
gap: 10,
},
languageButton: {
flex: 1,
paddingVertical: 10,
paddingHorizontal: 12,
borderWidth: 1,
borderColor: "#ddd",
borderRadius: 8,
alignItems: "center",
backgroundColor: "transparent",
},
languageButtonActive: {
backgroundColor: "#007AFF",
borderColor: "#007AFF",
},
languageButtonText: {
fontSize: 14,
fontWeight: "500",
color: "#666",
},
languageButtonTextActive: {
color: "#fff",
fontWeight: "600",
},
});