블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

2017. 9. 4. 15:51 카테고리 없음

Angular 최신 버전이 v5 beta-6를 향해 가고 있다. 9월에는 v5 release가 될 것으로 보인다. Angular에서 툴 기능으로 @angular/cli를 제공하고 있는데 오늘은 이것의 내부구조에 대해 연구해 본다. 



@angular/cli 설치 및 프로젝트 생성

설치는 npm 또는 yarn을 이용한다.

$> npm i -g @angular/cli


or 


$> yarn add global @angular/cli


Angular 기반 프로젝트를 생성해 보자.

$> ng new jamong


실행해 보자

$> ng serve




폴더 구조

angular/cli는 Automation Tool 과 Module loader로 webpack을 사용하고 있다. 웹팩의 환경파일을 루트 폴더에 생성한다. 
$> ng eject
=====================================================
Ejection was successful.

To run your builds, you now need to do the following commands:
   - "npm run build" to build.
   - "npm test" to run unit tests.
   - "npm start" to serve the app using webpack-dev-server.
   - "npm run e2e" to run protractor.

Running the equivalent CLI commands will result in an error.

=====================================================
Some packages were added. Please run "npm install".


설명에 따라 추가 명령을 수행한다. 

$> npm run build && npm start


// package.json의 build 와 start 스크립트 설정내역

  "scripts": {

    "ng": "ng",

    "start": "webpack-dev-server --port=4200",

    "build": "webpack",

    "test": "karma start ./karma.conf.js",

    "lint": "ng lint",

    "e2e": "protractor ./protractor.conf.js",

    "pree2e": "webdriver-manager update --standalone false --gecko false --quiet"

  },



webpack 오류가 난다면 webpack이  global설치가 않되어 있기때문이다. webpack을 설치한다. 

$> yarn add webpack --dev

또는

$> yarn add global webpack 

또는 

$> npm install -g webpack





Webpack 환경파일

webpack의 기본은 초기 참조할 entry파일과 결과 번들파일을 지정하는 것이다. 

$> webpack <entry file path> <output bundle file path>


예) webpack ./entry.js bunlde.js


간단한 번들링은 CLI를 사용해도 무방하지만 복잡한 옵션이 적용되어야 한다면 환경파일을 사용한다. 예) webpack.config.js 아래 예에서 ouput의 filename에 [name]은 entry의 'app' 키값이다. 

module.exports = {

  context: __dirname + '/app',

  entry: {

    app: './app.js'

  },

  output: {

    path: __dirname + '/dist',

    filename: '[name].bundle.js'

  }

}


환경설정 자세한 옵션은 공식문서를 참조한다. 여기서 주의할 것은 entry는 String, Object, Array로 설정가능하다. 

- String: 하나만 설정

- Array: output 번들링 파일에 순서적으로 합쳐진다.

- Object: SPA처럼 index.html에 적용되는 것이 아니라, index1.html 또는 index2.html 등 output이 각각의 html에 포함될 때 사용한다. 





Webpack Loader

Webpack에는 자바스크립트가 아닌 확장형식의 파일을 자바스크립트에서 동작할 수 있도록 해주는 로더(Loader)가 있다. 즉, 모든(CSS, Images, HTML...)을 모듈로 취급하게 해주는 핵심역할을 로더가 수행한다. 말 그대로 다양한 파일 확장자의 Module Loader의 줄임말이라 보면된다. (전체 목록 참조) 만일 설정중에 module, rules를 사용하지않고 loaders를 쓰거나, options대신 query를 쓰면 webpack 1에 대한 설명이다.


- 스타일: style, css

- 변환: typescript, coffeescript, ES2015


환경파일안에 module 밑으로 설정한다. 


module.exports = {

  entry: ...

  output: ...

  module: {

    rules: [

      {

        test: /\.css$/,

        use: [ 'style-loader', 'css-loader']

      }

    ]

    ...

  }


}


특히 Angular 개발시에는 Typescript를 사용하므로 sourcemap을 남기려면 'source-map-loader'를 module 프로퍼티에 설정한다. (sourcemap에 대해 webpack3에서는 plugin으로 설정도 가능하다.) enforce 설정값을 "pre"로 하면 자바스크립트 변환전에 sourcemap 을 만든다.

{

        "enforce": "pre",

        "test": /\.js$/,

        "loader": "source-map-loader",

        "exclude": [

          /(\\|\/)node_modules(\\|\/)/

        ]

}


개발시에는 Node.js기반의 webpack-dev-server를 통해 개발 페이지를 테스트할 수 있다. 옵션은 --inline (전체 페이지 리로딩) --hot (변경 컴포넌트만 리로딩)한다. 

// 전체 및 부분 리로딩 옵션 설정

$> webpack-dev-server --inline --hot




Webpack Plugins

