iperf3 測試網路速度

閱讀 指令式的網路速度測試工具 iPerf3 ,揪出網路頻寬真實的一面 以後做的小摘錄。

簡單說用法,因為是要測試內部網路的網路速度,所以要兩台電腦。一台執行

iperf3 -s

一台執行

iperf3 -c <server_ip>

這樣就可以了。也有公用的伺服器可以測,這樣就要一台電腦就行 (用 ipef3 -c <server_ip>),亞洲區只有兩台,一台在中亞(哈薩克),一台在印尼,要注意,使用公用伺服器的話,測出來的速度並不是網路內部電腦間的速度,而是電腦到Router到外部伺服器的速度。

flutter stable/beta 並存

簡單說,有專案因為怕被影響到,只想用 stable 來建置,不想用 beta,可是又想要試驗 flutter web ,而 flutter web 又只有 beta channel 才有,所以想讓他們並存。

其實意外的簡單,就只是放在不同目錄,只要在使用的時候小心,不要用到不對的 flutter 就行,在 terminal 直接下指令的話,會需要特別注意。

# 切到你要放 flutter beta channel 的資料夾
git clone https://github.com/flutter/flutter.git flutter-beta -b beta
cd flutter-beta/bin
./flutter precache
./flutter config —enable-web
./flutter devices

在 Android Studio 建立 flutter project 時,會問 flutter SDK 路徑,把路徑指到剛剛放 flutter beta channel 的位置,就可以了。

Visual Studio Code 的話,需要改 workspace preferences ,改裡面的 dart.flutterSdkPath (來源1 / 來源2 )

"settings": {
"dart.flutterSdkPath": "/Users/youruser/flutter-beta"
}

直接用指令的話,就要確定 PATH 是對的,這時候可以預先寫好環境變數檔案,然後用 source 來處理

# flutter-stable.env
export PATH=/Users/youruser/flutter-stable:$PATH
# flutter-beta.env
export PATH=/Users/youruser/flutter-beta:$PATH
# 切換到 stable
source flutter-stable.env

# 切換到 beta
source flutter-beta.env

紀錄一下 MacOS 的中文輸入法

之前有找過一次了,今天又再找一次,這次把找的過程記錄下來。那這次為什麼要找呢?是因為小麥注音輸入法不知道為什麼當機終止了,選不到這個輸入法,想說找穩定的輸入法來使用。

之前換小麥注音輸入法的主因是因為我實在是無法適應 MacOS 的內建注音輸入法,用了一陣子還是無法適應,特別是打注音符號,就斷然放棄。

言歸正傳,目前可以找到的幾個:

  1. 小麥注音
  2. Yahoo!奇摩注音輸入法
  3. 超注音
  4. 香草輸入法 (沒有注音)
  5. 自然注音輸入法
  6. 鼠鬚管

小麥注音

用 homebrew 就可以安裝:brew install mcbopomofo

目前免費,沒有智慧選字,也沒有詞庫,按 shift+, 可以輸入全形標點符號。 網址:https://github.com/openvanilla/McBopomofo

Yahoo!奇摩注音輸入法

安裝需要手動,homebrew 以前有這個 cask,但是後來被移出去了。

目前免費,有智慧選字,輸入法程式沒有持續更新,Yahoo 已經將這整個輸入法開放原始碼了,安裝包是 zonble 大大熱心去編譯並打包的 (zonble大大就是OpenVilla香草輸入法/小麥注音輸入法的開發者)。 網址:https://github.com/zonble/ykk_installer/

按 shift+, 可以輸入全形標點符號

介紹:

超注音

安裝要繞個路,透過 Google Play,我猜想這是開發者要收費的緣故。價格:500 NTD

安裝方法:

  1. 使用 Android 手機,去 Google play 安裝 (超注音 for macOS)
  2. 開啟 app,裡面有操作說明,簡單的說,這包 apk 裡面有超注音的安裝程式,你要依照操作說明把這個安裝程式放到你的 macos 機器上,然後安裝。

