Browse Source

Added support for chinese language.

pull/723/head
Sebastian 5 years ago
parent
commit
594b976ad1
  1. 2
      backend/i18n/source/backend_it.json
  2. 1
      backend/i18n/source/backend_nl.json
  3. 4
      backend/i18n/source/backend_zh.json
  4. 8
      backend/i18n/source/frontend_it.json
  5. 8
      backend/i18n/source/frontend_nl.json
  6. 28
      backend/i18n/translator/Squidex.Translator/Commands.cs
  7. 35
      backend/i18n/translator/Squidex.Translator/Processes/Helper.cs
  8. 2
      backend/src/Squidex/Config/Web/WebExtensions.cs
  9. 6
      frontend/app/framework/utils/cookies.ts
  10. 9
      frontend/app/framework/utils/date-helper.ts
  11. 3
      frontend/app/shared/state/ui-languages.ts
  12. 10
      frontend/app/shell/pages/internal/profile-menu.component.html
  13. 14
      frontend/app/shell/pages/internal/profile-menu.component.ts

2
backend/i18n/source/backend_it.json

@ -115,7 +115,6 @@
"common.success": "Successo", "common.success": "Successo",
"common.text": "Testo", "common.text": "Testo",
"common.trigger": "Trigger", "common.trigger": "Trigger",
"common.url": "URL",
"common.warning": "Warning", "common.warning": "Warning",
"common.workflow": "Workflow", "common.workflow": "Workflow",
"common.workflowStep": "Step", "common.workflowStep": "Step",
@ -171,7 +170,6 @@
"contents.validation.normalCharactersBetween": "Deve essere un testo tra {min} e {max} carattere(i).", "contents.validation.normalCharactersBetween": "Deve essere un testo tra {min} e {max} carattere(i).",
"contents.validation.notAllowed": "Non è un valore consentito.", "contents.validation.notAllowed": "Non è un valore consentito.",
"contents.validation.pattern": "Deve seguire il pattern.", "contents.validation.pattern": "Deve seguire il pattern.",
"contents.validation.reference": "La geolocalizzazione può avere come campi solamente come latitudine e longitudine.",
"contents.validation.referenceNotFound": "Contiene un collegamento '{id}' non valido.", "contents.validation.referenceNotFound": "Contiene un collegamento '{id}' non valido.",
"contents.validation.referenceToInvalidSchema": "Contiene dei collegamenti '{id}' ad uno schema errato.", "contents.validation.referenceToInvalidSchema": "Contiene dei collegamenti '{id}' ad uno schema errato.",
"contents.validation.regexTooSlow": "La regular expression è troppo lenta.", "contents.validation.regexTooSlow": "La regular expression è troppo lenta.",

1
backend/i18n/source/backend_nl.json

@ -112,7 +112,6 @@
"common.signup": "Aanmelden", "common.signup": "Aanmelden",
"common.text": "Tekst", "common.text": "Tekst",
"common.trigger": "Trigger", "common.trigger": "Trigger",
"common.url": "URL",
"common.workflow": "Workflow", "common.workflow": "Workflow",
"common.workflowStep": "Stap", "common.workflowStep": "Stap",
"common.workflowTransition": "Overgang", "common.workflowTransition": "Overgang",

4
backend/i18n/source/backend_zh.json

@ -250,13 +250,9 @@
"schemas.dateTimeCalculatedDefaultAndDefaultError": "计算出的默认值和默认值不能一起使用。", "schemas.dateTimeCalculatedDefaultAndDefaultError": "计算出的默认值和默认值不能一起使用。",
"schemas.duplicateFieldName": "字段 '{field}' 已添加两次。", "schemas.duplicateFieldName": "字段 '{field}' 已添加两次。",
"schemas.fieldCannotBeUIField": "字段不能是 UI 字段。", "schemas.fieldCannotBeUIField": "字段不能是 UI 字段。",
"schema.fieldIsLocked": "Schema字段被锁定。",
"schemas.fieldNameAlreadyExists": "已存在同名字段。", "schemas.fieldNameAlreadyExists": "已存在同名字段。",
"schema.fieldNotInSchema": "字段不是Schema的一部分。",
"schemas.fieldsNotCovered": "字段 ID 未涵盖所有字段。", "schemas.fieldsNotCovered": "字段 ID 未涵盖所有字段。",
"schemas.nameAlreadyExists": "一个同名的Schema已经存在。", "schemas.nameAlreadyExists": "一个同名的Schema已经存在。",
"schema.noPermission": "您没有此Schema的权限。",
"schema.notFoundId": "Schema {id} 不存在。",
"schemas.number.inlineEditorError": "无线电编辑器不允许内联编辑。", "schemas.number.inlineEditorError": "无线电编辑器不允许内联编辑。",
"schemas.onlyArraysHaveNested": "只有数组字段可以有嵌套字段。", "schemas.onlyArraysHaveNested": "只有数组字段可以有嵌套字段。",
"schemas.onylArraysInRoot": "嵌套字段不能是数组字段。", "schemas.onylArraysInRoot": "嵌套字段不能是数组字段。",