플러그인은 Output 번들의 Chunk 또는 Compilation 레벨 파일에 대한 추가 작업을 수행한다. 예로 ulgifyJSPlugin은 번들 파일 사이즈를 줄이고, 코드를 못 알아보게 만들어 준다. 또는 extract-text-webpack-plugin의 경우는 css-loader, style-loader의 결과를 하나의 별도 외부 파일로 만들어 준다. (플러그인 목록 참조)


@angular/cli에서  ng eject로 나온 webpack.config.js안의 plugins설정 내역

"plugins": [

    new NoEmitOnErrorsPlugin(),

    new GlobCopyWebpackPlugin({

      "patterns": [

        "assets",

        "favicon.ico"

      ],

      "globOptions": {

        "cwd": path.join(process.cwd(), "src"),

        "dot": true,

        "ignore": "**/.gitkeep"

      }

    }),

    new ProgressPlugin(),

    new CircularDependencyPlugin({

      "exclude": /(\\|\/)node_modules(\\|\/)/,

      "failOnError": false

    }),

    new NamedLazyChunksWebpackPlugin(),

    new HtmlWebpackPlugin({

      "template": "./src/index.html",

      "filename": "./index.html",

      "hash": false,

      "inject": true,

      "compile": true,

      "favicon": false,

      "minify": false,

      "cache": true,

      "showErrors": true,

      "chunks": "all",

      "excludeChunks": [],

      "title": "Webpack App",

      "xhtml": true,

      "chunksSortMode": function sort(left, right) {

        let leftIndex = entryPoints.indexOf(left.names[0]);

        let rightindex = entryPoints.indexOf(right.names[0]);

        if (leftIndex > rightindex) {

          return 1;

        } else if (leftIndex < rightindex) {

          return -1;

        } else {

          return 0;

        }

      }

    }),

    new BaseHrefWebpackPlugin({}),

    new CommonsChunkPlugin({

      "name": [

        "inline"

      ],

      "minChunks": null

    }),

    new CommonsChunkPlugin({

      "name": [

        "vendor"

      ],

      "minChunks": (module) => {

        return module.resource &&

          (module.resource.startsWith(nodeModules) ||

            module.resource.startsWith(genDirNodeModules) ||

            module.resource.startsWith(realNodeModules));

      },

      "chunks": [

        "main"

      ]

    }),

    new SourceMapDevToolPlugin({

      "filename": "[file].map[query]",

      "moduleFilenameTemplate": "[resource-path]",

      "fallbackModuleFilenameTemplate": "[resource-path]?[hash]",

      "sourceRoot": "webpack:///"

    }),

    new CommonsChunkPlugin({

      "name": [

        "main"

      ],

      "minChunks": 2,

      "async": "common"

    }),

    new NamedModulesPlugin({}),

    new AotPlugin({

      "mainPath": "main.ts",

      "replaceExport": false,

      "hostReplacementPaths": {

        "environments/environment.ts": "environments/environment.ts"

      },

      "exclude": [],

      "tsConfigPath": "src/tsconfig.app.json",

      "skipCodeGeneration": true

    })

]


JHipster로 자동생된 webpack.config.dev.js의 plugins 설정 내역

plugins: [

        new BrowserSyncPlugin({

            host: 'localhost',

            port: 9000,

            proxy: {

                target: 'http://localhost:9060',

                ws: true

            }

        }, {

            reload: false

        }),

        new webpack.NoEmitOnErrorsPlugin(),

        new webpack.NamedModulesPlugin(),

        new writeFilePlugin(),

        new webpack.WatchIgnorePlugin([

            utils.root('src/test'),

        ]),

        new WebpackNotifierPlugin({

            title: 'JHipster',

            contentImage: path.join(__dirname, 'logo-jhipster.png')

        })

 ]




Production vs Development

개발과 운영 시점에 webpack 환경을 달리 적용하기 위해 보통  webpack.config.dev.js 와 webpack.config.prod.js를  따로 만들고 package.json의 script에 적용해 사용한다. package.json에 적용하고 싶지 않다며 gulp를 사용해도 된다. 


@angular/cli의 script 내역

 "scripts": {

    "ng": "ng",

    "start": "webpack-dev-server --port=4200",

    "build": "webpack",

    "test": "karma start ./karma.conf.js",

    "lint": "ng lint",

    "e2e": "protractor ./protractor.conf.js",

    "pree2e": "webdriver-manager update --standalone false --gecko false --quiet"

}


JHipster script 내역

