i18n(app-svep) + i18n-vakt: hela mobil-UI:t översatt + CI-vakt mot regress
- Svepte 51 hårdkodade strängar -> t() över konto, sök/bläddra, sparade recept, kök, planera, skanna, byt måltid, inköp, minne, cooking, api-fel (+ locLabel/ kategorier via nycklar). 47 nya nycklar, översatta till alla 12 språk. - NY: apps/mobile/scripts/i18n-check.mjs (i18n:check) – fäller bygget om ett språk saknar en nyckel, en använd nyckel saknas, eller det finns hårdkodad UI-text. Wire:ad i CI (.github/workflows/ci.yml) efter typecheck. => 'lägg till språk' blir: kör vakten, den listar exakt vad som fattas. Aldrig mer leta för hand. - Prettier-fixade 5 filer från tidigare leveranser så format:check blir grön. - submit-recipe fri-text-payload + firebase dev-stubs markerade // i18n-ignore. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -37,14 +37,8 @@ interface InventoryItem {
|
||||
}
|
||||
|
||||
const LOCATION_ORDER = ["fridge", "freezer", "pantry", "garage_freezer", "wine_fridge"];
|
||||
const LOCATION_LABELS: Record<string, string> = {
|
||||
fridge: "Kyl",
|
||||
freezer: "Frys",
|
||||
pantry: "Skafferi",
|
||||
garage_freezer: "Garagefrys",
|
||||
wine_fridge: "Vinkyl",
|
||||
};
|
||||
const locLabel = (type: string) => LOCATION_LABELS[type] ?? type;
|
||||
const locLabel = (type: string) =>
|
||||
LOCATION_ORDER.includes(type) ? t(`home.location.${type}`) : type;
|
||||
const orderIndex = (type: string) => {
|
||||
const i = LOCATION_ORDER.indexOf(type);
|
||||
return i === -1 ? LOCATION_ORDER.length : i;
|
||||
@@ -121,25 +115,30 @@ export default function KitchenScreen() {
|
||||
|
||||
const confirmDelete = (ids: string[], label: string) => {
|
||||
if (ids.length === 0) return;
|
||||
Alert.alert(
|
||||
"Ta bort",
|
||||
`Är du säker på att du vill ta bort ${ids.length} ${ids.length === 1 ? "vara" : "varor"} ur ${label}?`,
|
||||
[
|
||||
{ text: t("common.cancel"), style: "cancel" },
|
||||
{ text: "Ta bort", style: "destructive", onPress: () => bulkRemove.mutate(ids) },
|
||||
],
|
||||
);
|
||||
Alert.alert(t("common.remove"), t("kitchen.deleteConfirm", { label }), [
|
||||
{ text: t("common.cancel"), style: "cancel" },
|
||||
{ text: t("common.remove"), style: "destructive", onPress: () => bulkRemove.mutate(ids) },
|
||||
]);
|
||||
};
|
||||
|
||||
const emptyLabel = locFilter ? locLabel(locFilter) : q ? "sökningen" : "hela lagret";
|
||||
const emptyLabel = locFilter
|
||||
? locLabel(locFilter)
|
||||
: q
|
||||
? t("kitchen.scopeSearch")
|
||||
: t("kitchen.scopeAll");
|
||||
|
||||
return (
|
||||
<Screen>
|
||||
<Input value={search} onChangeText={setSearch} placeholder="Sök vara…" autoCorrect={false} />
|
||||
<Input
|
||||
value={search}
|
||||
onChangeText={setSearch}
|
||||
placeholder={t("kitchen.searchPlaceholder")}
|
||||
autoCorrect={false}
|
||||
/>
|
||||
|
||||
<Row>
|
||||
<Button
|
||||
label="Alla"
|
||||
label={t("common.all")}
|
||||
variant={locFilter === null ? "primary" : "ghost"}
|
||||
onPress={() => setLocFilter(null)}
|
||||
/>
|
||||
@@ -162,22 +161,25 @@ export default function KitchenScreen() {
|
||||
<Button
|
||||
label={`Ta bort valda (${selected.size})`}
|
||||
variant="danger"
|
||||
onPress={() => confirmDelete([...selected], "markeringen")}
|
||||
onPress={() => confirmDelete([...selected], t("kitchen.scopeSelection"))}
|
||||
/>
|
||||
)}
|
||||
{visible.length > 0 && (
|
||||
<Button
|
||||
label="Töm listan"
|
||||
label={t("kitchen.clearList")}
|
||||
variant="ghost"
|
||||
onPress={() => confirmDelete(visible.map((i) => i.id), emptyLabel)}
|
||||
onPress={() =>
|
||||
confirmDelete(
|
||||
visible.map((i) => i.id),
|
||||
emptyLabel,
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Row>
|
||||
</Row>
|
||||
|
||||
{visible.length === 0 && (
|
||||
<EmptyState text="Inga varor att visa. Skanna eller lägg till varor." />
|
||||
)}
|
||||
{visible.length === 0 && <EmptyState text={t("kitchen.empty")} />}
|
||||
|
||||
{groups.map((g) => (
|
||||
<View key={g.type} style={{ gap: spacing.xs, marginTop: spacing.sm }}>
|
||||
@@ -191,7 +193,11 @@ export default function KitchenScreen() {
|
||||
<Card
|
||||
key={item.id}
|
||||
onPress={() => toggle(item.id)}
|
||||
style={isSel ? { borderColor: colors.primary, backgroundColor: colors.primarySoft } : undefined}
|
||||
style={
|
||||
isSel
|
||||
? { borderColor: colors.primary, backgroundColor: colors.primarySoft }
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Row style={{ justifyContent: "space-between", alignItems: "center" }}>
|
||||
<Body>
|
||||
@@ -199,7 +205,7 @@ export default function KitchenScreen() {
|
||||
{item.displayName} · {formatQuantity(item.quantity, item.unit)}
|
||||
</Body>
|
||||
<Row style={{ alignItems: "center", gap: 12 }}>
|
||||
{item.expiry.pastBestBefore && <Small>⚠︎ bäst före</Small>}
|
||||
{item.expiry.pastBestBefore && <Small>⚠︎ {t("kitchen.pastBefore")}</Small>}
|
||||
<Pressable
|
||||
onPress={() => confirmDelete([item.id], locLabel(item.locationType))}
|
||||
hitSlop={8}
|
||||
|
||||
Reference in New Issue
Block a user