* feat(protobufs): sync to firmware-current and consume workspace package Sync the vendored .proto sources to firmware-current (v2.7.25+48), regenerate the v2 TS bindings, and consume the workspace @meshtastic/protobufs (workspace:*) in place of the stale JSR 2.7.20 — finishing the monorepo migration (core was already workspace:*). Includes the one required breaking-change fix: admin nodedb_reset changed int32 to bool, so resetNodes() now sends value: true. * build(protobufs): vendor generated bindings for workspace consumers The package is consumed via workspace:* — its exports point at the TS source, which imports ./dist/meshtastic/*_pb.ts — so the generated output must exist at build time. CI builds web/core with no codegen step and the runners have no buf CLI, so the bindings are vendored here (kept gitignored; lint/format skip them). Regenerate with: pnpm --filter @meshtastic/protobufs gen * fix(protobufs): clean script removes the actual generated output dir buf writes bindings to packages/ts/dist, but clean was removing a non-existent root dist — so it never cleaned stale output. Addresses Copilot review feedback. * refactor: move web app packages/web -> apps/web Aligns the web app with the apps/web layout (matching the Vercel web-test Root Directory and the SDK-migration direction). Pure directory move plus root config: pnpm-workspace (adds apps/*), vitest projects, root tsconfig reference, and the pr/release-web/nightly workflows. vercel.json moved with the app. Build + 36 validation tests green. * feat: config fields, module pages, key verification, telemetry capture Incorporates the firmware-current feature work onto the protobuf foundation: new config fields (Display message bubbles; LoRa fem_lna_mode + serial_hal_only; Telemetry air_quality_screen_enabled); 4 new ModuleConfig pages (TrafficManagement, StatusMessage, TAK, RemoteHardware); the manual Key Verification flow (sendKeyVerification + ClientNotificationDialog stages + Verify Key button); live telemetry capture (nodeDB addDeviceMetrics) and admin hardening (toggleMutedNode, graceful PortNum default); plus the sdk-preview ConfigEditor demo and store/config tests. Build + lint + format + 131 tests green. * chore: drop #1062 (unsaved-change-detection) to match upstream revert #1062 was merged to main by accident (per @danditomaso) and is being reverted. Reverse-applied its diff here via 3-way so #1097 stays consistent with where main is headed, while keeping the feature changes layered on the same files (deviceStore/changeRegistry). Build + 131 tests + lint + format green. * fix(nodes): clean up SNR display in node table and map popup SNR is a ratio measured in dB, not dBm (which is absolute power); the node table and map popup both mislabeled it and crammed three values together: '0dBm/50%/50raw'. The trailing '%/raw' pair was the same heuristic ((snr+10)*5) shown twice — once clamped, once not. Render SNR in dB rounded to one decimal, color-coded by a 0-100% signal-quality heuristic (green/yellow/red), with the quality percentage as a muted secondary. Drop the redundant raw value. Adds unit.db; this matches the existing SNRTooltip, which already renders dB.
112 lines
3.5 KiB
Markdown
112 lines
3.5 KiB
Markdown
# i18n Developer Guide
|
|
|
|
When developing new components, all user-facing text must be added as an i18n
|
|
key and rendered using our translation functions. This ensures your UI can be
|
|
translated into multiple languages.
|
|
|
|
## Adding New i18n Keys
|
|
|
|
### Search Before Creating
|
|
|
|
Before adding a new key, please perform a quick search to see if one that fits
|
|
your needs already exists. Many common labels like "Save," "Cancel," "Name,"
|
|
"Description," "Loading...," or "Error" are likely already present, especially
|
|
in the common.json namespace. Reusing existing keys prevents duplication and
|
|
ensures consistency across the application. Using your code editor's search
|
|
function across the /i18n/locales/en/ directory is an effective way to do this.
|
|
|
|
### Key Naming and Structure Rules
|
|
|
|
To maintain consistency and ease of use, please adhere to the following rules
|
|
when creating new keys in the JSON files.
|
|
|
|
- **Keys are camelCase:** `exampleKey`, `anotherExampleKey`.
|
|
- **Avoid Deep Nesting:** One or two levels of nesting are acceptable for
|
|
grouping related keys (e.g., all labels for a specific menu). However, nesting
|
|
deeper than two levels should be avoided to maintain readability and ease of
|
|
use.
|
|
- **Good (1 level):**
|
|
```json
|
|
"buttons": {
|
|
"save": "Save",
|
|
"cancel": "Cancel"
|
|
}
|
|
```
|
|
- **Acceptable (2 levels):**
|
|
```json
|
|
"userMenu": {
|
|
"items": {
|
|
"profile": "Profile",
|
|
"settings": "Settings"
|
|
}
|
|
}
|
|
```
|
|
- **Avoid (3+ levels):**
|
|
```json
|
|
"userMenu": {
|
|
"items": {
|
|
"actions": {
|
|
"viewProfile": "View Profile"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
- **Organize for Retrieval, Not UI Layout:** Keys should be named logically for
|
|
easy retrieval, not to mirror the layout of your component.
|
|
|
|
### Namespace Rules
|
|
|
|
We use namespaces to organize keys. All source keys are added to the English
|
|
(`en`) files located at `/packages/web/public/i18n/locales/en/`. Place your new keys in the
|
|
appropriate file based on these rules:
|
|
|
|
- `common.json`:
|
|
- All button labels (`save`, `cancel`, `submit`, etc.).
|
|
- Any text that is repeated and used throughout the application (e.g.,
|
|
"Loading...", "Error").
|
|
- `ui.json`:
|
|
- Labels and text specific to a distinct UI element or view that isn't a
|
|
dialog or a config page.
|
|
- `dialog.json`:
|
|
- All text specific to modal dialogs (titles, body text, prompts).
|
|
- `messages.json`:
|
|
- Text specifically related to the messaging interface.
|
|
- `deviceConfig.json` & `moduleConfig.json`:
|
|
- Labels and descriptions for the settings on the Device and Module
|
|
configuration pages.
|
|
|
|
## Using i18n Keys in Components
|
|
|
|
We use the `useTranslation` hook from `react-i18next` to access the translation
|
|
function, `t`.
|
|
|
|
### Default Namespaces
|
|
|
|
Our i18next configuration has fallback namespaces configured which includes
|
|
`common`, `ui`, and `dialog`. This means you **do not** need to explicitly
|
|
specify these namespaces when calling the hook. The system will automatically
|
|
check these files for your key.
|
|
|
|
For any keys in `common.json`, `ui.json`, or `dialog.json`, you can instantiate
|
|
the hook simply:
|
|
|
|
```typescript
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
// In your component
|
|
const { t } = useTranslation(["messages"]);
|
|
|
|
// Usage
|
|
return <p>{t("someMessageLabel")}</p>;
|
|
```
|
|
|
|
You can also specify the namespace on a per-call basis using the options object.
|
|
This is useful if a component primarily uses a default namespace but needs a
|
|
single key from another.
|
|
|
|
```typescript
|
|
const { t } = useTranslation();
|
|
|
|
return <p>{t("someMessageLabel", { ns: "messages" })}</p>;
|
|
```
|