8
backend/i18n/source/frontend_it.json

@ -588,7 +588,6 @@
"roles.revokeFailed": "Non è stato possibile rimuovere il ruolo. Per favore ricarica.", "roles.revokeFailed": "Non è stato possibile rimuovere il ruolo. Per favore ricarica.",
"roles.roleNamePlaceholder": "Inserisci il nome del ruolo", "roles.roleNamePlaceholder": "Inserisci il nome del ruolo",
"roles.updateFailed": "Non è stato possibile aggiornare il ruolo. Per favore ricarica.", "roles.updateFailed": "Non è stato possibile aggiornare il ruolo. Per favore ricarica.",
"rules.actionEdit": "Modifica l'Azione",
"rules.cancelFailed": "Non è stato possibile eliminare la regola. Per favore ricarica.", "rules.cancelFailed": "Non è stato possibile eliminare la regola. Per favore ricarica.",
"rules.create": "Crea un nuova Regola", "rules.create": "Crea un nuova Regola",
"rules.createFailed": "Non è stato possibile creare una nuova regola. Per favore ricarica.", "rules.createFailed": "Non è stato possibile creare una nuova regola. Per favore ricarica.",
@ -596,10 +595,8 @@
"rules.deleteConfirmText": "Sei sicuro di voler eliminare la regola?", "rules.deleteConfirmText": "Sei sicuro di voler eliminare la regola?",
"rules.deleteConfirmTitle": "Cancella la regola", "rules.deleteConfirmTitle": "Cancella la regola",
"rules.deleteFailed": "Non è stato possibile eliminare la regola. Per favore ricarica.", "rules.deleteFailed": "Non è stato possibile eliminare la regola. Per favore ricarica.",
"rules.disableFailed": "Non è stato possibile disabilitare la regola. Per favore ricarica.",
"rules.empty": "Nessuna regola è stato ancora creata.", "rules.empty": "Nessuna regola è stato ancora creata.",
"rules.emptyAddRule": "Aggiungi una regola", "rules.emptyAddRule": "Aggiungi una regola",
"rules.enableFailed": "Non è stato possibile abilitare la regola. Per favore ricarica.",
"rules.enqueued": "La regola è stata aggiunta alle code.", "rules.enqueued": "La regola è stata aggiunta alle code.",
"rules.listPageTitle": "Regole", "rules.listPageTitle": "Regole",
"rules.loadFailed": "Non è stato possibile caricare le regole. Per favore ricarica.", "rules.loadFailed": "Non è stato possibile caricare le regole. Per favore ricarica.",
@ -629,14 +626,9 @@
"rules.stop": "La regola si fermerà al più presto.", "rules.stop": "La regola si fermerà al più presto.",
"rules.triggerConfirmText": "Sei sicuro che voler attivare la regola?", "rules.triggerConfirmText": "Sei sicuro che voler attivare la regola?",
"rules.triggerConfirmTitle": "Attiva la regola", "rules.triggerConfirmTitle": "Attiva la regola",
"rules.triggerEdit": "Modifica l'Attivazione",
"rules.triggerFailed": "Non è stato possibile attivare la regola. Per favore ricarica.", "rules.triggerFailed": "Non è stato possibile attivare la regola. Per favore ricarica.",
"rules.unnamed": "Regola senza nome", "rules.unnamed": "Regola senza nome",
"rules.updateFailed": "Non è stato possibile aggiornare la regola. Per favore ricarica.", "rules.updateFailed": "Non è stato possibile aggiornare la regola. Per favore ricarica.",
"rules.wizard.actionHint": "La selezione del tipo di azione non potrà essere modificata successivamente.",
"rules.wizard.selectAction": "Seleziona l'Azione",
"rules.wizard.selectTrigger": "Seleziona l'Attivazione",
"rules.wizard.triggerHint": "La selezione del tipo di attivazione non potrà essere modificata successivamente.",
"schemas.addField": "Aggiungi un Campo", "schemas.addField": "Aggiungi un Campo",
"schemas.addFieldAndClose": "Crea e chiudi", "schemas.addFieldAndClose": "Crea e chiudi",
"schemas.addFieldAndCreate": "Crea e aggiungi il campo", "schemas.addFieldAndCreate": "Crea e aggiungi il campo",

