I'm submitting a ... (check one with "x")
[x] bug report => check the FAQ and search github for a similar issue or PR before submitting
[x] support request => check the FAQ and search github for a similar issue before submitting
[x] feature request
I'm not really sure which category this issue belongs to.
I would like to use base language strings as message IDs in my templates as opposed to made up IDs:
{{聽'Log in' |聽translate }} vs. {{ 'HOME_LOGIN_BUTTON' | translate }}
It does not seem like it's supported to use real strings with params though.
Angular complains about template parse error (And rightly so) when doing this:
{{ 'Hello {{ name }}' |聽translate:聽{ name: 'Kim' } }}
Would it maybe make sense to change {{PARAM}} to {PARAM} or something completely else, to not trip up the angular template parser?
Hello,
You're mixing stuff here, params are not for keys, they are for translations. This: {{ 'Hello {{ name }}' | translate: { name: 'Kim' } }} will not work and for a good reason, keys are supposed to be static, not dynamic.
Still you can create dynamic keys like this:
{{ ('Hello' + someVariable) | translate: param }}
// ...
param = { name: 'Kim' };
But the name property will not replace the name in the key
Hi!
I probably did a poor job at explaining what I'm trying to achieve. I'm not trying to have dynamic keys.
This is how you recommend doing translations in the docs with params:
{
"SOME_KEY": "This translations has a param: {{param}}"
}
I don't want to use made up keys, but use the actual english strings. My JSON translation file would look like this (for danish translation):
{
"This translations has a param: {{param}}": "Denne overs忙ttelse indeholder et parameter: {{param}}"
}
Angular template parser trips over this:
{{ 'This translations has a param: {{param}}' | translate: { param: 'Some value' } }}
... which is understandable, but also why I'm raising this issue to debate if params should be marked differently to not confuse the parser.
Hope I explained it better this time!
Sidenote: concatenating translatable strings and variables is a bad idea. It will go wrong. Some translations will need to rearrange the words and variables to make sense in that language. Not related to my issue though, just thought I'd mention it :-)
A little context:
I usually work with po-files (Gettext), where msgid is the full untranslated string in the base language.
We use a translation service and the translators have never seen our app and wouldn't know what any of my made up keys means, making it impossible to do a proper translation.
Reasons (some subjective?) for using 'real strings' as translation keys in a project:
I'm currently working on the directive, and it can use the full text of an element as a key by default. But it will take into account the value of variables.
For example with the following code:
<div translate>Hello {{value}}</div>
//...
value = "world";
The real key will be Hello world, not Hello {{value}}. The idea behind this is that you will be able to provide dynamic values based on parameters inside your elements.
Also once the app is running, we never receive {{value}}, it's always either undefined, null or some value, so there is no way to have a key with {{value}}.
Can you mock the JSON file for your example to help me understand?
I don't understand how your example would work with future extraction of strings, if the extracted key is not going to be Hello {{value}}.
The solution could be to change interpolation start/end chars from {{value}} to, I dunno, {value}?
Pros:
Cons:
It won't work with the auto extraction obviously, that's why you will be able to define keys manually, for example you could do: <div translate="myKey">Hello {{value}}</div>.
The idea is that the tool will detect those cases and warn you (at first), and then once the tool is more sophisticated it will fix your source file by auto generating a key for the translate directive (it could even ask you for that key).
But this will be optional, like I said "Hello {{value}}" is totally valid, it will just mean that you have to define a key "Hello world" for example, and in the end that's up to you to do it.
Can't say I totally agree on the approach (but this is your work, not mine, so please take my words merely as input, not criticism).
I would prefer if it worked more like gettext:
The approach you describe doesn't solve #3 as far as I can see.
for the meaning, I'll probably use the same approach as the angular team and use description strings that will be included into xliff files (when the tool is able to extract to xliff).
If you have external translators you should use advanced formats (like xliff), and not json because they will probably use a translation application (and not edit json files directly).
But I hear your concerns, I need to think about it a bit more to see what's the best approach. I just started the work on this, so there is still time to improve the process
You're right regarding the json format. I actually wrote a KeyValueTranslateLoader, that use a file format that my translation service can work with. Gettext would be optimal though, so might write a loader for po-files, when I find a solution for auto extracting strings.
If you want, you can close this. It's possible to use real strings as base language (with working interpolation) using custom TranslateParser and MissingTranslationHandler, although it's not trivial to do for beginners.
app/app.module.ts
import { TranslateModule, TranslateLoader } from 'ng2-translate';
import { TRANSLATE_PROVIDERS, translateLoaderFactory } from '../i18n';
@NgModule({
declarations: [
AppComponent
],
imports: [
IonicModule.forRoot(AppComponent),
SharedModule,
TranslateModule.forRoot({
provide: TranslateLoader,
useFactory: translateLoaderFactory,
deps: [Http]
})
],
bootstrap: [
IonicApp
],
entryComponents: [
AppComponent
],
providers: [
...TRANSLATE_PROVIDERS
]
})
export class AppModule {
}
i18n/index.ts
import { Http } from '@angular/http';
import {
TranslateParser,
DefaultTranslateParser,
MissingTranslationHandler,
MissingTranslationHandlerParams } from 'ng2-translate';
import { TranslatePoLoader } from '@biesbjerg/ng2-translate-po-loader';
export class InterpolatedTranslateParser extends DefaultTranslateParser {
public templateMatcher: RegExp = /{\s?([^{}\s]*)\s?}/g;
}
export class InterpolatedMissingTranslationHandler implements MissingTranslationHandler {
public parser: TranslateParser = translateParserFactory();
public handle(params: MissingTranslationHandlerParams) {
// return params.translateService.parser.interpolate(params.key, params.interpolateParams);
// Workaround until this PR is merged: https://github.com/ocombe/ng2-translate/pull/348
return this.parser.interpolate(params.key, params.interpolateParams);
}
}
export function translateParserFactory() {
return new InterpolatedTranslateParser();
}
export function translateLoaderFactory(http: Http) {
return new TranslatePoLoader(http, 'assets/i18n');
}
export const TRANSLATE_PROVIDERS = [
{ provide: TranslateParser, useFactory: translateParserFactory },
{ provide: MissingTranslationHandler, useClass: InterpolatedMissingTranslationHandler }
];
@biesbjerg Is it possible to do something like <span translate [translateParams]="{'name': name}">Hello {{name}}</span> with your snippet?
I updated the .po file with
msgid "Hello {{name}}"
msgstr "Hallo {{name}}"
And added the TRANSLATE_PROVIDERS but the string is not translated.
I updated the snippet to work with v6.0.0, do I miss something?
import { Http } from '@angular/http';
import {
TranslateParser,
TranslateDefaultParser,
MissingTranslationHandler,
MissingTranslationHandlerParams } from '@ngx-translate/core';
import { TranslatePoLoader } from '@biesbjerg/ng2-translate-po-loader';
export class InterpolatedTranslateParser extends TranslateDefaultParser {
public templateMatcher: RegExp = /{\s?([^{}\s]*)\s?}/g;
}
export class InterpolatedMissingTranslationHandler implements MissingTranslationHandler {
public parser: TranslateParser = translateParserFactory();
public handle(params: MissingTranslationHandlerParams) {
return params.translateService.parser.interpolate(params.key, params.interpolateParams);
// Workaround until this PR is merged: https://github.com/ocombe/ng2-translate/pull/348
// return this.parser.interpolate(params.key, params.interpolateParams);
}
}
export function translateParserFactory() {
return new InterpolatedTranslateParser();
}
export function translateLoaderFactory(http: Http) {
return new TranslatePoLoader(http, 'assets/i18n', '.po');
}
export const TRANSLATE_PROVIDERS = [
{ provide: TranslateParser, useFactory: translateParserFactory },
{ provide: MissingTranslationHandler, useClass: InterpolatedMissingTranslationHandler }
];
Yes, you need to use:
Hello {name}
(Sorry, I'm on mobile)
Ok, thx for the clarification!
<span>{{ 'Hello { name }' | translate: { name: 'Kim' } }}</span> seems to work, <span translate [translateParams]="{name: 'Kim'}">Hello { name }</span> does not work...
Fair enough for now.
Hi,
I know this is an old issue, but any one figure out how to translate plural/gender with full text as translation key ?
Most helpful comment
If you want, you can close this. It's possible to use real strings as base language (with working interpolation) using custom TranslateParser and MissingTranslationHandler, although it's not trivial to do for beginners.
app/app.module.ts
i18n/index.ts