feat: added i18n translator & developer guides (#646)
This commit is contained in:
@@ -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
|
- [ ] Code follows project style guidelines
|
||||||
- [ ] Documentation has been updated or added
|
- [ ] Documentation has been updated or added
|
||||||
- [ ] Tests have been added or updated
|
- [ ] 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)
|
||||||
|
|||||||
@@ -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>;
|
||||||
|
```
|
||||||
@@ -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!
|
||||||
Reference in New Issue
Block a user