8
backend/i18n/source/frontend_nl.json

@ -560,7 +560,6 @@
"roles.revokeFailed": "Kan rol niet intrekken. Laad opnieuw.", "roles.revokeFailed": "Kan rol niet intrekken. Laad opnieuw.",
"roles.roleNamePlaceholder": "Voer de rolnaam in", "roles.roleNamePlaceholder": "Voer de rolnaam in",
"roles.updateFailed": "Update rol mislukt. Laad opnieuw.", "roles.updateFailed": "Update rol mislukt. Laad opnieuw.",
"rules.actionEdit": "Bewerk actie",
"rules.cancelFailed": "Annuleren van regel is mislukt. Laad opnieuw.", "rules.cancelFailed": "Annuleren van regel is mislukt. Laad opnieuw.",
"rules.create": "Maak een nieuwe regel", "rules.create": "Maak een nieuwe regel",
"rules.createFailed": "Maken van regel is mislukt. Laad opnieuw.", "rules.createFailed": "Maken van regel is mislukt. Laad opnieuw.",
@ -568,10 +567,8 @@
"rules.deleteConfirmText": "Wil je de regel echt verwijderen?", "rules.deleteConfirmText": "Wil je de regel echt verwijderen?",
"rules.deleteConfirmTitle": "Regel verwijderen", "rules.deleteConfirmTitle": "Regel verwijderen",
"rules.deleteFailed": "Verwijderen van regel is mislukt. Laad opnieuw.", "rules.deleteFailed": "Verwijderen van regel is mislukt. Laad opnieuw.",
"rules.disableFailed": "Kan regel niet uitschakelen. Laad opnieuw.",
"rules.empty": "Nog geen regel aangemaakt.", "rules.empty": "Nog geen regel aangemaakt.",
"rules.emptyAddRule": "Regel toevoegen", "rules.emptyAddRule": "Regel toevoegen",
"rules.enableFailed": "Kan regel niet inschakelen. Laad opnieuw.",
"rules.enqueued": "Regel is toegevoegd aan de wachtrij.", "rules.enqueued": "Regel is toegevoegd aan de wachtrij.",
"rules.listPageTitle": "Regels", "rules.listPageTitle": "Regels",
"rules.loadFailed": "Laden van regels is mislukt. Laad opnieuw.", "rules.loadFailed": "Laden van regels is mislukt. Laad opnieuw.",
@ -600,14 +597,9 @@
"rules.stop": "Regel stopt binnenkort.", "rules.stop": "Regel stopt binnenkort.",
"rules.triggerConfirmText": "Wil je echt de regel activeren?", "rules.triggerConfirmText": "Wil je echt de regel activeren?",
"rules.triggerConfirmTitle": "Trigger regel", "rules.triggerConfirmTitle": "Trigger regel",
"rules.triggerEdit": "Trigger bewerken",
"rules.triggerFailed": "Kan regel niet activeren. Laad opnieuw.", "rules.triggerFailed": "Kan regel niet activeren. Laad opnieuw.",
"rules.unnamed": "Naamloos regel", "rules.unnamed": "Naamloos regel",
"rules.updateFailed": "Update regel mislukt. Laad opnieuw.", "rules.updateFailed": "Update regel mislukt. Laad opnieuw.",
"rules.wizard.actionHint": "De selectie van het actietype kan later niet worden gewijzigd.",
"rules.wizard.selectAction": "Selecteer actie",
"rules.wizard.selectTrigger": "Selecteer Trigger",
"rules.wizard.triggerHint": "De selectie van het triggertype kan later niet worden gewijzigd.",
"schemas.addField": "Veld toevoegen", "schemas.addField": "Veld toevoegen",
"schemas.addFieldAndClose": "Maken en sluiten", "schemas.addFieldAndClose": "Maken en sluiten",
"schemas.addFieldAndCreate": "Maak en voeg veld toe", "schemas.addFieldAndCreate": "Maak en voeg veld toe",

28
backend/i18n/translator/Squidex.Translator/Commands.cs