"scripts": {

    "lint": "tslint --type-check --project './tsconfig.json' -e 'node_modules/**'",

    "lint:fix": "yarn run lint -- --fix",

    "ngc": "ngc -p tsconfig-aot.json",

    "cleanup": "rimraf target/{aot,www}",

    "clean-www": "rimraf target//www/app/{src,target/}",

    "start": "yarn run webpack:dev",

    "serve": "yarn run start",

    "build": "yarn run webpack:prod",

    "test": "karma start src/test/javascript/karma.conf.js",

    "test:watch": "yarn test -- --watch",

    "webpack:dev": "yarn run webpack-dev-server -- --config webpack/webpack.dev.js --progress --inline --hot --profile --port=9060",

    "webpack:build:main": "yarn run webpack -- --config webpack/webpack.dev.js --progress --profile",

    "webpack:build": "yarn run cleanup && yarn run webpack:build:main",

    "webpack:prod:main": "yarn run webpack -- --config webpack/webpack.prod.js --progress --profile",

    "webpack:prod": "yarn run cleanup && yarn run webpack:prod:main && yarn run clean-www",

    "webpack:test": "yarn run test",

    "webpack-dev-server": "node --max_old_space_size=4096 node_modules/webpack-dev-server/bin/webpack-dev-server.js",

    "webpack": "node --max_old_space_size=4096 node_modules/webpack/bin/webpack.js",

    "e2e": "protractor src/test/javascript/protractor.conf.js",

    "postinstall": "webdriver-manager update && node node_modules/phantomjs-prebuilt/install.js"

}


to be continued...



<참고>

- Webpack core concept

- 네이버 webpack 소개

- Webpack의 혼란스러운 사항들

- Webpack3에서 주의할 점


posted by 윤영식
2017. 3. 29. 15:05 Angular/Concept

NodeJS에서 Typescript를 사용하기 위한 빠른 환경 설정 방법을 정리한다.



설치

먼저 테스트를 위한 폴더를 만들고 Node환경을 만든다. package.json을  파일 생성한다.

$ npm init -y


필요한 패키지를 설치한다.

$ npm i -g typescript@latest


$ npm i -g ts-node


$ npm i @types/node --save-dev




환경설정


Typescript 환경파일을 생성한다.

$ tsc --init


tsconfig.json파일 환경을 설정한다. typeRoots와 exclude를 추가한다. (tsocnfig.json의 상세내역 참조)

{

    "compilerOptions": {

        "module": "commonjs",

        "target": "es5",

        "noImplicitAny": false,

        "sourceMap": false

    },

    "typeRoots": ["node_modules/@types"],

    "exclude": [

        "node_modules"

    ]

}




테스트


테스트 파일을 생성한다.

$ touch index.ts

$ vi index.ts


const hi = 'hello peter';

console.log(hi);


테스트를 위해 소스 변경을 런타임시에 체크하고 적용하는 nodemone을 설치한다. 

$ npm i nodemon --save-dev


테스트 스크립트를 package.json의 scripts 항목에 추가한다.

$ vi package.json


{

...

  "scripts": {

    "start": "npm run build:live",

    "build:live": "nodemon --exec ./node_modules/.bin/ts-node  ./index.ts"

  },

...

}


테스트한다.

$ npm start


> typescript@1.0.0 start /Users/dowonyun/prototyping/typescript

> npm run build:live

> typescript@1.0.0 build:live /Users/dowonyun/prototyping/typescript

> nodemon --exec ./node_modules/.bin/ts-node ./index.ts


[nodemon] 1.11.0

[nodemon] to restart at any time, enter `rs`

[nodemon] watching: *.*

[nodemon] starting `./node_modules/.bin/ts-node ./index.ts`

hello peter

[nodemon] clean exit - waiting for changes before restart



또는 ts-node를 설치해서 수행해도 된다.

$ npm install --save ts-node 

$ ts-node ./index.ts



참조

https://basarat.gitbooks.io/typescript/docs/quick/nodejs.html

- https://nodemon.io/

- https://github.com/TypeStrong/ts-node


posted by 윤영식
2016. 11. 11. 20:18 Meteor

미티어 스쿨에서 미티어를 다시 들여다보기 시작. 



미티어 설치 


$ curl https://install.meteor.com/ | sh


프로젝트 생성


$ meteor create addressBook

 Downloading templating-compiler@1.2.1...  [====================       ] 74% 5.1s



수행하기 

  - 의존성 관리는 미티어가 알아서 한다

  - --production 옵션을 주면 여러개의 파일을 한개 파일로 번들링 해준다 

$ cd addressBook

$ meteor run 


에러 발생시 

$ meteor npm install --save babel-runtime




MongoDB


몽고디비 접근 

  - wired tiger 적용

  - 기본 3001 포트를 사용

$ meteor mongo

MongoDB shell version: 3.2.6

connecting to: 127.0.0.1:3001/meteor


local 디비 사용 

meteor:PRIMARY> show dbs

local  0.000GB

meteor:PRIMARY> use local

switched to db local

meteor:PRIMARY> show collections

me

oplog.rs

replset.election

