Localization support
I'm opening this issue more as a discussion/proposal to see how you'd feel about that
Since it's a self-hosted bot I was thinking it would be pretty cool to be able to change the messages it sends, either to translate them or just as a customization option.
So I did a little work and implemented a very bare bones solution, but before moving forward I'd like to hear your thoughts about it :D
I think this is a great idea! You could then have a "southern" Muse or something instead of just midwestern 😛.
Would be happy to look over a PR implementing this. I would expect a few things:
- A standard library for internalization / localization is used, doesn't make sense to roll our own
- Allow bundling multiple localization files with Muse for different personalities / languages
- Allow a user to load a custom localization file
I did some benchmarking and most i18n libs either:
- Don't have good ts typings
- Aren't well mantained
- Are overly focused on frontend usage (even being bound reac/vue/etc)
So I was thinking, since the bots needs are rather well contained, couldn't we just use simpler code? Something like:
interface MuseLocale {
loadingMessageIcons: string[];
loadingMessage: string;
doneMessage: string;
leaveMessage: string;
addedSongsMessage: (songs: QueuedSong[], addToFrontOfQueue: boolean, extraMsg: string) => string;
skipMessage: (skipCount: number) => string;
...
}
Then locale files could just implement the interface:
export const baseLocale: MuseLocale = {
loadingMessage: 'cows! count \'em',
loadingMessageIcons: ['🐮', '🐴', '🐄'],
doneMessage: 'u betcha',
leaveMessage: 'u betcha',
addedSongsMessage: (songs: QueuedSong[], addToFrontOfQueue: boolean, extraMsg: string) => {
const firstSong = songs[0];
if (songs.length === 1) {
return `u betcha, **${firstSong.title}** added to the${addToFrontOfQueue ? ' front of the' : ''} queue${extraMsg}`;
}
return `u betcha, **${firstSong.title}** and ${songs.length - 1} other songs were added to the queue${extraMsg}`;
},
skipMessage: () => 'keep \'er movin\''
};
Hmm, I didn't consider cases where there's dynamic content injected into strings as you pointed out. Looks like various localization libraries support that, but we'd still have to potentially load a user provided JS/TS file at runtime...
I would be ok doing our own solution as long as it's typesafe and warns users if their file is missing translations. I don't really have any experience with transpiling TS at runtime so you're on your own there. 😛
A few other thoughts I had about localization:
- Not sure how other bots handle this, but might be nice if commands (.e.g
.play) were localized as well - Would be cool to allow users to add custom soundbites for their localization (things like
packers)
Did anything happen with this? I would like to customise the text
Intl.MessageFormat and a simple JSON config could be used, I could implement this if this is fine as an implementation.
lang/en-US.json:
{
"skip": "u betcha, **{title}** was skipped"
// etc
}
Intl.MessageFormat also allows for language plurality. For example:
new Intl.MessageFormat(
`You have {numPhotos, plural,
=0 {no photos.}
=1 {one photo.}
other {# photos.}
}`,
'en-US'
).format({numPhotos: 1000})
// Result: You have 1,000 photos.
I don't think the JSON solution would be type-safe. We do transpile TS at runtime now though, so that's no longer an issue.
I don't think the JSON solution would be type-safe. We do transpile TS at runtime now though, so that's no longer an issue.
I could make a typescript file as constants
Sounds good to me!
just now i am starting to work on this and i realize this is probably not the best approach
is something like i18next doable? since messages wont change i dont see a point in making very strict typing for this
Yeah, i18next is fine with me as long as there's an easy way for users to provide their own translations.