@ -89,6 +89,26 @@ namespace Squidex.Translator
new GenerateFrontendResources(folder, service).Run(); new GenerateFrontendResources(folder, service).Run();
} }
[Command(Name = "clean-backend", Description = "Clean the backend translations.")]
public void CleanBackend(TranslateArguments arguments)
{
var (folder, service) = Setup(arguments, "backend");
Helper.CleanOtherLocales(service);
service.Save();
}
[Command(Name = "clean-frontend", Description = "Clean the frontend translations.")]
public void CleanFrontend(TranslateArguments arguments)
{
var (folder, service) = Setup(arguments, "frontend");
Helper.CleanOtherLocales(service);
service.Save();
}
[Command(Name = "gen-keys", Description = "Generate the keys for translations.")] [Command(Name = "gen-keys", Description = "Generate the keys for translations.")]
public void GenerateBackendKeys(TranslateArguments arguments) public void GenerateBackendKeys(TranslateArguments arguments)
{ {
@ -124,18 +144,18 @@ namespace Squidex.Translator
throw new ArgumentException("Folder does not exist."); throw new ArgumentException("Folder does not exist.");
} }
var supportedLocaled = new string[] { "en", "nl", "it" }; var supportedLocales = new string[] { "en", "nl", "it", "zh" };
var locales = supportedLocaled; var locales = supportedLocales;
if (arguments.Locales != null && arguments.Locales.Any()) if (arguments.Locales != null && arguments.Locales.Any())
{ {
locales = supportedLocaled.Intersect(arguments.Locales).ToArray(); locales = supportedLocales.Intersect(arguments.Locales).ToArray();
} }
if (locales.Length == 0) if (locales.Length == 0)
{ {
locales = supportedLocaled; locales = supportedLocales;
} }
var translationsDirectory = new DirectoryInfo(Path.Combine(arguments.Folder, "backend", "i18n")); var translationsDirectory = new DirectoryInfo(Path.Combine(arguments.Folder, "backend", "i18n"));

35
backend/i18n/translator/Squidex.Translator/Processes/Helper.cs

@ -30,9 +30,9 @@ namespace Squidex.Translator.Processes
Console.WriteLine("----- CHECKING <{0}> -----", locale); Console.WriteLine("----- CHECKING <{0}> -----", locale);
var notTranslated = mainTranslations.Keys.Except(texts.Keys).ToList(); var notTranslated = mainTranslations.Keys.Except(texts.Keys).ToList();
var notRequired = texts.Keys.Except(mainTranslations.Keys).ToList(); var notUsed = texts.Keys.Except(mainTranslations.Keys).ToList();
if (notTranslated.Count > 0 || notRequired.Count > 0) if (notTranslated.Count > 0 || notUsed.Count > 0)
{ {
if (notTranslated.Count > 0) if (notTranslated.Count > 0)
{ {
@ -46,12 +46,12 @@ namespace Squidex.Translator.Processes
} }
} }
if (notRequired.Count > 0) if (notUsed.Count > 0)
{ {
Console.WriteLine(); Console.WriteLine();
Console.WriteLine("Translations not used:"); Console.WriteLine("Translations not used:");
foreach (var key in notRequired.OrderBy(x => x)) foreach (var key in notUsed.OrderBy(x => x))
{ {
Console.Write(" * "); Console.Write(" * ");
Console.WriteLine(key); Console.WriteLine(key);
@ -65,6 +65,33 @@ namespace Squidex.Translator.Processes
} }
} }
public static void CleanOtherLocales(TranslationService service)
{
var mainTranslations = service.MainTranslations;
foreach (var (locale, texts) in service.Translations.Where(x => x.Key != service.MainLocale))
{
Console.WriteLine();
Console.WriteLine("----- CLEANING <{0}> -----", locale);
var notUsed = texts.Keys.Except(mainTranslations.Keys).ToList();
if (notUsed.Count > 0)
{
foreach (var unused in notUsed)
{
texts.Remove(unused);
}
Console.WriteLine("Cleaned {0} translations.", notUsed.Count);
}
else
{
Console.WriteLine("> No errors found");
}
}
}
public static void CheckUnused(TranslationService service, HashSet<string> translations) public static void CheckUnused(TranslationService service, HashSet<string> translations)
{ {
var notUsed = new SortedSet<string>(); var notUsed = new SortedSet<string>();

2
backend/src/Squidex/Config/Web/WebExtensions.cs

@ -39,7 +39,7 @@ namespace Squidex.Config.Web
public static IApplicationBuilder UseSquidexLocalization(this IApplicationBuilder app) public static IApplicationBuilder UseSquidexLocalization(this IApplicationBuilder app)
{ {
var supportedCultures = new[] { "en", "nl", "it" }; var supportedCultures = new[] { "en", "nl", "it", "zh" };
var localizationOptions = new RequestLocalizationOptions() var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0]) .SetDefaultCulture(supportedCultures[0])

6
frontend/app/framework/utils/cookies.ts

@ -20,6 +20,12 @@ export module Cookies {
document.cookie = `${name}=${value || ''}${expires}; path=/`; document.cookie = `${name}=${value || ''}${expires}; path=/`;
} }
export function replace(name: string, value: string, days: number) {
remove(name);
set(name, value, days);
}
export function remove(name: string) { export function remove(name: string) {
document.cookie = `${name}=; Max-Age=-99999999;`; document.cookie = `${name}=; Max-Age=-99999999;`;
} }

9
frontend/app/framework/utils/date-helper.ts

@ -5,12 +5,17 @@
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/ */
import { enUS, it, nl } from 'date-fns/locale'; import { enUS, it, nl, zhCN } from 'date-fns/locale';
export module DateHelper { export module DateHelper {
let locale: string | null; let locale: string | null;
export const FNSLOCALES = { enUS, it, nl }; export const FNSLOCALES = {
en: enUS,
it,
nl,
zh: zhCN,
};
export function setlocale(code: string | null) { export function setlocale(code: string | null) {
locale = code; locale = code;

3
frontend/app/shared/state/ui-languages.ts

@ -17,5 +17,8 @@ export module UILanguages {
}, { }, {
iso2Code: 'it', iso2Code: 'it',
localName: 'Italiano', localName: 'Italiano',
}, {
iso2Code: 'zh',
localName: '中国人',
}]; }];
} }