startup_log

system.replset

meteor:PRIMARY> db.oplog.rs.find().pretty()




Meteor Shell 사용


미티어는 NodeJS위에 올라간다. 이에 대한 내용을 볼 수 있다. 

$ meteor shell



Meteor 폴더 구조


.meteor  폴더

버전 확인하기 

  .meteor/versions 파일에서 확인 가능 

$ meteor add <Module>@<version>


미티어 릴리즈 버전

  .meteor/release 에서 확인 가능

METEOR@1.4.2.1



플랫폼

  .meteor/platform

  여러 플랫폼을 지원 server, browser 또는 ios, android 등 추가 가능 

  


client

  javscript, assets 


lib

  공통 


server

  서버의 메소드를 call하고 싶을 경우, 메소드는 RPC와 유사하다 


==> client, lib, server를 자유롭게 depth로 줘서 운영이 가능하다 

posts/client

posts/lib

posts/server

house/client

house/lib

house/server


또는 


client/post

client/house

lib/post

lib/house

server/post

server/house


public 

  "/" 루트로 웹서버 구실을 한다. public을 별도의 웹서버로 올릴 수 있다. 



폴더 로딩시에 main.js파일은 가자 나중에 로딩된다. 




NPM 설치 

$ meteor npm install <module>





MongoDB 사용하기 


RDB에서의 관계에서 벗어나 도큐먼트로 표현 그리고 관계를 다시 만들어 내는 GraphDB에 관심을 가지면 종착역


  - 미티어에서는 Shard사용 안됨

  - Replica Set: Primary + Secondary1,2

  - Shard: collections을 나누어서 저장 - 키를 나누는게 중요, mongos (router)를 통해 샤드된다, 정말 큰 데이터 아닌 이상 샤드를 쓸 필요없다


GridFS


  - 바이너리 파일을 작은 Chunk단위로 쪼개서 저장한다 

  - 파일에 대한 Replication을 한다 

  - files: 파일의 정보만 존재, chunks: 실제 파일의 내용이 저장 



posted by 윤영식
2015. 8. 15. 16:09 Meteor

트위터 부트스트랩리액트 컴포넌트로 만들어 놓은 것이 이미 있어서 미티어(Meteor) 에서 사용하는 방법을 알아본다. 



설치 하기 


  - 먼저 미티어 프로젝트 하나를 생성한다. 

$ meteor create test


  - Twiiter Bootstrap 을 React로 변환해 놓은 것 

    + https://github.com/react-bootstrap/react-bootstrap

    + 사용자 메뉴얼

    + webpack을 사용해 번들을 만들었다.


  - react-bootstrap을 미티어의 패키지를 설치한다

   + https://atmospherejs.com/firfi/meteor-react-bootstrap (설명서)

   + package.js 를 추가해서 미티어의 패키지로 만들고, atmosphere에 배포했다. 

$ meteor add firfi:meteor-react-bootstrap

Package.describe({ name: 'firfi:meteor-react-bootstrap', version: '0.0.4', // Brief, one-line summary of the package. summary: 'React-bootstrap port for Meteor', // URL to the Git repository containing the source code for this package. git: 'https://github.com/Firfi/meteor-react-bootstrap', // By default, Meteor will default to using README.md for documentation. // To avoid submitting documentation, set this field to null. documentation: 'METEOR.md' }); Package.onUse(function(api) { api.versionsFrom('1.0.5'); api.use('reactjs:react@0.2.1'); api.use('twbs:bootstrap@3.3.4', 'client'); api.addFiles('dist/react-bootstrap.js'); api.export(['ReactBootstrap']); }); Package.onTest(function(api) {

});


  - 미티어에 리액트를 사용하기 위한 공식 패키지를 설치한다. 

$ meteor add react




사용 하기 


  - FlowRouter와 ReactLayout을 설치한다. 

$ meteor add kadira:flow-router

# meteor add kadira:react-layout


  - 리액트 문구가 들어 있는 파일의 확장자는 .jsx가 되어야 한다. test.jsx 파일을 하나 만들고 다음과 같이 탭을 사용한다. 

    + ReactBootstrap 이 글로벌 변수이다. 

    + 리액트 컴포넌트 (App)는 미티어에서 글로벌 변수여야 한다. 

if (Meteor.isClient) {

  

  App = React.createClass({

    render() {

      return (

        <ReactBootstrap.TabbedArea defaultActiveKey={2}>

          <ReactBootstrap.TabPane eventKey={1} tab='Tab 1'>TabPane 1 content</ReactBootstrap.TabPane>

          <ReactBootstrap.TabPane eventKey={2} tab='Tab 2'>TabPane 2 content</ReactBootstrap.TabPane>

        </ReactBootstrap.TabbedArea>

      )

    }

  });

}


  - Flow Router를 설정한다. 