網址:https://www.superkbd.com/

參考資料:超注音 for macOS 開放下載!為 Mac 再添一款輸入法

香草輸入法

安裝:brew install openvanilla

如果你需要倉頡、簡易(速成)、大易、行列、符號與日文假名、粵拼等輸入法,裝這個就對了,不過我沒用過。

網址:https://openvanilla.org/

自然注音輸入法

老牌的輸入法,要上官方網站購買,網址:https://www.goingpro.me/products

價格 2000 NTD,如果你有雙系統需求,可以考慮購買 Win+Mac 共通版,價格 3500 NTD,可以安裝在三台電腦上。

鼠鬚管

感謝推友 Ralphsun73221 的推薦。鼠鬚管就是只有注音的 RIME (Linux版是中州韻,Windows 版是小狼毫)。

安裝:brew cask install squirrel

介紹:【RIME 鼠鬚管注音版】Mac 中最好用的注音輸入法!

最終的選擇

之前是使用小麥注音輸入法,這個先保留,不移除。現在則是安裝了 Yahoo!奇摩注音輸入法來試用看看,未來如果不好用,再來考慮安裝鼠鬚管或是購買超注音或是購買自然注音輸入法。

剛剛使用,注意到一點,選字的游標位置不太一樣:

  • 小麥注音輸入法跟內建的注音輸入法,選字是選前個位置的字。
  • Windows/Linux 上的輸入法跟Yahoo!奇摩注音輸入法,選字是選後面位置的字。

筆記:Best practices for REST API design

來源:Best practices for REST API design

下面是看完以後,我的整理、摘要以及一點自己的想法:

  • 盡可能使用 JSON (application/json),除非有特殊需求,才來考慮使用其他格式,例如 form (上傳檔案) 或是 xml
  • 使用名詞,而非動詞:這樣才能搭配 HTTP verbs 的 POST/DELETE/GET/PUT,POST 放新資料到伺服器上,DELETE 移除資料,GET 取得資料,PUT 是更新資料
  • 時使用複數,表示取得一堆資料。
  • 階層物件可以使用巢狀資源,例如 /articles/article_id/comments/ 。P.S. 碰到這種情況其實也可以考慮使用 GraphQL
  • 漂亮的處理錯誤並回傳錯誤代碼,盡可能利用 HTTP 狀態碼而不要另外建立新的錯誤代碼。伺服器端在回傳錯誤時,可以帶上錯誤訊息,讓客戶端便於判斷、處理。
  • 允許篩選、排序跟分頁。篩選跟分頁可以避免一次拿過多資料,導致伺服器傳輸過多資料,也可以提升速度,拿的少,自然就快,對吧~
  • 安全性,SSL/TLS 是必要的,再來就是處理好使用者能存取的資源權限,這部份是實作 API 時必須要考慮到的。
  • 要用 cache,實作時要想,這資料會很常變動嗎?會很常被索取嗎?不常變動又很常被索取,就放到 cache 吧。
  • 幫 API 編上版號,這可以避免影響到舊有的 API,一方面也可以單純化,不用考慮到過多相容性的問題。例如:/v1, /v2

Angular i18n 的另外一個選擇 ngx-translate

Angular i18n 的官方作法並不讓人滿意,我後來找到 ngx-translate

先說明一下他的作法,他把這些翻譯好的字詞放到 JSON 翻譯檔去,在執行時就可以透過 http client 去拉取回來作動態的替換。

好處是,程式只要建置一次,不需要針對個別語言再次建置,網頁伺服器那邊也不需要特別寫設定去處理,而且可以做到動態切換語言。壞處是會有額外的 HTTP 請求,會增加流量。

ngx-translate 額外好的地方是,他提供了相應的工具、plugin,相當的方便。

那麼怎麼使用呢?我推薦看這篇【Angular】ngx-translate 多語系實務應用 ,他這篇的缺點是萃取字串的部分是手動,我建議萃取字串的部分可以用原作者 biesbjergngx-translate-extract  ,就不用自己找字串找的太累。

