2019年4月28日 星期日

[Vue] Internationalization with vue-i18n and vue-router


 Vue.js   vue-18n   vue-router  


Introduction­


We will implement i18n with

n   vue-router: For getting current target culture from url, such as http://localhost/en-US/login

n   vue-i18n: Localize the content by local or remote i18n data





Related articles




Environment


Vue CLI 3.5.1 (with TypeScript 3.2.1)
vue-router 3.0.2
vue-i18n 8.9.0


Implement


Router

To create routes which can indicate current culture, such as,

http://localhost/zh-TW/login
http://localhost/en-US/about

The routes patterns are set as following,

router.ts

import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const routes = [
  {
    name: 'home',
    path: '/',
    redirect: '/zh-tw/login',
  },
  {
    name: 'app',
    path: '/:lang',
    component: Home,
    children: [
      { path: 'login', name: 'login', component: Login },
      { path: 'about', name: 'about', component: About },
    ],
  },
];
export default new VueRouter({
  routes,
  mode: 'history',
});



Global Before Guards

We can use vue-router’s Global Before Guards to get current-culture value from user’s navigation url, and then set the right i18n data to vue-i18n.
Here is the sample code which will implement requesting i18n data,loadLanguageAsync(…), later.

router.beforeEach((to: any, from: any, next: any) => {
  const lang = to.params.lang;
  const key = to.query.key || to.name;

  if (supportedLanguages.indexOf(to.params.lang) >= 0) {
    loadLanguageAsync(lang, key).then((response) => {
      const msg = new LocaleMsg(lang, response.data);
      i18n.setLocaleMessage(msg.lang, msg.messages);
      next();
    });
  } else {
    // HACK: Alert not supporting the language
    next(false); // Fallback to "from"'s url
  }
});



The ajax method for i18n data is as following,

const loadedLanguages: string[] = []; // Default language that is preloaded if any

function loadLanguageAsync(lang: string, key: string): Promise<any> {
  if (loadedLanguages.indexOf(lang) < 0) {
    i18n.locale = lang;
    return getI18n(lang, key);
  } else {
    return Promise.resolve(() => {
      i18n.locale = lang;
    });
  }
}

function getI18n(lang: string, key: string): AxiosPromise<any> {
  const serverUrl: string = process.env.VUE_APP_HOST_BACKEND_URL!;
  const uri = serverUrl.concat(`api/locale/get/${lang}/?key=${key}`);
  return axios.get(uri);
}



i18n

Now we can create an i18n module to setup vue-i18n, and set the i18n option to Vue instance.

i18n.ts

import Vue from 'vue';
import axios from 'axios';
import VueI18n, { LocaleMessages } from 'vue-i18n';
import router from '@/router';

Vue.use(VueI18n);
axios.defaults.withCredentials = false;

const supportedLanguages = ['en-us', 'zh-tw', 'zh-cn'];

const i18n = new VueI18n({
  locale: process.env.VUE_APP_I18N_LOCALE || 'zh-tw',
  fallbackLocale: process.env.VUE_APP_I18N_FALLBACK_LOCALE || 'zh-tw',
});

// You can put the previous codes here…

export {supportedLanguages, i18n};




main.ts

import router from './router';
import { i18n } from '@/modules/i18n';

Vue.config.productionTip

new Vue({
  router,
  i18n,
  render: (h) => h(App),
}).$mount('#app');




Demo





Reference




2019年4月26日 星期五

[Sourcetree] Delete passwd


 Sourcetree   Windows credential


Recently my windows account had been locked frequently and don’t know which application used the wrong password of windows credential.
Finally I found out the Sourcetree had kept the Windows credential (ID/PWD) in the following  location,

~\AppData\Local\Atlassian\SourceTree\passwd

Ex.
C:\Users\karatejb\AppData\Local\Atlassian\SourceTree\passwd





The solution is deleting the file: passwd, and restart Sourcetree and a  popup will ask for the new credential.


Reference






2019年4月23日 星期二

[PostgreSQL] Cross database query with dblink


 PostgreSQL   dblink


Introduction


dblink is a module that supports connections to other PostgreSQL databases from within a database session. (Reference)

In this article, we will learn how to use psql to create a View with records located in another PostgreSQL database.





Environment


Docker Engine Community 18.09.2
postgres 10
pgAdmin 4


Implement


Create dblink

Install dblink extension

CREATE EXTENSION dblink;


Verify DbLink

SELECT pg_namespace.nspname, pg_proc.proname
FROM pg_proc, pg_namespace
WHERE pg_proc.pronamespace=pg_namespace.oid
AND pg_proc.proname LIKE '%dblink%';




Test connection of the target database


SELECT dblink_connect('host=<server_name_or_ip> user=<user> password=<pwd> dbname=<target_database>');


For example, we want to connect to the database: MyDatabase, in db-server-2, we can first test the connection like this,

SELECT dblink_connect('host=db-server-2 user=postgres password=xxxxxxx dbname=MyDatabase');



Create foreign data wrapper for global authentication

Create a connection wrapper that we can use this name for cross database query.

CREATE FOREIGN DATA WRAPPER <wrapper_name> VALIDATOR postgresql_fdw_validator;
CREATE SERVER <custom_server_name> FOREIGN DATA WRAPPER <wrapper_name> OPTIONS (hostaddr '<IP>', dbname '<db_name>' port '<db_port>');
CREATE USER MAPPING FOR <custom_user_mapping_name> SERVER <custom_server_name> OPTIONS (user '<user>', password '<pwd>');


Ex.
CREATE FOREIGN DATA WRAPPER data_wrapper VALIDATOR postgresql_fdw_validator;
CREATE SERVER db2 FOREIGN DATA WRAPPER data_wrapper OPTIONS (host 'db-server-2', dbname 'MyDatabase' );
CREATE USER MAPPING FOR postgres SERVER db2 OPTIONS (user 'postgres', password 'xxxxxx');



Notice that if you had already created the Password File (.pgpass), we can skip the password parameter on creating USER MAPPING. 

CREATE USER MAPPING FOR postgres SERVER db2 OPTIONS (user 'postgres');

 

 




Test created server

SELECT dblink_connect('db2');





Give require permission to map user

GRANT USAGE ON FOREIGN SERVER <custom_server_name> TO <custom_user_mapping_name >;

In this example,

GRANT USAGE ON FOREIGN SERVER db2 TO postgres;



Cross database query

Now we can use the dblink to do cross database query.
For example, I created a View which query data from the other database: db-server-2.

CREATE VIEW "VmCustomers" AS
SELECT * FROM public.dblink('db2','SELECT Id, Type, Name, Address FROM public.message')
AS DATA("Id" integer, "Type" text,"Name" text, "Address" text)
WHERE "Type"='VIP'




Reference