A general purpose internationalization library in 298 bytes!
Features
- Simple and Familiar API
- Unobstrusive and Unopinionated
- Less than 300 bytes – including dependencies!
Install
$ npm install --save rosetta
Usage
import rosetta from 'rosetta';
const i18n = rosetta({
en: {
intro: {
welcome: 'Welcome, {{username}}!',
text: 'I hope you find this useful.',
},
support(obj) {
let hour = Math.floor(Math.random() * 3) + 9;
let str = `For questions, I'm available on ${obj.date.toLocaleDateString()}`;
str += `, any time after ${hour}:00.`
return str;
}
}
});
i18n.locale('en');
i18n.set('pt', {
intro: {
welcome: obj => `Benvind${obj.feminine ? 'a' : 'o'}, ${obj.username}!`,
text: 'Espero que você ache isso útil.'
}
});
i18n.set('pt', {
support(obj) {
let hour = Math.floor(Math.random() * 3) + 9;
let str = `Se tiver perguntas, estou disponível em ${obj.date.toLocaleDateString()}`;
str += `, qualquer hora depois às ${hour}:00.`
return str;
}
});
const data = {
feminine: false,
username: 'lukeed',
date: new Date()
};
i18n.t('intro.welcome', data);
i18n.t('intro.text', data);
i18n.t('support', data);
i18n.t('intro.welcome', data, 'pt');
i18n.locale('pt');
i18n.t('intro.text', data);
i18n.t('intro.text', data, 'en');
API
rosetta(dict?)
Returns: Rosetta
Initializes a new Rosetta
instance.
You may optionally provide an initial translation object.
rosetta.locale(lang?)
Returns: String
Sets the language code for the Rosetta
instance.
This will cause all rossetta.t()
lookups to assume this lang
code.
The function will return the currently active lang
code. This means that a setting a new value will reply with the same value. Additionally, calling locale()
without any argument will return the lang
code that the Rosetta
instance was last given.
lang
Type: String
Required: false
The language code to choose.
If locale()
is called without an argument (or with a falsey value), then the current lang
code is returned.
rosetta.set(lang, table)
Merge (or override) translation keys into the lang
collection.
lang
Type: String
The language code to target.
table
Type: Object
A new record of key-values to merge into the lang
's dictionary.
Each key within the table
can correspond to a function or a string template.
When using a function, it will receive the entire data input (see params
).
You are required to ensure the function returns a (string) value of your liking.
When using a string template, anything within double curly brackets ({{ example }}
) will be interpreted as a key path and interpolated via templite
. The key path can use dot-notation to access nested values from the data input (see params
). Additionally, if a key path did not resolve to a value, an empty string is injected.
const ctx = rosetta({
en: {
foo: (obj) => `function sees "${obj.value || '~DEFAULT~'}"`,
bar: 'template sees "{{value}}"'
}
});
ctx.t('foo', {}, 'en');
ctx.t('foo', { value: 123 }, 'en');
ctx.t('bar', {}, 'en');
ctx.t('bar', { value: 123 }, 'en');
rosetta.table(lang)
Returns: Object
or undefined
Retrieve the the lang
's full dictionary/table of translation keys.
If the language does not exist (aka, no translations have been provided for it), you'll receive undefined
.
Otherwise, you'll receive the full object as it exists within the Rosetta
instance. See table
.
Important: Manipulating this object is any way will mutate and affect your Rosetta
instance. Be careful!
lang
Type: String
The language code's table to retrieve.
rosetta.t(key, params?, lang?)
Returns: String
Retrieve the value for a given key
.
Important: In the normal/default mode, an empty string will be returned for unknown keys.
Conversely, in "debug" mode, an error message will be printed and undefined
will be returned for unknown keys.
key
Type: String
or Array<String|Number>
The identifier to retrieve.
A key
can access nested properties via:
- a string that with dot notation —
'foo.bar[1].baz'
- an array of individual key segments —
['foo', 'bar', 1, 'baz']
Important: You are expected to know & traverse your own dictionary structure correctly.
const ctx = rosetta({
en: {
fruits: {
apple: 'apple',
}
}
});
ctx.locale('en');
ctx.t('fruits.apple');
ctx.t(['fruits', 'apple']);
params
Type: any
Optional: true
The data object argument to pass your dictionary keys' string templates and/or functions.
Note: If your string template tries to access a key that doesn't exist, an empty string is injected.
const ctx = rosetta({
es: {
hello: '¡Hola {{name}}!'
},
en: {
hello(obj) {
return obj.name === 'lukeed' ? 'wazzzuppp' : `Hello, ${obj.name}!`;
},
},
pt: {
hello: 'Oi {{person}}, tudo bem?'
},
});
const user1 = { name: 'lukeed' };
const user2 = { name: 'Billy' };
ctx.t('hello', user1, 'es');
ctx.t('hello', user1, 'en');
ctx.t('hello', user2, 'en');
ctx.t('hello', user1, 'pt');
lang
Type: String
Optional: true
A language code override without changing the entire Rosetta
instance's default language.
const ctx = rosetta();
ctx.locale('en');
ctx.t('greeting', 'lukeed');
ctx.t('greeting', 'lukeed', 'es');
ctx.t('bye');
Debugging
There is a "debug" mode included for development environments.
The only difference with "debug" mode is that rossetta.t()
will log an error to the console when attempting to access a key
that does not exist. Conversely, the main/default runtime will quietly return an an empty string for consistent output.
Otherwise, the API is exactly the same as the main/default export!
This makes it easy to alias or swap the versions for development vs production bundles. Checkout the Configuration section below for recipes.
import rosetta from 'rosetta/debug';
const i18n = rosetta({
en: {
hello: 'hello'
}
});
i18n.locale('en');
i18n.t('hello');
i18n.t('foobar');
Note: With the non-"debug" runtime, an empty string would be returned for the foobar
key.
Configuration
Here are quick configuration recipes for Rollup and webpack that allow you to choose the right version of rosetta
for your current environment without changing you application code.
With both recipes, you will import rosetta
like this:
import rosetta from 'rosetta';
It is up to the bundler to change what 'rosetta'
resolves to...
Rollup
You will need to install @rollup/plugin-alias
before continuing.
const isDev = || !!process.env.ROLLUP_WATCH;
export default {
plugins: [
require('@rollup/plugin-alias')({
entries: {
rosetta: isDev ? 'rosetta/debug' : 'rosetta'
}
})
]
}
webpack
The ability to add aliases within webpack comes by default.
One simply needs to add a resolve.alias
value depending on the environment:
const isDev = ;
module.exports = {
resolve: {
alias: {
rosetta: isDev ? 'rosetta/debug' : 'rosetta'
}
}
}
Runtime Support
The library makes use of Object shorthand methods and Object.assign
.
This yields the following support matrix:
Chrome | Safari | Firefox | Edge | IE | Node.js |
---|
45+ | 9+ | 34+ | 12+ | :x: | 4.0+ |
If you need to support older platforms, simply attach rosetta
to your project's Babel (or similar) configuration.
Examples
- Using Next.js — Thank you @SharpTech
Official Next.js example using React Hooks and Context to provide SSR, SSG, CSR compatible i18n solutions.
Credits
Thank you @7sempra for gifting the rosetta
name on npm.
License
MIT © Luke Edwards