先進行安裝

npm install @ngx-translate/core —save
npm install @ngx-translate/http-loader --save

然後改 app.module.ts

import { TranslateModule, TranslateLoader, TranslateCompiler } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
import { HttpClientModule, HttpClient } from '@angular/common/http';

// … 省略 …

// 這主要是告訴 ngx-translate 翻譯檔該怎麼載入,用 TranslateHttpLoader 是表示以 HTTP 方式去下載、載入
export function HttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http, './assets/i18n/', '.json');
}

// … 省略 …

// 設定
const translateConfig = {
  defaultLanguage: 'en-US',  // 預設是英文
  loader: {
    provide: TranslateLoader,
    useFactory: HttpLoaderFactory,  // 前面寫的 Factory
    deps: [HttpClient]
  },
  compiler: {
    provide: TranslateCompiler,
    useClass: TranslateMessageFormatCompiler
  }
};

@NgModule({
  // …
  imports: [
    BrowserAnimationsModule,
    BrowserModule,
    TranslateModule.forRoot(translateConfig),  // 模組帶設定
    // …
  ],
  // …
})

在 HTML 裡,使用

// 方法 1
{{ ‘your_translation_key’ | translate }}

// 方法 2
<div [translate]=“‘your_translation_key’”></div>

// 方法 3,適用於字串要用 HTML
<div [innerHTML]="'HELLO' | translate"></div>

他還可以帶參數,只是這邊我看不太懂,暫時也還用不到。

在程式裡,使用

// 先匯入
import {TranslateService} from '@ngx-translate/core';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';

// … 省略 …
export class AppComponent implements OnInit {
  l10n__title = '';

  constructor(public translate: TranslateService) {
  }

  ngOnInit(): void {
    const self = this;

    // 讓 ngx-translate-extract 可以抓到字串用的
    _('your_translation_key');

    // 取得字串都要使用 translate.get() 來預先取得
    this.translate.get('your_translation_key').subscribe((res: string) => {
      self.l10n__title = res;
    });
  }
}

這裡要特別說明一點,也是我當初用的時候搞錯的地方,就是上面用到的 your_translation_key 並不是字串,而是你自定義的代碼,裡面有使用 ‘.’ 的時候,在產出的 JSON 裡會變成 nested object ,舉個例子,假設這個 key 是 login.title,那麼 JSON 翻譯檔就會是

{
  "login": {
    "title": ""
  }
}

接下來講 ngx-translate-extract,ngx-translate-extract 的安裝

npm install @biesbjerg/ngx-translate-extract --save-dev

裝好以後,在 package.json 的 scripts 裡加入 (要產生什麼語言,請替換 {en,da,de,fi,nb,nl,sv} 這個字串,以繁體中文來說,是zh-TW或zh-Hant,只有英文跟繁體中文的話,就放 {en-US,zh-TW}。 )

// package.json
...
"scripts": {
  "i18n:init": "ngx-translate-extract --input ./src --output ./src/assets/i18n/template.json --key-as-default-value --replace --format json",
  "i18n:extract": "ngx-translate-extract --input ./src --output ./src/assets/i18n/{en,da,de,fi,nb,nl,sv}.json --clean --format json"
}
...

然後建立存放字串的資料夾:mkdir -p src/assets/i18n,執行 npm run i18n:extract 以後,就可以在 src/assets/i18n 裡看到翻譯檔了。

bfg

因為 git repository 裡有敏感資訊,為了安全起見,必須要把這些敏感資訊移掉。
找到這兩篇:

裡面大同小異,主要提到兩個方法,一個是 git filter-branch,一個是 bfg,這邊只介紹 bfg。 bfg 是一個相對於 git filter-branch 來說簡單、快速的工具,除了可以清理敏感資訊之外,也可以清掉超級大的檔案。

MacOS 的安裝可以用 brew:brew install bfg