// test.js 

if(Meteor.isClient) {


  FlowRouter.route('/', {

    // do some action for this route

    action: function(params, queryParams) {

        // console.log("Params:", params);

        // console.log("Query Params:", queryParams);

        // ReactLayout.render(AppLayout, {

        //  content: <MainComponent />

        // })

        ReactLayout.render(App);

    }

  });

  

}


// test.html 

<head>

  <title>test</title>

</head>


  - 탭 결과 화면이 출력된다.

  



오류 해결


  - 크롬 DevTools에 React extension을 설치하고 결과를 보면 다음과 같이 <Unknown> 태그가 나온다. 

    

 - <Unknown>을 제거하기 위해 displayName을 지정한다. 

if (Meteor.isClient) {

  

  App = React.createClass({

    displayName: 'App',


    render() {

      return (

        <ReactBootstrap.TabbedArea defaultActiveKey={2}>

          <ReactBootstrap.TabPane eventKey={1} tab='Tab 1'>TabPane 1 content</ReactBootstrap.TabPane>

          <ReactBootstrap.TabPane eventKey={2} tab='Tab 2'>TabPane 2 content</ReactBootstrap.TabPane>

        </ReactBootstrap.TabbedArea>

      )

    }

  });

}







<참조>


  - npm을 미티어에서 직접 사용하고자 할 경우 meteorhacks:npm의 설정 가이드


posted by 윤영식
2014. 5. 28. 21:20 AngularJS/Start MEAN Stack

다국어 처리를 Angular.js 기반인 클라이언트단에서 처리하는 방법에 대해 알아본다. angular-translateangular-gettext 두가지가 존재하는데 여기서는 angular-gettext를 살펴보도록 한다 



준비사항

  - 먼저 poedit을 설치한다. 언어 번역을 일괄적으로 관리할 수 있는 툴이다. 기본 영문에서 한글 번역내역을 입력하여 언어별로 .po 파일을 관리한다 

  - angular-gettext 모듈을 사용한다. --save 옵션넣어서 bower.json 업데이트 한다. 인스톨 가이드를 참조한다 

$ bower install angular-gettext --save

  - grunt-angular-gettext 를 설치한다. --save-dev 옵션. 해당 모듈은 .po파일을 생성하거나 생성된 내용을 angular 자바스크립트로 변환을 담당한다 

$ npm install grunt-angular-gettext --save-dev



Grunt Config 수정

  - grunt-angular-gettext를 통하여 poedit에서 읽을 수 있는 원본 파일(.pot)을 생성하고, 원본에서 다른 언어의 번역을 넣은 파일(.po)을 읽어서 angular 형식의 자바스크립트 파일을 생성한다. 

  - Gruntfile.js 첨부내역

    + nggettext_extract : 다국어 지원이 필요한 .html을 읽어서 원본 origin_template.pot 파일 생성 위치와 파일명 지정

    + nggettext_compile : 다국어 .po 파일을 읽어서 angular 형식의 파일을 만들 위치와 파일명 지정. 

                                   별도의 모듈로 gettext_translation을 적용한다 

    // Translation for multi-lang

    nggettext_extract: {

      pot: {

        files: {

          'app/translation/po/origin_template.pot': [

            'app/index.html',

            'app/views/**/*.html',

            'app/domain/**/*.html'

          ]

        }

      },

    },

    nggettext_compile: {

      all: {

        options: {

          module: 'gettext_translation'

        },

        files: {

          'app/translation/translation.js': ['app/translation/po/*.po']

        }

      },

    }, 



다국어 지원 자바스크립트 생성 작업

  - html 수정 : 다국어 지원이 필요한 부분에 translate 애트리뷰트를 넣는다. 한줄은 <span></span> 태그를 사용한다

    <form name="signupForm" novalidate>

        <div class="session-signup-main-subject">

            <span translate>Create an Account</span>

        </div>

        <div class="session-signup-name-subject">

            <span translate>Name</span> 

            <span style="color:red" ng-show="focusName" translate> @Please input your full name.</span>

        </div>

        <input type="text" name="user_name" placeholder="{{'Enter Full Name'|translate}}" class="session-signup-name-input" ng-model="user.name" required sg-focus="focusName">

        <div class="session-signup-email-subject">

            <span translate>Email</span> 

            <span style="color:red" ng-show="focusEmail" translate> @Please input your email.</span>

        </div>

        <input type="email" name="user_email" placeholder="{{'Enter Email'|translate}}" class="session-signup-email-input" ng-model="user.email" required sg-focus="focusEmail">

        <div class="session-signup-password-subject">

            <span translate>Password</span> 

            <span style="color:red" ng-show="focusPassword" translate> @Please input your password.</span>

        </div>

        <input type="password" name="user_password" placeholder="{{'Enter Password'|translate}}" class="session-signup-password-input" ng-model="user.password" required sg-focus="focusPassword">

        <div class="session-signup-have">

            <span translate>Have an account?</span>

        </div>

        <a ui-sref="signin" class="session-signup-login-btn">

            <span translate>Log-in</span>

        </a>

        <button class="session-signup-create-btn" ng-click="signup(signupForm)">

            <div class="session-signup-create-btn-text">

                <span translate>Create New Account</span>

            </div>

        </button>

    <form> 


  - grunt를 통해서 html의 translate 을 해석하여 origin_template.pot파일을 생성한다

