Closed arthot closed 6 years ago
Hey there,
to be honest I was at the same point in my current project. I had some text variables from an external library I wanted to translate. I think the best would be to create a translate function like you suggested. A way to use the tag functionality by calling a function. Unfortunately I don't have a lot of time right now so I will keep this task open for someone to grab.
Most probably I will have time in the next 2 weeks to participate. The problem I see is that the most intuitive way to use tag as function is occupied by groups functionality:
let translation = i18n(key)
will just return new function. let translation = i18n()(key)
also doesn't look good.
So the only solution without braking changes is a separate function like let translation = i18n.translate(key)
or let translation = i18n(group).translate(key)
What do you think?
Thanks I appreciate your help.
The syntax looks good. There is also a third case: let translation = i18n(translationGroup, configGroup).translate(key)
hello, justed started using the library. thanks for the work :)
any hint on the workaround for calling i18n for a dynamic key with arguments? does that make sense?
I tried i18n([key, value])
work? It does not seem to be working.
thanks @pedroteixeira 👍 @arthot do you have a workaround for this usecase?
Yes. It's not so obvious, but workaround exists.
For instance you want to construct a phrase: Hi, {0}. I'm a {1} value
so direct call will be:
i18n(["Hi, ", ". I'm a ", " value"], ZERO_VALUE, ONE_VALUE)
So the main rule is: item count in first array must equals to variables count + 1
If you want to use formatting: Hi, {0}:c. I'm a {1}:c value
i18n(["Hi, ", ":c. I'm a ", ":c value"], ZERO_VALUE, ONE_VALUE)
It also possible to have only variables: {0}:c
i18n(["", ":c"], ZERO_VALUE)
thanks a lot!
how about a function like
i18n(group, configGroup).translate('my key {0} eg.', ['value', 'format'] | 'value', ...)
to support the same formatting functionality of a i18n template string in a simple function?
to have a 'oficial' library function that accepts a string template and internally does the spliting based on some regexp and accept a array of values will be really handy :)
@skolmer , in your example i18n(group, configGroup).translate('my key {0} eg.', ['value', 'format'] | 'value', ...)
, why do you move formatting to the variable, instead of being part of template like my key {0}:format eg.'
. I suppose we should adhere to the same style like in tagged strings.
const translations = {'your phone is {0}': 'deine Telefonnummer ist {0}', 'your email is: {0}': 'deine email ist {0}'}
let dynamic_var = api.getType();
let result = i18n.translate(`your ${dynamic_var} is {0}:format`, 1234)
But we can even implement both variants, because sometimes variables can have really different meaning like string or number
Hi, I ended writing the following wrapper function:
export function translate(i18n, template, values) {
let tokens = template.split(/\${[^}\r\n]*}/g);
let args = [tokens];
if(values) {
args = args.concat(values)
}
return i18n.apply(null, args);
}
Some usages:
describe('text with two arguments', () => {
const translations = {
"Changed label from ${0} to ${1}": "Renamed from '${0}' to '${1}'"
};
const A = 'A';
const B = 'B';
describe('translating dynamic keys', () => {
beforeEach(() => {
i18nConfig({
translations: translations
});
});
it('i18n expects an array for the text, and the values as rest', () => {
expect(i18n(['Changed label from ', ' to ', ''], A, B)).toEqual(
"Renamed from 'A' to 'B'"
);
});
it('translate should work just like i18n, assuming indices for arguments', () => {
expect(translate(i18n, 'Changed label from ${0} to ${1}', [A, B])).toEqual(
"Renamed from 'A' to 'B'"
);
});
});
});
@arthot I used this syntax because the formatting information is part of the template string but not part of the key. If you write a template string like this:
i18n`total: ${var}:n(2)`
the translation will look like this:
{ "total: ${0}": "Summe: ${0}" }
the function could use the same key format:
i18n.translate("total: ${0}", [var, 'n(2)'])
It will keep the key management more consistent and you can use the same key via template string or function. You will also be able to use the same key for different formats. The translation will be decoupled from formatting which brings a lot more flexibility.
we could even skip a lot of the string parsing work if we would choose a format like:
i18n.translate("total: ${0}", { value: var, formatter: 'n', format: 2 })
Is someone already working on this? Please let me know if that's the case. We need this feature in our current project too and I will start with an implementation if no one has already started working on this. Thanks!
My current workaround:
i18nConfig({
locales: 'en-GB',
translations: {
variables: {
word: 'thing',
},
},
standardFormatters: {
string: {
i18n: (locales, stringOptions, value) => i18n('variables')([value]),
},
},
});
const variable = 'word';
console.log(i18n`Translate this ${variable}:s(i18n)`);
Output Translate this thing
.
Downside is you can't specify a translation group for the variable (unless you create a separate formatter for every group, or your environment allows Proxies to achieve the same thing).
Could resolve this by adding a new localizer to the module:
i /*translatable variable*/: (config, v, group) => {
return this.i18n(group, config, [v])
},
But @skolmer you said you didn't want to do this using formatting information? IMO it's preferable to have the translation key include placeholders and have the variables as separate translation keys.
@simlrh very creative solution 👍
I just pushed the implementation I worked on. It's not well documented yet but has 100% test coverage, so it should work fine.
Release: https://github.com/skolmer/es2015-i18n-tag/releases/tag/v1.2.0 Docs: https://github.com/skolmer/es2015-i18n-tag#translating-without-template-literals
Update: i18n-tag-schema is now able to pick up translation keys from i18n.translate()
Hi! I'm wondering, is it possible to use es2015-i18n-tag with dynamic key? For instance:
will not work, because it will pass
key
variable as param of template string. So do any official way to do this exists? Because right now I'm using following workaround:but maybe it worth to consider to have official simple function fallback? Because this issue also occurs with different template engines were tagged strings are not yet supported (Vue for instance) and this limit usage scope of this great project.