使用步驟如下:

  1. 移除掉你要處理的檔案或是先清理掉你要處理的檔案內容,然後提交、推送到 repository 去。這段官方有特別說明 (在 Your current files are sacred… 這個小節),我是已經做完下面步驟,上 gitlab 網頁看檔案怎麼沒消失,花了點時間才在網頁上注意到這段,所以這個步驟要先作!!
  2. 切到另外一個目錄,例如 $HOME/tmp,對 repository 作 mirror,這樣拿下來的檔案結構不是一般的檔案佈局,而是 .git 下的佈局:git clone –mirror your_repository.git ,這時候 $HOME/tmp 下會有一個 your_repository.git
  3. 幾種使用方法:
    • 刪除檔案:bfg –delete-files your_file your_repository.git
    • 移除超過指定大小的檔案:bfg –strip-blobs-bigger-than 50M your_repository.git
    • 清理敏感資訊:先新增一個 passwords.txt,裡面放置要移除的文字,範例可以參考這個 gist ,然後執行 bfg –replace-text passwords.txt your_repository.txt
    • 刪除資料夾:bfg –delete-folders .git –delete-files .git –no-blob-protection your_repository.git
  4. 切到 your_repository.git 下,依照指示執行 git reflog expire –expire=now –all && git gc –prune=now –aggressive
  5. 推送回去:git push
  6. 大功告成

把敏感設定的內容跟 Angular 程式分離

以我用過 Django / Docker 的經驗,一般都是利用環境變數來作分離,程式在執行時,會去讀取環境變數來當作設定,盡量不依靠設定檔,進而達到 12 factor –  config 的要求。

到了 Angular ,就需要做出調整。Angular 是需要先進行建置產出 javascript / html / css ,再把這些產出的檔案放到網頁伺服器,瀏覽器再去下載,所以完全沒辦法使用環境變數作為設定,必須要把設定寫到檔案裡,再做建置。那設定寫到檔案的話,其實我們都知道,這些敏感設定內容不適合放到 git repository,即使是 private repository,這樣會有安全上的風險。那這樣就兩難了啊?

說來很妙,我是覺得官方早就應該有比較好的作法了,但是,並沒有。不管怎麼樣,我還是找到解決方法了,基本上跟我想的也差不多。

這兩篇文章的作法大同小異,這邊作簡單的說明:

  1. 移除 src/environment/environment.ts
  2. 新增一個腳本,這個腳本會讀取環境變數,並產生一個新的 src/environment/environment.ts
  3. 修改 package.json
    1. 在 scripts 裡增加 config,這個 config 會去執行步驟 2 的腳本,用以產生 environment.ts
    2. 修改 scripts 裡的 start / build,在執行原來的指令前,先執行 npm run config 去產生 environment.ts

下面兩個片段是關鍵的改動部分:

// set-env.ts
// 放在專案根目錄下
import { writeFile } from 'fs';
import { name, version } from './package.json';


// Configure Angular `environment.ts` file path
const targetPath = './src/environments/environment.ts';


// 載入 colors 模組,主要是用來顯示
const colors = require('colors');


// 可以把敏感內容放到 .env 檔案裡,nodejs 會把內容讀出來,放到環境變數裡
// 也可以在執行 npm run 之前,先設定好環境變數
const result = require('dotenv').config();
if (result.error) {
  // throw result.error;
}


// 原來 environment.ts 裡的內容,把該替換的,用 template literals 來替換

// https://developer.mozilla.org/zh-TW/docs/Web/JavaScript/Reference/Template_literals
const envConfigFile = `export const environment = {
  production: ${process.env.PRODUCTION},
  VERSION: '${version}’,
};

`;


// 顯示
console.log(colors.magenta('The file `environment.ts` will be written with the following content: \n'));
console.log(colors.grey(envConfigFile)); writeFile(targetPath, envConfigFile, (err) => {
  if (err) {
    throw console.error(err);
  } else {
    console.log(colors.magenta(`Angular environment.ts file generated correctly at ${targetPath} \n`));
  }
});
// package.json
// 只摘錄重要的部分
{
  “scripts”: {
    "config": "ts-node -O '{\"module\": \"commonjs\"}' ./set-env.ts",
    "start": "npm run config && ng serve",
    "build": "npm run config && ng build”
  }
}