$ grunt nggettext_extract


  - origin_template.pot 파일을 poedit로 import 한다. 한글을 언어로 설정하여 번역을 한후, ko_KR.po 파일을 생성한다.

    + 새 번역 만들기 클릭 후 origin_template.pot파일 선택한 후 번역 언어 선택함  

    

    + 번역을 입력하고 "다른 이름으로 저장하기..."를 선택하여 ko_KR.po 파일을 만든다 

    


  - 번역된 ko_KR.po 파일 내역을 translate.js 파일로 만들기 

$ grunt nggettext_compile 


// ko_KR.po 파일 내역

msgid ""

msgstr ""

"Project-Id-Version: \n"

"POT-Creation-Date: \n"

"PO-Revision-Date: 2014-05-27 16:20+0900\n"

"Last-Translator: \n"

"Language-Team: \n"

"Language: ko_KR\n"

"MIME-Version: 1.0\n"

"Content-Type: text/plain; charset=UTF-8\n"

"Content-Transfer-Encoding: 8bit\n"

"X-Generator: Poedit 1.6.5\n"

"X-Poedit-Basepath: .\n"

"Plural-Forms: nplurals=1; plural=0;\n"


#: app/domain/session/signup/signup.html

msgid "@Please input your email."

msgstr "@이메일주소를 입력해 주세요."


#: app/domain/session/signup/signup.html

msgid "@Please input your full name."

msgstr "@전체 이름을 입력해 주세요."


#: app/domain/session/signup/signup.html

msgid "@Please input your password."

msgstr "@전체 패스워드를 입력해 주세요."


#: app/domain/session/signup/signup.html

msgid "Create New Account"

msgstr "신규 계정 생성"


#: app/domain/session/signup/signup.html

msgid "Create an Account"

msgstr "계정 생성"


#: app/domain/session/signup/signup.html

msgid "Email"

msgstr "이메일"


#: app/domain/session/signup/signup.html

msgid "Enter Email"

msgstr "이메일 입력"


#: app/domain/session/signup/signup.html

msgid "Enter Full Name"

msgstr "이름 입력"


#: app/domain/session/signup/signup.html

msgid "Enter Password"

msgstr "패스워드 입력"


#: app/domain/session/signup/signup.html

msgid "Have an account?"

msgstr "계정이 있나요?"


#: app/domain/session/signup/signup.html

msgid "Log-in"

msgstr "로그인"


#: app/domain/session/signup/signup.html

msgid "Name"

msgstr "이름"


#: app/domain/session/signup/signup.html

msgid "Password"

msgstr "패스워드"



// translate.js 파일로 ko_KR.po 파일을 기반으로 생성된 내역 

angular.module('gettext_translation').run(['gettextCatalog', function (gettextCatalog) {

/* jshint -W100 */

    gettextCatalog.setStrings('ko_KR', {"@Please input your email.":"@이메일주소를 입력해 주세요.","@Please input your full name.":"@전체 이름을 입력해 주세요.","@Please input your password.":"@전체 패스워드를 입력해 주세요.","Create New Account":"신규 계정 생성","Create an Account":"계정 생성","Email":"이메일","Enter Email":"이메일 입력","Enter Full Name":"이름 입력","Enter Password":"패스워드 입력","Have an account?":"계정이 있나요?","Log-in":"로그인","Name":"이름","Password":"패스워드"});

/* jshint +W100 */

}]);


  - 별도의 모듈 gettext_translation을 생성하고 index.html에 파일들을 추가한다  

// translationModule.js 을 생성

angular.module('gettext_translation', []); 


// index.html에 <script>도 추가한다 

<script src="bower_components/angular-gettext/dist/angular-gettext.js"></script>

<script src="translation/translationModule.js"></script>

<script src="translation/translation.js"></script>


  - 메인 애플리케이션인 App.js 에 gettext와 gettext_translation모듈을 추가하고, run 메소드에 언어 설정을 한다

var App = angular.module('studyGpsApp', [

  'ngCookies',

  'ngResource',

  'ngSanitize',

  'ui.router',

  'ui.bootstrap',

  'restangular',

  'gettext',

  'gettext_translation'

]);


