Browse Source

feat: added i18n translator & developer guides (#646)

pull/653/head
Dan Ditomaso 12 months ago
committed by GitHub
parent
commit
26d5c0a08a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 3
      .github/pull_request_template.md
  2. 112
      CONTRIBUTING_I18N_DEVELOPER_GUIDE.md
  3. 31
      CONTRIBUTING_TRANSLATIONS.md

3
.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)

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

31
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!
Loading…
Cancel
Save