From 26d5c0a08a33cad9a5d6aa20fc1fb2e0ade32b42 Mon Sep 17 00:00:00 2001 From: Dan Ditomaso Date: Thu, 12 Jun 2025 20:15:43 -0400 Subject: [PATCH] feat: added i18n translator & developer guides (#646) --- .github/pull_request_template.md | 3 +- CONTRIBUTING_I18N_DEVELOPER_GUIDE.md | 112 +++++++++++++++++++++++++++ CONTRIBUTING_TRANSLATIONS.md | 31 ++++++++ 3 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 CONTRIBUTING_I18N_DEVELOPER_GUIDE.md create mode 100644 CONTRIBUTING_TRANSLATIONS.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c44eaa18..d3fe3f05 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -46,4 +46,5 @@ Check all that apply. If an item doesn't apply to your PR, you can leave it unch - [ ] Code follows project style guidelines - [ ] Documentation has been updated or added - [ ] Tests have been added or updated -- [ ] All i18n translation labels have been added/updated +- [ ] All i18n translation labels have been added (read + CONTRIBUTING_I18N_DEVELOPER_GUIDE.md for more details) diff --git a/CONTRIBUTING_I18N_DEVELOPER_GUIDE.md b/CONTRIBUTING_I18N_DEVELOPER_GUIDE.md new file mode 100644 index 00000000..0b900de6 --- /dev/null +++ b/CONTRIBUTING_I18N_DEVELOPER_GUIDE.md @@ -0,0 +1,112 @@ +# 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 /src/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 `/src/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

{t("someMessageLabel")}

; +``` + +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

{t("someMessageLabel", { ns: "messages" })}

; +``` diff --git a/CONTRIBUTING_TRANSLATIONS.md b/CONTRIBUTING_TRANSLATIONS.md new file mode 100644 index 00000000..66a7d646 --- /dev/null +++ b/CONTRIBUTING_TRANSLATIONS.md @@ -0,0 +1,31 @@ +# Contributing Translations + +Thank you for your interest in making the Meshtastic Web Client accessible to a +global audience! Your translation efforts are greatly appreciated. + +## Our Translation Platform: Crowdin + +We manage all our translations through a platform called +[Crowdin](https://crowdin.com/). This allows for a collaborative and streamlined +translation process. All translation work should be done on our Crowdin project, +not directly in the code repository via Pull Requests. + +### How to Get Started + +1. **Create a Crowdin Account:** If you don't already have one, sign up for a + free account on Crowdin. +2. **Join Our Project:** Please ask for a link to our specific Crowdin project + on the Meshtastic Discord. +3. **Request Translator Role:** Once you have an account, join the Meshtastic + Discord and notify an admin in the `#web` channel. They will grant you the + necessary permissions to start translating. +4. **Start Translating:** Once you have your role, you can begin translating the + source labels into your native language directly on the Crowdin platform. + +### Language Activation + +A new language will only be added to the web client and appear in the language +picker once its translation is 100% complete on Crowdin. The repository +maintainers will handle this process once the milestone is reached. + +Thank you for helping us bring Meshtastic to more users around the world!