Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: implements i18n #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/out-tsc

# generated content
content.json
content.*.json

# dependencies
/node_modules
Expand Down
44 changes: 44 additions & 0 deletions TRANSLATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Translation Guide

## Add languages

The following tasks are required to add a new language.
[See available code here](https://github.com/angular/angular/tree/master/packages/common/locales).

- Copy production into the configurations section of angular.json to create production build settings for the language.
- Add rewrites for the language to the `rewrites` of `firebase.json`.
- Add languages ​​to the languages ​​in `xliffmerge.json` (And do `yarn i18n`).
- Add languages ​​to `langages`, an array of `tools/utils.ts` files.
- Let's make build environment for language in `build:ssr` in scripts of package.json.
- Register localeData of the language to be added to `app.module.ts` using `registerLocaleData()`.
https://angular.io/guide/i18n#i18n-pipes
- Add a language to the languages propety of `src/app/shared/footer/footer.component.ts`.
- Make a target language directory by copying `en-US` in the content directory. And then run `yarn build-content`.

Hooray! Now you can choose a new language.

## Do translation

There are two types of translation: translation of the application using angular i18n and translation of the main content composed of markdown.

### Application translation

Please read the [angular i18n](https://angular.io/guide/i18n) documentation once.

Translate the app by editing `src/locale/messages.[language code].xlf`.
It is difficult to edit xlf file manually, so use something like a tool.

Tool Example: https://poedit.net/

### Translation of content

Translation of content is editing files in the `content/[target lang]` directory.

You don't have to make all the files at once. but when it's missing it will be displayed in original English.

**Note:** If you set char such as `*` or `@` at the beginning of metadata such as `title:`, the translation will be broken.
Use double-byte characters or devise a text.

## Reflect the translated content

See [CONTRIBUTING.md](https://github.com/angular-checklist/angular-checklist/blob/master/CONTRIBUTING.md).
26 changes: 25 additions & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,31 @@
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true
"buildOptimizer": true,
"outputPath": "dist/browser/en-US",
"baseHref": "/en-US/"
},
"ja": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"outputPath": "dist/browser/ja",
"baseHref": "/ja/",
"i18nFile": "src/locale/messages.ja.xlf",
"i18nFormat": "xlf",
"i18nLocale": "ja"
}
}
},
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
17 changes: 15 additions & 2 deletions firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,23 @@
"**/node_modules/**"
],
"rewrites": [
{
"source": "/en-US/**",
"destination": "/en-US/index.html"
},
{
"source": "/ja/**",
"destination": "/ja/index.html"
},
{
"source": "**",
"destination": "/index.html"
"destination": "/en-US/index.html"
}
]
],
"redirects": [{
"source" : "/",
"destination" : "/en-US",
"type" : 301
}]
}
}
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"ng": "ng",
"start": "concurrently \"ng serve\" \"yarn build-content:watch\"",
"build": "ng build",
"build:ssr": "ng build --prod && ng run angular-checklist:server -- --output-hashing=none",
"build:ssr": "ng build --prod && ng build -c ja && ng run angular-checklist:server -- --output-hashing=none",
"prerender": "npm run build:ssr && ts-node prerender.ts",
"serve:ssr": "npm run prerender && http-server dist/browser",
"test": "ng test",
Expand All @@ -16,7 +16,8 @@
"ci": "npm run build-content && ng build --prod",
"format:base": "prettier \"{src,tools,cypress}/**/*{.ts,.js,.json,.html}\"",
"format:check": "npm run format:base -- --list-different",
"format:fix": "npm run format:base -- --write"
"format:fix": "npm run format:base -- --write",
"i18n": "ng xi18n --output-path locale/ --i18n-locale en && xliffmerge --profile xliffmerge.json"
},
"husky": {
"hooks": {
Expand Down Expand Up @@ -58,6 +59,7 @@
"highlight.js": "^9.13.1",
"lodash.groupby": "^4.6.0",
"ngrx-store-localstorage": "^5.1.0",
"ngx-i18nsupport": "^0.17.1",
"normalize.css": "^8.0.0",
"rxjs": "^6.3.3",
"tslib": "^1.9.0",
Expand Down
2 changes: 1 addition & 1 deletion prerender.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ enableProdMode();

const ROUTES = ['/', '/checklist'];
const DIST_FOLDER = join(process.cwd(), 'dist');
const BROWSER_FOLDER = join(DIST_FOLDER, 'browser');
const BROWSER_FOLDER = join(DIST_FOLDER, 'browser/en-US');

const index = readFileSync(join(BROWSER_FOLDER, 'index.html'), 'utf8');

Expand Down
17 changes: 13 additions & 4 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import { NgModule } from '@angular/core';
import { NgModule, LOCALE_ID, Inject } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { registerLocaleData } from '@angular/common';
import localeJa from '@angular/common/locales/ja';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { PreloadAllModules, RouterModule } from '@angular/router';
import { StoreRouterConnectingModule } from '@ngrx/router-store';
import { StoreModule } from '@ngrx/store';
import { StoreModule, Store } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '../environments/environment';
import { AppComponent } from './app.component';
import { APP_ROUTES } from './app.routes';
import { ChecklistModule } from './checklist/checklist.module';
import { CustomMaterialModule } from './custom-material.module';
import { ProjectsModule } from './projects/projects.module';
import { META_REDUCERS, ROOT_REDUCER } from './state/app.state';
import { META_REDUCERS, ROOT_REDUCER, ApplicationState } from './state/app.state';
import { SetLangageCode } from './checklist/state/checklist.actions';

registerLocaleData(localeJa, 'ja');

@NgModule({
declarations: [AppComponent],
Expand All @@ -33,4 +38,8 @@ import { META_REDUCERS, ROOT_REDUCER } from './state/app.state';
],
bootstrap: [AppComponent]
})
export class AppModule {}
export class AppModule {
constructor(@Inject(LOCALE_ID) locale: string, store: Store<ApplicationState>) {
store.dispatch(new SetLangageCode(locale));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
<div class="filters" *ngIf="filter">
<button class="filter" mat-button (click)="filterChange.emit('ALL')" [class.active]="filter === 'ALL'">
<mat-icon>assignment</mat-icon>
ALL
<ng-container i18n="@@checlistCtaBarAll">ALL</ng-container>
</button>
<button class="filter" mat-button (click)="filterChange.emit('DONE')" [class.active]="filter === 'DONE'">
<mat-icon>done</mat-icon>
DONE
<ng-container i18n="@@checlistCtaBarDone">DONE</ng-container>
</button>
<button class="filter" mat-button (click)="filterChange.emit('TODO')" [class.active]="filter === 'TODO'">
<mat-icon>check_box_outline_blank</mat-icon>
TODO
<ng-container i18n="@@checlistCtaBarToto">TODO</ng-container>
</button>
</div>
<div class="cta-buttons" *ngIf="showActionButtons">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<ng-container *ngIf="(item$ | async) as item">
<header>
<mat-checkbox color="primary" (click)="toggleItem(item)" [checked]="item.checked">Done</mat-checkbox>
<mat-checkbox color="primary" (click)="toggleItem(item)" [checked]="item.checked" i18n="@@checkListDetailDone"
>Done</mat-checkbox
>
<ac-checklist-favorite-button
(toggle)="toggleFavorite(item)"
[active]="item.favorite"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ <h4>{{ favorite.category.title }}</h4>
<ng-template #noFavorites>
<div class="no-favorites">
<img src="assets/undraw_no_data.svg" alt="No Data" />
<span>You have no favorites yet... but they are only a few clicks away!</span>
<span i18n="@@checklistViewNoFavorites">You have no favorites yet... but they are only a few clicks away!</span>
</div>
</ng-template>
</ng-container>
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
<a class="info author" [href]="author.url" *ngIf="author">{{ author.name }}</a>
<a class="info link" [href]="source" *ngIf="source">Source</a>
<a class="info link" [href]="source" *ngIf="source" i18n="@@checklistMetadataSource">Source</a>
13 changes: 9 additions & 4 deletions src/app/checklist/checklist.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
bindValue="id"
>
<ac-dropdown-static-options>
<ac-dropdown-static-option routerLink="/"> <mat-icon>edit</mat-icon> Manage Projects </ac-dropdown-static-option>
<ac-dropdown-static-option routerLink="/">
<mat-icon>edit</mat-icon> <ng-container i18n="@@confirmDialogManageProjects">Manage Projects</ng-container>
</ac-dropdown-static-option>
</ac-dropdown-static-options>
</ac-dropdown>
<ac-checklist-search *ngIf="(mediumUp$ | async)"></ac-checklist-search>
Expand All @@ -26,15 +28,16 @@
[matBadgeHidden]="!(favoritesCount$ | async)"
matBadgeColor="accent"
matBadgeOverlap="false"
i18n="@@confirmDialogFavorites"
>Favorites</span
>
</a>
</nav>
</section>
<section class="category-list-wrapper">
<div class="section-header">
<h4>CATEGORIES</h4>
<mat-slide-toggle (change)="toggleEditMode()">Edit</mat-slide-toggle>
<h4 i18n="@@confirmDialogHeader">CATEGORIES</h4>
<mat-slide-toggle (change)="toggleEditMode()" i18n="@@confirmDialogEdit">Edit</mat-slide-toggle>
</div>
<div class="category-list">
<nav class="category" *ngFor="let category of (categories$ | async); trackBy: trackBySlug">
Expand All @@ -61,7 +64,9 @@ <h4>CATEGORIES</h4>
</mat-sidenav>
<mat-sidenav-content>
<div class="scroll-container"><router-outlet></router-outlet></div>
<div *ngIf="editMode" class="overlay"><span>🧐 Ups, seems like you're in edit mode!</span></div>
<div *ngIf="editMode" class="overlay">
<span i18n="@@confirmDialogUpsEditMode">🧐 Ups, seems like you're in edit mode!</span>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
<ac-footer></ac-footer>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<h1 mat-dialog-title>{{ data.title }}</h1>
<div mat-dialog-content>{{ data.text }}</div>
<div mat-dialog-actions align="end">
<button mat-button [mat-dialog-close]="false">Cancel</button>
<button mat-button [mat-dialog-close]="false" i18n="@@confirmDialogCancel">Cancel</button>
<button mat-button color="warn" [mat-dialog-close]="true" cdkFocusInitial>{{ data.buttonText }}</button>
</div>
11 changes: 9 additions & 2 deletions src/app/checklist/state/checklist.actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { ChecklistFilter } from '../models/checklist.model';
export enum ChecklistActionTypes {
SET_CATEGORIES_FILTER = '[Checklist] set categories filter',
SET_FAVORITES_FILTER = '[Checklist] set favroites filter',
TOGGLE_EDIT_MODE = '[Checklist] toggle edit mode'
TOGGLE_EDIT_MODE = '[Checklist] toggle edit mode',
SET_LANG_CODE = '[Checklist] set langage code '
}

export class SetCategoriesFilter implements Action {
Expand All @@ -25,4 +26,10 @@ export class ToggleEditMode implements Action {
constructor() {}
}

export type ChecklistActions = SetCategoriesFilter | SetFavoritesFilter | ToggleEditMode;
export class SetLangageCode implements Action {
readonly type = ChecklistActionTypes.SET_LANG_CODE;

constructor(public payload: string) {}
}

export type ChecklistActions = SetCategoriesFilter | SetFavoritesFilter | ToggleEditMode | SetLangageCode;
8 changes: 7 additions & 1 deletion src/app/checklist/state/checklist.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Filter } from '../models/checklist.model';
import { ChecklistActions, ChecklistActionTypes } from './checklist.actions';
import { ChecklistState } from './checklist.state';

const CHECKLIST = require('../../../assets/content.json');
const CHECKLIST = require('../../../assets/content.en-US.json');

export const INITIAL_STATE: ChecklistState = {
...CHECKLIST,
Expand All @@ -26,6 +26,12 @@ export function checklistReducer(state = INITIAL_STATE, action: ChecklistActions
...state,
editMode: !state.editMode
};
case ChecklistActionTypes.SET_LANG_CODE:
return {
...state,
...require(`../../../assets/content.${action.payload || 'en-US'}.json`),
editMode: !state.editMode
};
default:
return state;
}
Expand Down
26 changes: 19 additions & 7 deletions src/app/projects/project-dialog/project-dialog.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,34 @@ <h1 mat-dialog-title>
type="text"
/>
<mat-hint align="end">{{ projectName.value?.length || 0 }}/{{ maxLength }}</mat-hint>
<mat-error *ngIf="projectName.hasError('projectExists')">Project already exists</mat-error>
<mat-error *ngIf="projectName.hasError('projectExists')" i18n="@@projectDialogExistsError"
>Project already exists</mat-error
>
<mat-spinner *ngIf="projectName.pending" diameter="20" color="primary" matSuffix></mat-spinner>
</mat-form-field>
</div>
<div class="danger-zone-wrapper" *ngIf="isEditMode()">
<h4>DANGER ZONE</h4>
<h4 i18n="@@projectDialogDengerZoneSection">DANGER ZONE</h4>
<ul class="danger-zone">
<li class="danger-zone-cta">
<span class="danger-zone-cta-title">Delete Project</span>
<span class="danger-zone-cta-title" i18n="@@projectDialogDeleteProject">Delete Project</span>
<div class="danger-zone-cta-content">
<p>Once you delete a project, there is no going back. Please be certain.</p>
<p i18n="@@projectDialogConfirmMessage">
Once you delete a project, there is no going back. Please be certain.
</p>
<mat-form-field>
<input matInput [formControl]="verifyProjectName" type="text" />
<mat-hint align="end">Please type in the project name to confirm.</mat-hint>
<mat-hint align="end" i18n="@@projectDialogConfirmMessageHint"
>Please type in the project name to confirm.</mat-hint
>
</mat-form-field>
<button (click)="deleteProject()" [disabled]="!verifyProjectName.valid" mat-raised-button color="warn">
<button
(click)="deleteProject()"
[disabled]="!verifyProjectName.valid"
mat-raised-button
color="warn"
i18n="@@projectDialogSubmitButton"
>
Delete this Project
</button>
</div>
Expand All @@ -38,7 +50,7 @@ <h4>DANGER ZONE</h4>
</div>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button [mat-dialog-close]="null">Cancel</button>
<button mat-button [mat-dialog-close]="null" i18n="@@projectDialogCancel">Cancel</button>
<button
mat-raised-button
color="primary"
Expand Down
Loading