電影流水帳(2020/05/01~2020/05/10)

Emma Stone
Emma Stone,飾演 Zombieland: Double Tap 裡的 Wichita
  • J’ai perdu mon corps (IMDB, Wikipedia),英譯:I lost my body,台譯:隻手探險。
  • Zombieland: Double Tap (IMDB, Wikipedia),台譯:屍樂園-髒比雙拼。

J’ai perdu mon corps

這是部故事很有意思的電影,只是有點小悶。

故事從一隻手開始,這隻手莫名其妙的會動,然後開始他的旅程。在這個旅程中,開始穿插著他主人的故事。原來這隻手的主人 Naoufel 是個孤兒,小時候學過鋼琴,然後因為意外,父母車上吵架發生了車禍,導致 Naoufel 變成了孤兒。後來長大以後,Naoufel 當了披薩外送員,某次外送,他外送到一個女孩子家,可是遲到了,女孩子有點兒生氣,但還是原諒了他,他們透過對講機聊起了天。Naoufel 對這女孩子很有好感,依據聊天的內容,用了點詭計取得了她的名字 – Gabrielle ,以及上班地點。接著 Naoufel 跟蹤 Gabrielle,得知她有個叔叔,她的叔叔似乎需要人手,Naoufel 毛遂自薦,當了她叔叔的學徒,然後跟 Gabrielle 有了進一步的認識以及交往。就在 Naoufel 進一步告訴了 Gabrielle 自己是怎麼接近她以及想要進一步交往時,Gabrielle 拒絕了他。Naoufel 很難過,他去了朋友的舞會,喝的爛醉。隔天早上宿醉的他回到 Gabrielle 叔叔的工廠,要開始工作,可是,意外往往就是這麼發生。宿醉的 Naoufel 一個不小心,讓自己的手被鋸斷了,Naoufel 被送到醫院,這隻手則是意外的動了起來。

這隻手最後是找到了他的主人,只是 Naoufel 已經決定離去,他跑到屋頂去。Gabrielle 來找 Naoufel 時,沒看到 Naoufel ,也跟著到了屋頂,想說會不會在之前告白的地方。雪開始下了,在屋頂除了 Naoufel 蓋的小木屋、覆蓋著雪的屋頂地上的腳印之外,只剩下之前 Naoufel 很珍藏的錄音機。她撿起來邊聽著這錄音,一邊找尋著 Naoufel 。在邊聽的時候,知道了 Naoufel 為什麼一直聽這錄音,同時也聽到了Naoufel 留給她的話。從足跡來看,原本以為 Naoufel 是跳樓自盡,但搭配著錄音機裡的聲音,她知道 Naoufel 是成功的從這屋頂跳到另外一棟大樓去了…

Zombieland: Double Tap

失望的續集電影,故事普普通通。

故事的一開始,Little Rock 厭倦了四人一起的生活,Columbus 向 Wichita 求婚,Wichita 不願意正面回應,就跟 Little Rock 離開了。Wichita 跟 Little Rock 在路上遇到一個男孩子 Berkeley,Little Rock 為了擺脫姊姊,在半夜裡丟下 Wichita ,跟 Berkeley 一起上路走了。隔天醒來的 Wichita 感到錯愕,只能回去找 Columbus 跟 Tallahassee 。被 Wichita 跟 Little Rock 丟下的 Columbus 跟 Tallahassee 去了購物中心,意外遇到一個沒被感染的女孩 Madison ,帶了她回去。Columbus 跟 Madison 發生了關係,回來的 Wichita 感情很受傷,才離開沒兩天,Columbus 居然就跟別的女人上床了,而且還是個傻大姊。

