-
-
Notifications
You must be signed in to change notification settings - Fork 836
Readest i18n Guide
Readest uses the key-as-content approach for internationalization (i18n), where English strings are used as translation keys. This ensures straightforward management of translations across the app. Strings for translations are marked with the _ shorthand token of useTranslation hook in React components and stub translation function in non-React modules.
To translate strings within React components, import and use the useTranslation hook. This provides a shorthand function for translating strings.
--- a/apps/readest-app/src/app/reader/hooks/useProgressSync.ts
+++ b/apps/readest-app/src/app/reader/hooks/useProgressSync.ts
@@ -5,6 +5,7 @@ import { BookConfig } from '@/types/book';
import { useBookDataStore } from '@/store/bookDataStore';
import { useReaderStore } from '@/store/readerStore';
import { useSettingsStore } from '@/store/settingsStore';
+import { useTranslation } from '@/hooks/useTranslation';
import { deserializeConfig, serializeConfig } from '@/utils/serializer';
import { DEFAULT_BOOK_SEARCH_CONFIG, SYNC_PROGRESS_INTERVAL_SEC } from '@/services/constants';
@@ -12,6 +13,7 @@ export const useProgressSync = (
bookKey: string,
setToastMessage?: React.Dispatch<React.SetStateAction<string>>,
) => {
+ const _ = useTranslation();
const { getConfig, setConfig } = useBookDataStore();
const { getView } = useReaderStore();
const { settings } = useSettingsStore();
@@ -81,7 +83,7 @@ export const useProgressSync = (
const configFraction = config!.progress![0] / config!.progress![1];
if (syncedFraction > configFraction) {
view?.goToFraction(syncedFraction);
- setToastMessage?.('Progress synced');
+ setToastMessage?.(_('Progress synced'));
}
}
}For non-React modules, use a stub translation function (stubTranslation) during string declaration. Then, use the real translation function provided by the useTranslation hook in the React component where the string is utilized.
Define strings with stubTranslation shorthand _ in a utility module:
import { stubTranslation as _ } from '@/utils/misc';
export const FILE_REVEAL_LABELS = {
macos: _('Reveal in Finder'),
windows: _('Reveal in File Explorer'),
linux: _('Reveal in Folder'),
default: _('Reveal in Folder'),
};
Use the real translation function from the useTranslation hook in the relevant React component:
const showBookInFinderMenuItem = await MenuItem.new({
text: _(fileRevealLabel),
action: async () => {
const folder = `${settings.localBooksDir}/${getFilename(book)}`;
revealItemInDir(folder);
},
});
Run the following command to automatically extract new strings for translation:
pnpm i18n:extract
This command scans the codebase for untranslated strings and adds them to the public/locales directory. Newly extracted strings are assigned the value __STRING_NOT_TRANSLATED__.
-
The English locale has an empty translation file because the key-as-content approach is used. In this case, the key itself serves as the translation.
-
Other locales include translations in their respective files.
-
Stub Translation: Use
stubTranslationonly for non-React modules. -
Default to English: When no translation is found, the key (English string) will be used as the fallback.
-
Local Directory: Translation files are stored in
public/locales. Ensure this directory is kept in sync when adding or modifying translations. -
Only translation keys in the format
_('KEY', options?={})are recognized. For more details, refer to the config file fori18next-scanner.