10
frontend/app/shell/pages/internal/profile-menu.component.html

@ -5,7 +5,7 @@
</a> </a>
</li> </li>
<li class="nav-item nav-icon dropdown" #button> <li class="nav-item nav-icon dropdown" #button>
<span class="nav-link dropdown-toggle" (click)="modalMenu.toggle()"> <span class="nav-link dropdown-toggle" (click)="toggleProfile()">
<span class="user"> <span class="user">
<img class="user-picture" [src]="snapshot.profileId | sqxUserIdPicture"> <img class="user-picture" [src]="snapshot.profileId | sqxUserIdPicture">
</span> </span>
@ -13,9 +13,9 @@
</li> </li>
</ul> </ul>
<ng-container *sqxModal="modalMenu;onRoot:false"> <ng-container *sqxModal="modalMenu;onRoot:false;closeAlways:true">
<div class="dropdown-menu" [sqxAnchoredTo]="button" [offset]="10" @fade> <div class="dropdown-menu" [sqxAnchoredTo]="button" [offset]="10" @fade>
<a class="dropdown-item dropdown-info" [sqxPopupLink]="snapshot.profileUrl" (click)="modalMenu.hide()"> <a class="dropdown-item dropdown-info" [sqxPopupLink]="snapshot.profileUrl">
<div>{{ 'profile.userEmail' | sqxTranslate }}</div> <div>{{ 'profile.userEmail' | sqxTranslate }}</div>
<strong>{{snapshot.profileEmail}}</strong> <strong>{{snapshot.profileEmail}}</strong>
@ -27,12 +27,12 @@
{{ 'common.administration' | sqxTranslate }} {{ 'common.administration' | sqxTranslate }}
</a> </a>
<a class="dropdown-item" [sqxPopupLink]="snapshot.profileUrl" (click)="modalMenu.hide()"> <a class="dropdown-item" [sqxPopupLink]="snapshot.profileUrl">
{{ 'profile.title' | sqxTranslate }} {{ 'profile.title' | sqxTranslate }}
</a> </a>
<div class="dropdown-submenu"> <div class="dropdown-submenu">
<a class="dropdown-item dropdown-toggle" (click)="toggle()"> <a class="dropdown-item dropdown-toggle" (click)="toggleSubmenu()" sqxStopClick>
{{ 'common.language' | sqxTranslate }} {{ 'common.language' | sqxTranslate }}
</a> </a>

14
frontend/app/shell/pages/internal/profile-menu.component.ts

@ -73,14 +73,22 @@ export class ProfileMenuComponent extends StatefulComponent<State> implements On
} }
public changeLanguage(code: string) { public changeLanguage(code: string) {
Cookies.remove('.AspNetCore.Culture'); Cookies.replace('.AspNetCore.Culture', `c=${code}|uic=${code}`, 365);
Cookies.set('.AspNetCore.Culture', `c=${code}|uic=${code}`, 365);
// eslint-disable-next-line no-restricted-globals // eslint-disable-next-line no-restricted-globals
location.reload(); location.reload();
} }
public toggle() { public toggleProfile() {
this.modalMenu.toggle();
this.next(s => ({
...s,
showSubmenu: false,
}));
}
public toggleSubmenu() {
this.next(s => ({ this.next(s => ({
...s, ...s,
showSubmenu: !s.showSubmenu, showSubmenu: !s.showSubmenu,

Loading…
Cancel
Save