回來的 Wichita 表明了很擔心 Little Rock ,Columbus 跟 Tallahassee 雖然不喜歡之前被丟棄,但基於家人的立場,還是決定幫忙 Wichita,於是四人就出發去找 Little Rock 了。一開始沒多久,Madison 就疑似被僵屍咬到,看起來就是要變成僵屍,Columbus 只能痛下殺手。三人繼續旅程,循著線索去找 Little Rock ,然後他們來到一間擺放著貓王遺物的旅館,在這裡他們遇到 Nevada 。聊了以後,才知道 Nevada 經營著這家旅館,並且保存著貓王的遺物。因為同樣愛貓王的關係,Tallahassee 跟 Nevada 還蠻契合的。隔天,兩個人 Flagstaff 跟 Albuquerque 來找 Nevada,相互打過照面以後,發現這兩個人意外的跟 Columbus 與 Tallahassee 蠻相似的,一個老愛碎碎念,一個愛殺僵屍。這時候僵屍突然殺過來,Flagstaff 跟 Albuquerque 出去殺退僵屍,只是回來時,兩人已經被感染。Nevada 等人只好幹掉 Flagstaff 跟 Albuquerque ,隨後 Columbus, Tallahassee 跟 Wichita 告別 Nevada 繼續上路。上路以後,意外遇到 Madison ,所以 Madison 真的只是過敏,而不是被僵屍咬了。四人再次會合,上路去找 Little Rock。終於,他們根據 Nevada 的線索,找到了 Little Rock 所在地。Little Rock 所到的地方是一群愛好和平的人所居住的村落,所有人都不能帶武器。他們進去想要勸退 Little Rock,可是看來 Little Rock 心意已決。Tallahassee 說既然已經找到 Little Rock,我任務也結束了,那我要離開囉,就獨自開車離去。

Tallahassee 在月夜下孤身一人很愜意的開著車,突然他看到一群僵屍往 Little Rock 的所在地跑去,他覺得大事不妙,就回去示警。四人決定設下陷阱來對付僵屍,經過一番大戰,眼看四人就要命喪僵屍手下,Nevada 開著車過來救了四人。五個人依據僵屍的行動模式重新擬定了作戰策略,跟住在這邊的人一起對抗僵屍,最後打敗了僵屍。

故事裡,有兩個地方讓我覺得很有趣,第一個是喜歡立下規則的 Columbus 居然打破了自己的規則,他沒有殺死 Madison,而是對空鳴槍把她嚇走,不過這也讓他們後續能有交通工具繼續旅程,這或許是編劇想告訴我們的,「有時候打破規則也無妨」。第二個是,兩人遇到跟自己個性相似的人,Tallahassee 是很不爽,而 Columbus 則是有惺惺相惜的感覺,那我呢?我要是看到跟自己相似的人是會生氣?覺得這人不長進?還是會覺得太好了,這樣應該比較好溝通?這倒是蠻值得好好想想的。

Angular i18n

Angular 官方提供的套件以及教學:Angular Internalization (i18n)

