rclone-i18n
v1.73.5
Published
Translate rclone RC responses (config/providers, options/info) using language packs fetched on demand.
Downloads
128
Maintainers
Readme
Rclone i18n
Translate rclone RC responses on the fly
Rewrites translatable strings in config/providers and options/info responses · Pairs with rclone-sdk · Works with Vanilla Fetch
Install
npm install rclone-i18nThe package ships a single translate function. Pass it either a raw Response or a parsed JSON body, and it returns the same shape with all known translatable fields rewritten into the target language.
Loading translations
Two modes, pick whichever suits you.
Fetch from jsDelivr (lang)
import { translate } from 'rclone-i18n'
const translated = await translate(body, { lang: 'fr' })The language pack is fetched once from jsDelivr with cache: 'force-cache', so subsequent calls are served from the HTTP cache. Supported codes: fr, ja, zh, es.
Bring your own JSON (messages)
import { translate } from 'rclone-i18n'
const fr = await fetch('/locales/fr.json').then((r) => r.json())
const translated = await translate(body, { messages: fr })Useful when you want to bundle the language pack, ship it from your own CDN, or override individual strings. Grab the source files from languages/ in this repo.
Vanilla Fetch
Pass the raw Response and get a Response back, with the same status, statusText, and headers:
import { translate } from 'rclone-i18n'
const res = await fetch('http://localhost:5572/config/providers', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: '{}',
})
const translatedRes = await translate(res, { lang: 'fr' })
const { providers } = await translatedRes.json()
console.log(providers.find((p) => p.Name === 'local').Description)
// → "Disque local"Or pass the parsed body directly:
const body = await res.json()
const translated = await translate(body, { lang: 'fr' })The original input is never mutated — bodies are deep-cloned, and a fresh Response is returned.
With rclone-sdk
rclone-sdk returns { data, error, response } from each call. Translate data directly:
import createRCDClient from 'rclone-sdk'
import { translate } from 'rclone-i18n'
const rcd = createRCDClient({ baseUrl: 'http://localhost:5572' })
const { data, error } = await rcd.POST('/config/providers')
if (error || !data) throw error
const translated = await translate(data, { lang: 'fr' })
for (const provider of translated.providers ?? []) {
console.log(provider.Name, '→', provider.Description)
}Same thing with /options/info:
const { data } = await rcd.POST('/options/info')
const translated = await translate(data, { lang: 'fr' })
const filter = translated.filter
const maxSize = filter?.find((o) => o.Name === 'max_size')
console.log(maxSize?.Help)
// → "Ne transférer que les fichiers plus petits que cette valeur, …"What gets translated
translate walks the response and rewrites these fields when a matching entry exists in the language pack:
/config/providersproviders[].Descriptionproviders[].Options[].Help(withProvideroverride)providers[].Options[].Examples[].Help(incl. emptyValue: "")providers[].CommandHelp[].Shortand.Longproviders[].MetadataInfo.HelpandMetadataInfo.System[k].Help
/options/info<block>[].Help(e.g.filter,main,vfs, …)<block>[].Examples[].Help
Any other field is passed through unchanged. The function also returns the input untouched when:
- the input is a
Responsewith!okstatus, or non-JSONContent-Type - the input is a parsed body shaped like an rclone error (
{ error: string, … })
Contributing translations
Language packs live in languages/. The English source-of-truth (en.json) is regenerated from a live rclone daemon:
# rclone rcd --rc-no-auth --rc-addr 127.0.0.1:5572 &
npm run extract:i18nscripts/check-i18n.ts (run via npm run check:i18n) compares the live extraction against languages/en.json and fails CI if keys drift. Two manual workflows wrap it: check-release runs against the latest released rclone, check-build builds rclone from master.
To add a new translation, copy languages/en.json, translate the leaf strings, and open a PR. Keys must match exactly — __empty__ is the sentinel for examples whose Value is "".
Contributing
Contributions = welcome!