App.run(function ($rootScope, gettextCatalog) {

    //translate for multi-lang

    $rootScope.setLang = function(lang, isDebug) {

      if(lang) {

        gettextCatalog.currentLanguage = lang;

      } else {

        gettextCatalog.currentLanguage = 'ko_KR';

      }

      gettextCatalog.debug = isDebug;

    }

    // init

    $rootScope.setLang('ko_KR', true);


  - 결과화면

  



지속적인 번역 파일 만들기 

  - 만일 화면이 추가되어 신규 번역이 필요할 경우 다음과 같이 수행을 하면 추가된 부분만 따로 설정 할 수 있다. 

  - poedit을 사용하게 되면 html 마다 반복적으로 사용되는 용어의 중복을 unique하게 관리 할 수 있고, 별도의 .js 코딩을 할 필요가 없다.

  - 많은 언어를 관리해야 한다면 poedit을 통해 관리 편의성을 얻을 수 있다

// 먼저 origin_template.pot 파일을 생성한다 

$ grunt nggettext_extract


// poedit 에서 ko_KR.po 파일을 open 한 후에 다음의 메뉴를 선택하고 origin_template.pot를 선택하면 새롭게 추가된 번역할 내역이 자동으로 ko_KR.po 파일에 추가되어 나온다 

// 이제 <언어별>.po 파일들을 translate.js 파일로 만든다. 

$ grunt nggetext_compile 


* angular-translate 모듈이 있는데 해당 모듈은 html 화면에 기본 랭귀지가 아닌 KEY값을 넣어서 바인딩해야 하는 번거로움이 존재하고, poedit와 같은 도구를 통한 번역의 편리성을 제공하지 않는다. 



Gulp를 사용할 때

  - gulp용의 angular-gettext를 설치한다. 물론 gulp도 설치한다. 

$ npm install gulp 

$ npm install gulp-angular-gettext

  

  - gulpfile.js 의 설정 내역

    + gulp-rename 플러그인을 이용해서 파일명을 바꾼다. 

    + translation 할때는 format을 javascript로 한다. 포맷은 json과 javascript가 있다.

var rename = require('gulp-rename');

var gettext = require('gulp-angular-gettext');


gulp.task('lang', ['extract', 'translation']);

gulp.task('extract', function() {

  return gulp.src(['./www/app/**/*.html'])

             .pipe(gettext.extract('origin_template.pot', {}))

             .pipe(gulp.dest('./www/lib/common/translation/po/'));

});


gulp.task('translation', function() {

  return gulp.src('./www/lib/common/translation/po/*.po')

             .pipe(gettext.compile({

                module: 'mb.translation',

                format: 'javascript'

             }))

             .pipe(rename('lib/common/translation/translation.js'))

             .pipe(gulp.dest('./www'));

});




<참조>

  - AngularJS Multi-Language Support

  - AngularJS GetText Homepage

  - Grunt Angular GetText GitHub

  - angular-translate Hompage


posted by 윤영식
2013. 8. 14. 14:32 NodeJS/Modules

Node.js 프로젝트에서 사용된 자신의 모듈을 공유하고 싶다면 NPM Regsitry를 이용하면 된다. Publis Registry에 등록하고 사용하는 방법에 대해 알아보자 



1. NPM Registry

  - NPM Registry는 누구나 Node.js에서 사용할 수 있는 모듈을 일정한 양식만 갖춘다면 등록할 수 있고,  

    npm 명령을 통하여 Module Registry 에서 필요한 모듈을 설치할 수 있다

  - 홈페이지 : https://npmjs.org/

  - 홈페이지에서 계정을 미리 생성해 놓자 : 자신이 등록한 모듈 목록을 볼 수 있다

    




2. 배포전 준비하기 

  - .npmignore 파일 : npm 저장소에 배포하지 않을 것들에 대해 열거한다. 해당 파일이 없을 경우 .gitignore를 사용한다 

// .gitignore 내역 

.DS_Store

.git*

node_modules/

  - 모듈이 이미 GitHub에 등록되고 npm init을 통하여 package.json 파일 내역이 정확히 장성되었음을 가정한다 (참조)

// package.json 내역 

// 주의)

// npm init으로 해당 파일 생성시 engines 내역은 포함되지 않는 관계로 사용하는 Node.js 버전을 명시하여 준다 

// name : 값은 대문자와 띄워쓰기 없이 소문자로 이어서 작성한다 

// version : semantic versioning을 사용한다 major.minor.patch

// main : 프로그램 진입점

// test : 테스트 프로그램 수행 스크립트 명령 (npm test)

{

  "name": "mobiconstatistics",

  "version": "0.0.1",

  "description": "include statistics function such as the moving average",

  "main": "./lib/mobiconStatistics.js",

  "engines": { "node": ">= 0.10.0" }, 

  "dependencies": {

    "underscore": "~1.5.1"

  },

  "devDependencies": { 

    "mocha": "latest",

    "should": "~1.2.2"

  },

  "scripts": {

    "test": "mocha test/*.js"

  },

  "repository": {

    "type": "git",

    "url": "https://github.com/ysyun/mobiconStatistics.git"

  },

  "keywords": [

    "mobicon",

    "statistics",

    "movingAverage"

  ],

  "author": "yun youngsik",

  "license": "MIT",

  "bugs": {

    "url": "https://github.com/ysyun/mobiconStatistics/issues"

  }

}




3. 배포하기 

  - https://www.npmjs.org/ 사이트에 가입을 한다.

  - 모듈 디렉토리로 이동하고 사용자를 추가합니다 : npm adduser 

  - 가입했던 username과 password등을 입력하면 된다.

Users/development/node-modules/mobiconStatistics> npm adduser

Username: (ysyun)

Password: 

Email: 

  - 모듈 배포전 npm install이 잘 되는지 테스트 합니다 

    test 폴더를 하나 만들어서 기존에 만든 모듈을 install 해봅니다. test 폴더에 node_modules/mobiconstatistics 모듈을 설치되면 성공!

/Users/development/node-modules/mobiconStatistics> mkdir ../mobiconStatistics-installTest

/Users/development/node-modules/mobiconStatistics> cd ../mobiconStatistics-installTest

/Users/development/node-modules/mobiconStatistics-installTest> npm install ../mobiconStatistics

npm http GET https://registry.npmjs.org/underscore

npm http 304 https://registry.npmjs.org/underscore

mobiconstatistics@0.0.1 node_modules/mobiconstatistics

└── underscore@1.5.1


/Users//development/node-modules/mobiconStatistics-installTest/node_modules/mobiconstatistics> ls

-rw-r--r--  1   staff  1096  8 13 17:09 LICENSE

drwxr-xr-x  3   staff   102  8 13 17:31 test

drwxr-xr-x  3   staff   102  8 13 17:41 lib

-rw-r--r--  1   staff    49  8 14 11:26 .travis.yml

-rw-r--r--  1   staff   904  8 14 11:34 README.md

-rw-r--r--  1   staff  1881  8 14 14:19 package.json

drwxr-xr-x  3   staff   102  8 14 14:19 node_modules

  - 모듈을 배포합니다 : npm publish

Users//development/node-modules/mobiconStatistics> npm publish                          

npm http PUT https://registry.npmjs.org/mobiconstatistics

npm http 201 https://registry.npmjs.org/mobiconstatistics

npm http GET https://registry.npmjs.org/mobiconstatistics

npm http 200 https://registry.npmjs.org/mobiconstatistics

npm http PUT https://registry.npmjs.org/mobiconstatistics/-/mobiconstatistics-0.0.1.tgz/-rev/1-b8e34dc09489f8c4c9ece305d250264a

npm http 201 https://registry.npmjs.org/mobiconstatistics/-/mobiconstatistics-0.0.1.tgz/-rev/1-b8e34dc09489f8c4c9ece305d250264a

npm http PUT https://registry.npmjs.org/mobiconstatistics/0.0.1/-tag/latest

npm http 201 https://registry.npmjs.org/mobiconstatistics/0.0.1/-tag/latest

+ mobiconstatistics@0.0.1

  - 모듈이 잘 배포되었는지 확인합니다 : http://npmjs.org/package/<모듈명>

    예) https://npmjs.org/package/mobiconstatistics

    




4. 모듈 사용하기 

  - 이제 npm registry로 자신의 모듈이 배포되었으므로 프로젝트에 첨부하여 사용할 수 있게 되었습니다. 

// mobiconstatistics 모듈 추가하기 

/Users/development/smart-solutions/SmartStatistics> npm install mobiconstatistics --save

npm http GET https://registry.npmjs.org/mobiconstatistics

npm http 200 https://registry.npmjs.org/mobiconstatistics

mobiconstatistics@0.0.1 node_modules/mobiconstatistics


// 프로젝트의 package.json에 mobiconstatistics 모듈 추가

/Users/development/smart-solutions/SmartStatistics> cat package.json

{

  "name": "smartstatistics",

  "version": "0.0.0",

  "dependencies": {

    "sails": "0.8.9",

    "express": "~3.2.6",

    "ejs": "~0.8.4",

    "underscore": "~1.5.1",

    "mobiconstatistics": "0.0.1"

  },

  - 트위터에서 npm registry에 배포된 모듈중 괜찮은 것들을 정리하여 트윗을 해준다 : @nodenpm

    



<참조>

  - Node.js 소개 in opentutorial

  - npm 이란? 

  - Node Module NPM Registry 등록하기

  - npm developer 가이드

posted by 윤영식
prev 1 next