文章裡一大堆,簡單整理如下:

  1. 安裝:ng add @angular/localize
    • 這個步驟會幫你在 polyfills.ts 裡加入必要的 import
  2. 使用,這部份分為 HTML 跟程式
    • HTML,在需要多國語言的標籤加入 i18n 的屬性
      • <span i18n>Hello world</span>
      • <span i18n=“@@span_hello”>Hello world</span> ,用 i18n=“@@span_hello” 的好處是,產出的翻譯檔裡不會是一個隨意的數字,而是一個對開發者來說比較明確的名稱。
      • <input i18n-placeholder> 這個是有些屬性本身需要多國語言的,就在前面加上 “i18n-“
    • 程式,字串前方加上 $localize ,並且改用 back quote,例如:$localize`hello world`
  3. 萃取,用 ng xi18n –output-path src/i18n 就可以把 HTML 裡有標 i18n 的字串萃取到 src/i18n/messages.xlf 裡
  4. 翻譯,先把上個步驟取得的 messages.xlf 複製為 messages.zh_Hant.xlf ,再去編輯。這邊提供一個簡易的網頁工具 – tiny-translator,在處理上會方便很多。開啟以後,要先建立專案,然後上傳 .xlf 檔案,接著就可以進行翻譯了。翻譯好,再下載下來即可。
  5. 合併,程式開發中難免會有增刪,每次用 xi18n 基本上都是重新萃取一次,等於是又要再搞一次合併的功夫,這太累。tiny-translator 的作者有提供另外一個工具 – xliffmerge 
    • 安裝:npm install -g ngx-i18nsupport
    • 在 package.json 的 scripts 裡加入 “extract-i18n”: “ng xi18n –output-path src/i18n && xliffmerge –profile xliffmerge.json en de” ,裡面的 en, de 等 locale 請依照自己的需求作調整
    • 新增 xliffmerge.json ,這個檔案請參考後面。
    • 使用 npm run extract-i18n 就可以自動萃取字串並且作合併了。
  6. 專案的建置,主要是修改 angular.json,有三個部分:
    • projects / your_project_name 加入 “i18n”: {“sourceLocale”: “en”, “locales”: {“de”: “src/i18n/messages.de.xlf”}}
    • projects / your_project_name / architect / build / configurations 裡加入 “de”: {“localize”: [“de”]}
    • projects / your_project_name / architect / serve / configurations 裡加入 “de”: {“browserTarget”: “ng-hosting:build:de”}
  7. 要執行 ng build / ng serve 時,就可以用
    • ng build –configuration=production,de
    • ng serve –configuration=de
  8. 補充一個我覺得很重要的部分,就是一個語言要建置一次,所以一般的佈署會是這樣的,建置好 zh ,放在 zh/ 目錄下,建置好 de,放在 de/ 目錄下,然後在 nginx/apache 的設定裡去依照 header 的 language 去導向到對應的目錄去。這篇 Deploying an i18n Angular app with angular-cli 的後面有教怎麼去設定 apache / nginx。

看到這邊,你可能會想,那程式裡標上 $localize 的字串呢?嗯,ng xi18n 並不會把這些字串萃取出來 (issue),所以這部份得自己手動處理 😣 

P.S. 用 ngx-i18nsupport 的 tooling 可以把上面講的簡化掉,像是加入 npm package、在 package.json 加入 extract-i18n 、在 angular.json 加入設定等等,一次就搞定了,我是已經用了才看到這個 tooling ,有點相見恨晚。

// xliffmerge.json
{
  "xliffmergeOptions": {
    "srcDir": "src/i18n",
    "genDir": "src/i18n",
    "i18nFile": "messages.xlf",
    "i18nBaseFile": "messages",
    "i18nFormat": "xlf",
    "encoding": "UTF-8",
    "defaultLanguage": "en",
    "languages": ["en", "de"],
    "removeUnusedIds": true,
    "supportNgxTranslate": false,
    "ngxTranslateExtractionPattern": "@@|ngx-translate",
    "useSourceAsTarget": true,
    "targetPraefix": "",
    "targetSuffix": "",
    "beautifyOutput": false,
    "preserveOrder": true,
    "allowIdChange": false,
    "autotranslate": false,
    "apikey": "",
    "apikeyfile": "",
    "verbose": false,
    "quiet": false
  }
}

電影流水帳(2020/04/11~2020/04/30)

https://www.flickr.com/photos/94915094@N06/42774806181/
Golshifteh Farahani ,驚天營救裡的 Nik,很酷。
  • Extraction (IMDB, Wikipedia),台譯:驚天營救。
  • The Nightmare Before Christmas (IMDB, Wikipedia),台譯:聖誕驚魂夜。

Extraction

昨天晚上看完驚天營救,這是在臉書社團看到大家推薦才看的。

電影的內容是描述傭兵Tyler 受雇去拯救一個毒梟的兒子所經歷的過程。

Tyler 心裡是有缺憾的,他的孩子生了淋巴癌,但他不忍心看著兒子在眼前死去而去出任務,後來他生了淋巴癌的兒子走完人生最後一段,所以 Tyler 心裡一直耿耿於懷,這也是後來他為什麼知道沒有錢之後,還願意繼續拯救這個孩子的原因。

劇情還蠻簡單的,A毒梟跟B毒梟為了搶地盤,B毒梟就把A毒梟兒子綁架走,A毒梟在監獄裡,又沒有足夠的錢,只要自己的手下 Saju 去救人。Saju 無奈,只能找傭兵來幫忙,然後再半途搶人,翻臉不付錢。B毒梟掌控了整個城市跟警察,在他得知 Tylor 救出那個孩子後,就封鎖了整個城市。Tylor 在逃出的過程裡面是非常驚險的,不但被 Saju 追,也被警察追殺。在封城的情況下,Tylor 跟那個孩子幾乎已經被困住了。後來他請 Nik 找了以前欠他人情的朋友來幫他逃出去,Tylor 的朋友知恩圖報,在整個城市被封鎖的情況下還願意來幫他。只是,Tylor 的朋友已經跟 B 毒梟談好條件,只要孩子交出來,他跟 Tylor 都能全身而退。Tylor 不願意,兩人打鬥了起來,聽到打鬥聲的孩子出來拿了槍,殺了 Tylor 的朋友。這下可好,該怎麼殺出重圍呢?Tylor 找了 Saju 來幫忙,然後聯絡了 Nik ,在隔天一早,他們以聲東擊西的方式,試圖殺出重圍。經過一番血戰,Tylor 跟 Saju 將孩子交到 Nik 手上,Saju 戰死,Tylor 力盡掉到河裡去。

八個月之後,酷酷的女主角出現在廁所裡,把 B 毒梟幹掉了。然後場景帶到孩子去游泳,孩子學男主角一樣潛在水裡想事情,浮上來的時候看到了男主角模糊的身影,所以最後 Tylor 活著還是死了呢?如果活著,為什麼 Nik 還要去殺死 B 毒梟?如果死了,孩子又怎麼會看到這模糊的身影呢?

The Nightmare Before Christmas

很久以前的片了,從 Netflix 上了這片以後,就一直掛在「我的片單」裡,終於找時間看完它。

Jack 是萬聖小鎮上的搞怪王,但是長期都做同樣的事情以後,他覺得乏了,想找些新花樣。他出鎮外去逛,逛啊逛,發現了聖誕小鎮,知道了聖誕老人跟聖誕節,他非常的開心,趕緊回到鎮上講這件事情,要大家進行準備,期望能取代聖誕節。大家非常樂意的配合,只是,方向偏了,大家準備的東西,像是禮物等等的,跟 Jack 想的不一樣。時間過的很快,轉眼就到聖誕節了。Jack綁架了聖誕老人,開心的帶著萬聖小鎮大夥製作的禮物,坐上雪橇挨家挨戶去送禮物。只是,這禮物太可怕了,人類沒辦法接受,於是軍隊發射了炮火,要把 Jack 打下來。Jack 有些吃驚,本來以為大家是在放煙火,後來才知道,人類並不歡迎這樣的禮物。被炮火打下來以後,他發現自己錯了,還是應該找回聖誕老人,就回去小鎮。被 Jack 綁架的聖誕老人被囚禁在 Oogie Boogie 那邊,暗地裡愛慕 Jack 的 Sally 一直默默的支持 Jack,在 Jack 出發去送禮物後,她感覺事情不對,跑去 Oogie Boogie 那邊找原來的聖誕老人,哪知道自己也陷入了險境。趕回來的 Jack ,看到這樣的景況,打敗了 Oogie Boogie,救出聖誕老人以及 Sally,然後將聖誕老人送回聖誕小鎮,進而拯救了因為自己而崩壞的聖誕節。

我還滿喜歡 Tim Burton 拍的這類電影,像是剪刀手愛德華、陰間大法師、斷頭谷、怪奇孤兒院等,都是我蠻喜歡的電影。剛剛查維基百科時,蠻驚訝的是,2001 年的星球崛起也是他拍的啊。