diff --git a/.gitignore b/.gitignore
index a41d831b28..0072ff5528 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@ _authortools
node_modules
package-lock.json
_benchmarks/benchmarker/benchmarker.exe
-_benchmarks/benchmarker/platforms
\ No newline at end of file
+_benchmarks/benchmarker/platforms
+go.sum
\ No newline at end of file
diff --git a/HISTORY.md b/HISTORY.md
index 04d64f8d43..7046d410f0 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -19,7 +19,53 @@
Developers are not forced to upgrade if they don't really need it. Upgrade whenever you feel ready.
-**How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris@master`.
+**How to upgrade**: Open your command-line and execute this command: `go get github.com/kataras/iris/v12@latest`.
+
+# Fr, 13 December 2019 | v12.1.0
+
+## Breaking Changes
+
+Minor as many of you don't even use them but, indeed, they need to be covered here.
+
+- Old i18n middleware(iris/middleware/i18n) was replaced by the [i18n](i18n) sub-package which lives as field at your application: `app.I18n.Load(globPathPattern string, languages ...string)` (see below)
+- Community-driven i18n middleware(iris-contrib/middleware/go-i18n) has a `NewLoader` function which returns a loader which can be passed at `app.I18n.Reset(loader i18n.Loader, languages ...string)` to change the locales parser
+- The Configuration's `TranslateFunctionContextKey` was replaced by `LocaleContextKey` which Context store's value (if i18n is used) returns the current Locale which contains the translate function, the language code, the language tag and the index position of it
+- The `context.Translate` method was replaced by `context.Tr` as a shortcut for the new `context.GetLocale().GetMessage(format, args...)` method and it matches the view's function `{{tr format args}}` too
+- If you used [Iris Django](https://github.com/kataras/iris/tree/master/_examples/view/template_django_0) view engine with `import _ github.com/flosch/pongo2-addons` you **must change** the import path to `_ github.com/iris-contrib/pongo2-addons` or add a [go mod replace](https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive) to your `go.mod` file, e.g. `replace github.com/flosch/pongo2-addons => github.com/iris-contrib/pongo2-addons v0.0.1`.
+
+## Fixes
+
+All known issues.
+
+1. [#1395](https://github.com/kataras/iris/issues/1395)
+2. [#1369](https://github.com/kataras/iris/issues/1369)
+3. [#1399](https://github.com/kataras/iris/issues/1399) with PR [#1400](https://github.com/kataras/iris/pull/1400)
+4. [#1401](https://github.com/kataras/iris/issues/1401)
+5. [#1406](https://github.com/kataras/iris/issues/1406)
+6. [neffos/#20](https://github.com/kataras/neffos/issues/20)
+7. [pio/#5](https://github.com/kataras/pio/issues/5)
+
+## New Features
+
+### Internationalization and localization
+
+Support for i18n is now a **builtin feature** and is being respected across your entire application, per say [sitemap](https://github.com/kataras/iris/wiki/Sitemap) and [views](https://github.com/kataras/iris/blob/master/_examples/i18n/main.go#L50).
+
+Refer to the wiki section: https://github.com/kataras/iris/wiki/Sitemap for details.
+
+### Sitemaps
+
+Iris generates and serves one or more [sitemap.xml](https://www.sitemaps.org/protocol.html) for your static routes.
+
+Navigate through: https://github.com/kataras/iris/wiki/Sitemap for more.
+
+## New Examples
+
+2. [_examples/i18n](_examples/i18n)
+1. [_examples/sitemap](_examples/sitemap)
+3. [_examples/desktop-app/blink](_examples/desktop-app/blink)
+4. [_examples/desktop-app/lorca](_examples/desktop-app/lorca)
+5. [_examples/desktop-app/webview](_examples/desktop-app/webview)
# Sa, 26 October 2019 | v12.0.0
diff --git a/HISTORY_ES.md b/HISTORY_ES.md
index b1ac2bd647..6da9b9382d 100644
--- a/HISTORY_ES.md
+++ b/HISTORY_ES.md
@@ -19,7 +19,11 @@
Los desarrolladores no están obligados a actualizar si realmente no lo necesitan. Actualice siempre que se sienta listo.
-**Cómo actualizar**: Abra su línea de comandos y ejecute este comando: `go get github.com/kataras/iris@master`.
+**Cómo actualizar**: Abra su línea de comandos y ejecute este comando: `go get github.com/kataras/iris/v12@latest`.
+
+# Fr, 13 December 2019 | v12.1.0
+
+Not translated yet, please navigate to the [english version](HISTORY.md#fr-13-december-2019--v1210) instead.
# Sábado, 26 de octubre 2019 | v12.0.0
diff --git a/NOTICE b/NOTICE
index cca000993c..b86f00a5b2 100644
--- a/NOTICE
+++ b/NOTICE
@@ -29,13 +29,10 @@ Revision ID: 607b5b7cef034da2692f99a4c9bafb31a999ccda
11767721ed
columnize 9e6335e58db3b4c https://github.com/ryanuber/columnize
fe3c3c5c881f51f
- fbc1091b34
- formBinder fbd5963f41e18ae https://github.com/iris-contrib/
- 1f1423ba0462350 formBinder
- 94b0721ea1
- go e369490fb7db5f2 https://github.com/golang/go
- d42bb0e8ee19b48
- 378dee0ebf
+ fbc1091b34
+ go c39cd41e5e0c8cd https://github.com/golang/go
+ bc910e0e0214a36
+ 0ec7829c07
go-version 192140e6f3e645d https://github.com/hashicorp/go-version
971b134d4e35b51
91adb9dfd3
@@ -48,24 +45,21 @@ Revision ID: 607b5b7cef034da2692f99a4c9bafb31a999ccda
goreferrer ec9c9a553398739 https://github.com/Shopify/goreferrer
f0dcf817e0ad5e0
1c4e7dcd08
- httpexpect ebe99fcebbcedf6 https://github.com/iris-contrib/
- e7916320cce24c3 httpexpect
- e1832766ac
- i18n 987a633949d087b https://github.com/iris-contrib/i18n
- a52207b587792e8
- c67d65780b
+ httpexpect 0387206792097a6 https://github.com/gavv/httpexpect
+ dc6fd830ac268a6
+ f1953194f1
jade 9ffefa50b5f3141 https://github.com/Joker/jade
6ac643e9d9ad611
6f4688705f
json-iterator 08047c174c6c03e https://github.com/json-iterator/go
8ec963a411bde1b
6d1ee67b26
- neffos c6806f19261108f https://github.com/kataras/neffos
- bc1281e21faa79d
- 7193b36097
- pongo2 8914e1cf9164420 https://github.com/flosch/pongo2
- c91423cdefc7d97
- 8a76c38213
+ neffos eb5c6fbe548cf13 https://github.com/kataras/neffos
+ 2812142b9ab1633
+ ca79911ae6
+ pongo2 0738cc45f23da6a https://github.com/iris-contrib/pongo2
+ 8c14959779a75d3
+ 37b7944fb6
raymond b565731e1464263 https://github.com/aymerick/raymond
de0bda75f2e45d9
7b54b60110
diff --git a/README.md b/README.md
index 548a5d07f7..9d51b3252f 100644
--- a/README.md
+++ b/README.md
@@ -7,13 +7,15 @@
-[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://www.paypal.me/kataras)
+[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![donate on PayPal](https://img.shields.io/badge/support-PayPal-blue.svg?style=for-the-badge)](https://www.paypal.me/kataras)
Iris is a fast, simple yet fully featured and very efficient web framework for Go. It provides a beautifully expressive and easy to use foundation for your next website or API.
Learn what [others saying about Iris](https://iris-go.com/testimonials/) and **[star](https://github.com/kataras/iris/stargazers)** this open-source project to support its potentials.
-[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
+[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/)
+
+> **NEW:** Iris version 12.1.0 has been released. Follow [this link](HISTORY.md#fr-13-december-2019--v1210) to discover more
## Learning Iris
diff --git a/README_ES.md b/README_ES.md
index 4ebcbb1bff..ae6c2633da 100644
--- a/README_ES.md
+++ b/README_ES.md
@@ -2,13 +2,13 @@
# Iris
-[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
+[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
Iris es un framework web rápido, simple pero con muchas funcionalidades y muy eficiente para Go. Proporciona una base bellamente expresiva y fácil de usar para su próximo sitio web o API.
Descubra lo que [otros dicen sobre Iris](https://iris-go.com/testimonials/) y **siga** :star: este repositorio github.
-[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
+[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/)
## Aprende Iris
diff --git a/README_FA.md b/README_FA.md
index 7a9fb7dc59..eadea89804 100644
--- a/README_FA.md
+++ b/README_FA.md
@@ -4,14 +4,14 @@
# آیریس
-[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
+[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
آیریس سریع ترین و ساده ترین و موثرترین فریمورک وب در زبان GO میباشد. آیریس ساختاری بسیار زیبا و کارآمد را فراهم کرده است تا شما از آن برای پروژه های بعدی تان استفاده کنید. .
برای این که بدانید دیگران در مورد آیریس چه می گویند لطفا در این لینک کلیک کنید [دیگران در مورد آیریس چه می گویند](https://iris-go.com/testimonials/) لطفا این پروژه را در گیتاب **استار** کنید.
-[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
+[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/)
## آموزش آیریس
diff --git a/README_GR.md b/README_GR.md
index 5045e8b885..d58bc1ef32 100644
--- a/README_GR.md
+++ b/README_GR.md
@@ -1,12 +1,12 @@
# Iris
-[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
+[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
Το Iris είναι ένα γρήγορο, απλό αλλά και πλήρως λειτουργικό και πολύ αποδοτικό web framework για τη Go γλώσσα προγραμματισμού. Παρέχει ένα εκφραστικό και εύχρηστο υπόβαθρο για την επόμενη ιστοσελίδα σας.
Μάθετε τι [λένε οι άλλοι για το Iris](https://iris-go.com/testimonials/) και δώστε ένα **αστεράκι** στο GitHub.
-[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
+[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/)
## Μαθαίνοντας το Iris
diff --git a/README_KO.md b/README_KO.md
index 5f92d77252..8e2d4abe22 100644
--- a/README_KO.md
+++ b/README_KO.md
@@ -1,12 +1,12 @@
# Iris
-[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
+[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
Iris는 단순하고 빠르며 좋은 성능과 모든 기능을 갖춘 Go언어용 웹 프레임워크입니다. 당신의 웹사이트나 API를 위해서 아름답고 사용하기 쉬운 기반을 제공합니다.
[여러 사람들의 의견](https://iris-go.com/testimonials/)을 둘러보세요. 그리고 이 github repository을 **star**하세요.
-[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
+[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/)
## Iris 배우기
diff --git a/README_ZH.md b/README_ZH.md
index caf78eeeec..86ba8c030e 100644
--- a/README_ZH.md
+++ b/README_ZH.md
@@ -1,12 +1,12 @@
# Iris
-[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
+[![build status](https://img.shields.io/travis/kataras/iris/master.svg?style=for-the-badge&logo=travis)](https://travis-ci.org/kataras/iris) [![report card](https://img.shields.io/badge/report%20card-a%2B-ff3333.svg?style=for-the-badge)](https://goreportcard.com/report/github.com/kataras/iris) [![view examples](https://img.shields.io/badge/learn%20by-examples-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/tree/master/_examples) [![chat](https://img.shields.io/gitter/room/iris_go/community.svg?color=blue&logo=gitter&style=for-the-badge)](https://gitter.im/iris_go/community) [![release](https://img.shields.io/badge/release%20-v11.2-0077b3.svg?style=for-the-badge)](https://github.com/kataras/iris/releases)
Iris 是基于 Go 编写的一个快速,简单但功能齐全且非常高效的 Web 框架。 它为您的下一个网站或 API 提供了一个非常富有表现力且易于使用的基础。
看看 [其他人如何评价 Iris](https://iris-go.com/testimonials/),同时欢迎各位点亮 **star**。
-[![](https://media.giphy.com/media/eGku4UbilECflFjcNj/giphy.gif)](https://iris-go.com/testimonials/)
+[![](https://media.giphy.com/media/j5WLmtvwn98VPrm7li/giphy.gif)](https://iris-go.com/testimonials/)
## 学习 Iris
diff --git a/VERSION b/VERSION
index 50c9b74880..020d661e92 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-12.0.2:https://github.com/kataras/iris/releases/tag/v12.0.2
\ No newline at end of file
+12.1.0:https://github.com/kataras/iris/releases/tag/v12.1.0
\ No newline at end of file
diff --git a/_examples/README.md b/_examples/README.md
index ea8c8a7d35..7522d839dd 100644
--- a/_examples/README.md
+++ b/_examples/README.md
@@ -60,7 +60,7 @@ Structuring depends on your own needs. We can't tell you how to design your own
### HTTP Listening
- [Common, with address](http-listening/listen-addr/main.go)
- * [public domain address](http-listening/listen-addr-public/main.go) **NEW**
+ * [public domain address](http-listening/listen-addr-public/main.go)
* [omit server errors](http-listening/listen-addr/omit-server-errors/main.go)
- [UNIX socket file](http-listening/listen-unix/main.go)
- [TLS](http-listening/listen-tls/main.go)
@@ -70,7 +70,7 @@ Structuring depends on your own needs. We can't tell you how to design your own
* [common net.Listener](http-listening/custom-listener/main.go)
* [SO_REUSEPORT for unix systems](http-listening/custom-listener/unix-reuseport/main.go)
- Custom HTTP Server
- * [HTTP/3 Quic](http-listening/http3-quic) **NEW**
+ * [HTTP/3 Quic](http-listening/http3-quic)
* [easy way](http-listening/custom-httpserver/easy-way/main.go)
* [std way](http-listening/custom-httpserver/std-way/main.go)
* [multi server instances](http-listening/custom-httpserver/multi/main.go)
@@ -133,7 +133,7 @@ Navigate through examples for a better understanding.
- [Write your own custom parameter types](routing/macros/main.go)
- [Reverse routing](routing/reverse/main.go)
- [Custom Router (high-level)](routing/custom-high-level-router/main.go)
-- [Custom Wrapper](routing/custom-wrapper/main.go) **UPDATED**
+- [Custom Wrapper](routing/custom-wrapper/main.go)
- Custom Context
* [method overriding](routing/custom-context/method-overriding/main.go)
* [new implementation](routing/custom-context/new-implementation/main.go)
@@ -152,17 +152,17 @@ Navigate through examples for a better understanding.
- [Basic](hero/basic/main.go)
- [Overview](hero/overview)
- [Sessions](hero/sessions)
-- [Yet another dependency injection example and good practises at general](hero/smart-contract/main.go) **NEW**
+- [Yet another dependency injection example and good practises at general](hero/smart-contract/main.go)
### MVC
- [Hello world](mvc/hello-world/main.go)
-- [Regexp](mvc/regexp/main.go) **NEW**
+- [Regexp](mvc/regexp/main.go)
- [Session Controller](mvc/session-controller/main.go)
- [Overview - Plus Repository and Service layers](mvc/overview)
- [Login showcase - Plus Repository and Service layers](mvc/login)
- [Singleton](mvc/singleton)
-- [Websocket Controller](mvc/websocket) **UPDATED**
+- [Websocket Controller](mvc/websocket)
- [Register Middleware](mvc/middleware)
- [Vue.js Todo MVC](tutorial/vuejs-todo-mvc)
@@ -195,11 +195,25 @@ Navigate through examples for a better understanding.
- [Pug (Jade) Actions`](view/template_pug_1)
- [Pug (Jade) Includes`](view/template_pug_2)
- [Pug (Jade) Extends`](view/template_pug_3)
-- [Jet](/view/template_jet_0) **NEW**
-- [Jet Embedded](view/template_jet_1_embedded) **NEW**
+- [Jet](/view/template_jet_0)
+- [Jet Embedded](view/template_jet_1_embedded)
You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [hero templates](https://github.com/shiyanhui/hero/hero) files too, simply by using the `context#ResponseWriter`, take a look at the [http_responsewriter/quicktemplate](http_responsewriter/quicktemplate) and [http_responsewriter/herotemplate](http_responsewriter/herotemplate) examples.
+### Localization and Internationalization
+
+- [I18n](i18n/main.go) **NEW**
+
+### Sitemap
+
+- [Sitemap](sitemap/main.go) **NEW**
+
+### Desktop App
+
+- [Using blink package](desktop-app/blink) **NEW**
+- [Using lorca package](desktop-app/lorca) **NEW**
+- [Using webview package](desktop-app/webview) **NEW**
+
### Authentication
- [Basic Authentication](authentication/basicauth/main.go)
@@ -210,23 +224,23 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
### File Server
- [Favicon](file-server/favicon/main.go)
-- [Basic](file-server/basic/main.go) **UPDATED**
-- [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go) **UPDATED**
-- [Embedding Gziped Files Into App Executable File](file-server/embedding-gziped-files-into-app/main.go) **UPDATED**
+- [Basic](file-server/basic/main.go)
+- [Embedding Files Into App Executable File](file-server/embedding-files-into-app/main.go)
+- [Embedding Gziped Files Into App Executable File](file-server/embedding-gziped-files-into-app/main.go)
- [Send/Force-Download Files](file-server/send-files/main.go)
- Single Page Applications
- * [single Page Application](file-server/single-page-application/basic/main.go) **UPDATED**
- * [embedded Single Page Application](file-server/single-page-application/embedded-single-page-application/main.go) **UPDATED**
- * [embedded Single Page Application with other routes](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go) **UPDATED**
+ * [single Page Application](file-server/single-page-application/basic/main.go)
+ * [embedded Single Page Application](file-server/single-page-application/embedded-single-page-application/main.go)
+ * [embedded Single Page Application with other routes](file-server/single-page-application/embedded-single-page-application-with-other-routes/main.go)
### How to Read from `context.Request() *http.Request`
- [Read JSON](http_request/read-json/main.go)
* [Struct Validation](http_request/read-json-struct-validation/main.go)
- [Read XML](http_request/read-xml/main.go)
-- [Read YAML](http_request/read-yaml/main.go) **NEW**
+- [Read YAML](http_request/read-yaml/main.go)
- [Read Form](http_request/read-form/main.go)
-- [Read Query](http_request/read-query/main.go) **NEW**
+- [Read Query](http_request/read-query/main.go)
- [Read Custom per type](http_request/read-custom-per-type/main.go)
- [Read Custom via Unmarshaler](http_request/read-custom-via-unmarshaler/main.go)
- [Read Many times](http_request/read-many/main.go)
@@ -238,7 +252,7 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
### How to Write to `context.ResponseWriter() http.ResponseWriter`
-- [Content Negotiation](http_responsewriter/content-negotiation) **NEW**
+- [Content Negotiation](http_responsewriter/content-negotiation)
- [Write `valyala/quicktemplate` templates](http_responsewriter/quicktemplate)
- [Write `shiyanhui/hero` templates](http_responsewriter/herotemplate)
- [Text, Markdown, HTML, JSON, JSONP, XML, Binary](http_responsewriter/write-rest/main.go)
@@ -257,16 +271,15 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
### Miscellaneous
-- [HTTP Method Override](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go) **NEW**
+- [HTTP Method Override](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go)
- [Request Logger](http_request/request-logger/main.go)
* [log requests to a file](http_request/request-logger/request-logger-file/main.go)
-- [Localization and Internationalization](miscellaneous/i18n/main.go)
- [Recovery](miscellaneous/recover/main.go)
- [Profiling (pprof)](miscellaneous/pprof/main.go)
- [Internal Application File Logger](miscellaneous/file-logger/main.go)
- [Google reCAPTCHA](miscellaneous/recaptcha/main.go)
-### Experimental Handlers
+### Community-based Handlers
- [Casbin wrapper](experimental-handlers/casbin/wrapper/main.go)
- [Casbin middleware](experimental-handlers/casbin/middleware/main.go)
@@ -324,12 +337,12 @@ iris session manager lives on its own [package](https://github.com/kataras/iris/
### Websockets
-- [Basic](websocket/basic) **NEW**
+- [Basic](websocket/basic)
* [Server](websocket/basic/server.go)
* [Go Client](websocket/basic/go-client/client.go)
* [Browser Client](websocket/basic/browser/index.html)
* [Browser NPM Client (browserify)](websocket/basic/browserify/app.js)
-- [Native Messages](websocket/native-messages/main.go) **UPDATED**
+- [Native Messages](websocket/native-messages/main.go)
- [TLS Enabled](websocket/secure/README.md)
### Typescript Automation Tools
diff --git a/_examples/README_ZH.md b/_examples/README_ZH.md
index 876e0da585..93cf7b5d72 100644
--- a/_examples/README_ZH.md
+++ b/_examples/README_ZH.md
@@ -125,6 +125,10 @@ app.Get("{root:path}", rootWildcardHandler)
- [Sessions](hero/sessions)
- [另一种依赖注入的例子和通常的较好实践](hero/smart-contract/main.go) **新**
+### i18n
+
+- [本地化和多语言支持](i18n/main.go)
+
### MVC 模式
![](mvc/web_mvc_diagram.png)
@@ -366,7 +370,6 @@ You can serve [quicktemplate](https://github.com/valyala/quicktemplate) and [her
- [HTTP Method Override](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go) **更新**
- [请求记录器](http_request/request-logger/main.go)
* [将请求记录到文件](http_request/request-logger/request-logger-file/main.go)
-- [本地化和多语言支持](miscellaneous/i18n/main.go)
- [恢复](miscellaneous/recover/main.go)
- [性能报告Profiling (pprof)](miscellaneous/pprof/main.go)
- [内部文件记录Internal Application File Logger](miscellaneous/file-logger/main.go)
diff --git a/_examples/apidoc/yaag/go.mod b/_examples/apidoc/yaag/go.mod
index ff20415488..2fe5e078c1 100644
--- a/_examples/apidoc/yaag/go.mod
+++ b/_examples/apidoc/yaag/go.mod
@@ -4,5 +4,5 @@ go 1.13
require (
github.com/betacraft/yaag v1.0.1-0.20191027021412-565f65e36090
- github.com/kataras/iris/v12 v12.0.1
+ github.com/kataras/iris/v12 v12.1.0
)
diff --git a/_examples/apidoc/yaag/go.sum b/_examples/apidoc/yaag/go.sum
deleted file mode 100644
index 7a46f58927..0000000000
--- a/_examples/apidoc/yaag/go.sum
+++ /dev/null
@@ -1,173 +0,0 @@
-github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5uPdBC/X17wanyJAMxM33+4ZhEIV96MIH8U=
-github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
-github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE=
-github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
-github.com/Joker/hpp v0.0.0-20180418125244-6893e659854a/go.mod h1:MzD2WMdSxvbHw5fM/OXOFily/lipJWRc9C1px0Mt0ZE=
-github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
-github.com/Joker/jade v1.0.0/go.mod h1:efZIdO0py/LtcJRSa/j2WEklMSAw84WV0zZVMxNToB8=
-github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8=
-github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
-github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
-github.com/betacraft/yaag v1.0.1-0.20191027021412-565f65e36090 h1:+GqA3rJ5SyB3K8OmAW6q9ue/pOz+ySnK103xUrAy/Ss=
-github.com/betacraft/yaag v1.0.1-0.20191027021412-565f65e36090/go.mod h1:/ckKeGGiG5nDlbew5K+R5EsJYdkpnUsJBg54kHdWm/0=
-github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
-github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
-github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=
-github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
-github.com/gavv/monotime v0.0.0-20171021193802-6f8212e8d10d/go.mod h1:vmp8DIyckQMXOPl0AQVHt+7n5h7Gb7hS6CUydiV8QeA=
-github.com/gin-contrib/sse v0.0.0-20190125020943-a7658810eb74/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
-github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
-github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
-github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
-github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
-github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
-github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec/go.mod h1:cOaXtrgN4ScfRrD9Bre7U1thNq5RtJ8ZoP4iXVGRj6o=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4=
-github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
-github.com/iris-contrib/formBinder v0.0.0-20190104093907-fbd5963f41e1/go.mod h1:i8kTYUOEstd/S8TG0ChTXQdf4ermA/e8vJX0+QruD9w=
-github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
-github.com/iris-contrib/httpexpect v0.0.0-20180314041918-ebe99fcebbce/go.mod h1:VER17o2JZqquOx41avolD/wMGQSFEFBKWmhag9/RQRY=
-github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
-github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA=
-github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
-github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=
-github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
-github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
-github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
-github.com/kataras/golog v0.0.0-20180321173939-03be10146386/go.mod h1:PcaEvfvhGsqwXZ6S3CgCbmjcp+4UDUh2MIfF2ZEul8M=
-github.com/kataras/golog v0.0.9 h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM=
-github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
-github.com/kataras/iris/v12 v12.0.1 h1:Wo5S7GMWv5OAzJmvFTvss/C4TS1W0uo6LkDlSymT4rM=
-github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
-github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
-github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=
-github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
-github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY=
-github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
-github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
-github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
-github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
-github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
-github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
-github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
-github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
-github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
-github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/revel/config v0.21.0/go.mod h1:GT4a9px5kDGRqLizcw/md0QFErrhen76toz4qS3oIoI=
-github.com/revel/log15 v2.11.20+incompatible/go.mod h1:l0WmLRs+IM1hBl4noJiBc2tZQiOgZyXzS1mdmFt+5Gc=
-github.com/revel/pathtree v0.0.0-20140121041023-41257a1839e9/go.mod h1:TmlwoRLDvgRjoTe6rbsxIaka/CulzYrgfef7iNJcEWY=
-github.com/revel/revel v0.21.0/go.mod h1:VZWJnHjpDEtuGUuZJ2NO42XryitrtwsdVaJxfDeo5yc=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/twinj/uuid v1.0.0/go.mod h1:mMgcE1RHFUFqe5AfiwlINXisXfDGro23fWdPUfOMjRY=
-github.com/ugorji/go v1.1.2/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/ugorji/go/codec v0.0.0-20190204201341-e444a5086c43/go.mod h1:iT03XoTwV7xq/+UGwKO3UbC1nNNlopQiY61beSdrtOA=
-github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
-github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
-github.com/xeonx/timeago v1.0.0-rc4/go.mod h1:qDLrYEFynLO7y5Ho7w3GwgtYgpy5UfhcXIIQvMKVDkA=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
-github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
-github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/fsnotify/fsnotify.v1 v1.4.7/go.mod h1:Fyux9zXlo4rWoMSIzpn9fDAYjalPqJ/K1qJ27s+7ltE=
-gopkg.in/gin-gonic/gin.v1 v1.3.0/go.mod h1:Eljh74A/zAvUOQ835v6ySeZ+5gQG6tKjbZTaZ9iWU3A=
-gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
-gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
-gopkg.in/stack.v0 v0.0.0-20141108040640-9b43fcefddd0/go.mod h1:kl/bNzW/jgTgUOCGDj3XPn9/Hbfhw6pjfBRUnaTioFQ=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/_examples/desktop-app/blink/main.go b/_examples/desktop-app/blink/main.go
new file mode 100644
index 0000000000..87ae931d36
--- /dev/null
+++ b/_examples/desktop-app/blink/main.go
@@ -0,0 +1,40 @@
+package main
+
+import (
+ "github.com/kataras/iris/v12"
+ "github.com/raintean/blink"
+)
+
+const addr = "127.0.0.1:8080"
+
+/*
+ $ go build -ldflags -H=windowsgui -o myapp.exe # build for windows
+ $ ./myapp.exe # run the app
+*/
+func main() {
+ go runServer()
+ showAndWaitWindow()
+}
+
+func runServer() {
+ app := iris.New()
+ app.Get("/", func(ctx iris.Context) {
+ ctx.HTML(" Hello Desktop
")
+ })
+ app.Run(iris.Addr(addr))
+}
+
+func showAndWaitWindow() {
+ blink.SetDebugMode(true)
+ if err := blink.InitBlink(); err != nil {
+ panic(err)
+ }
+
+ view := blink.NewWebView(false, 800, 600)
+ view.LoadURL(addr)
+ view.SetWindowTitle("My App")
+ view.MoveToCenter()
+ view.ShowWindow()
+
+ <-view.Destroy
+}
diff --git a/_examples/desktop-app/lorca/main.go b/_examples/desktop-app/lorca/main.go
new file mode 100644
index 0000000000..aa191dd562
--- /dev/null
+++ b/_examples/desktop-app/lorca/main.go
@@ -0,0 +1,40 @@
+package main
+
+import (
+ "github.com/kataras/iris/v12"
+ "github.com/zserge/lorca"
+)
+
+const addr = "127.0.0.1:8080"
+
+/*
+ $ go build -ldflags="-H windowsgui" -o myapp.exe # build for windows
+ $ ./myapp.exe # run
+*/
+func main() {
+ go runServer()
+ showAndWaitWindow()
+}
+
+func runServer() {
+ app := iris.New()
+ app.Get("/", func(ctx iris.Context) {
+ ctx.HTML("My AppHello Desktop
")
+ })
+ app.Run(iris.Addr(addr))
+}
+
+func showAndWaitWindow() {
+ webview, err := lorca.New("http://"+addr, "", 800, 600)
+ if err != nil {
+ panic(err)
+ }
+ defer webview.Close()
+
+ // webview.SetBounds(lorca.Bounds{
+ // WindowState: lorca.WindowStateFullscreen,
+ // })
+
+ // Wait for the browser window to be closed
+ <-webview.Done()
+}
diff --git a/_examples/desktop-app/webview/main.go b/_examples/desktop-app/webview/main.go
new file mode 100644
index 0000000000..3c2111392d
--- /dev/null
+++ b/_examples/desktop-app/webview/main.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+ "github.com/kataras/iris/v12"
+ "github.com/zserge/webview"
+)
+
+const addr = "127.0.0.1:8080"
+
+/*
+ # Windows requires special linker flags for GUI apps.
+ # It's also recommended to use TDM-GCC-64 compiler for CGo.
+ # http://tdm-gcc.tdragon.net/download
+ #
+ #
+ $ go build -ldflags="-H windowsgui" -o myapp.exe # build for windows
+ $ ./myapp.exe # run
+ #
+ #
+ # Note: if you see "use option -std=c99 or -std=gnu99 to compile your code"
+ # please refer to: https://github.com/zserge/webview/issues/188
+*/
+func main() {
+ go runServer()
+ showAndWaitWindow()
+}
+
+func runServer() {
+ app := iris.New()
+ app.Get("/", func(ctx iris.Context) {
+ ctx.HTML(" Hello Desktop
")
+ })
+ app.Run(iris.Addr(addr))
+}
+
+func showAndWaitWindow() {
+ webview.Open("My App",
+ addr, 800, 600, true)
+}
diff --git a/_examples/http-listening/listen-letsencrypt/main.go b/_examples/http-listening/listen-letsencrypt/main.go
index 12fcc9c808..1af9c3fdd8 100644
--- a/_examples/http-listening/listen-letsencrypt/main.go
+++ b/_examples/http-listening/listen-letsencrypt/main.go
@@ -22,6 +22,6 @@ func main() {
// NOTE: This will not work on domains like this,
// use real whitelisted domain(or domains split by whitespaces)
- // and a non-public e-mail instead.
+ // and a non-public e-mail instead or edit your hosts file.
app.Run(iris.AutoTLS(":443", "example.com", "mail@example.com"))
}
diff --git a/_examples/miscellaneous/i18n/hosts b/_examples/i18n/hosts
similarity index 100%
rename from _examples/miscellaneous/i18n/hosts
rename to _examples/i18n/hosts
diff --git a/_examples/miscellaneous/i18n/locales/locale_el-GR.ini b/_examples/i18n/locales/el-GR/locale_el-GR.ini
similarity index 100%
rename from _examples/miscellaneous/i18n/locales/locale_el-GR.ini
rename to _examples/i18n/locales/el-GR/locale_el-GR.ini
diff --git a/_examples/miscellaneous/i18n/locales/locale_multi_first_el-GR.ini b/_examples/i18n/locales/el-GR/locale_multi_first_el-GR.ini
similarity index 100%
rename from _examples/miscellaneous/i18n/locales/locale_multi_first_el-GR.ini
rename to _examples/i18n/locales/el-GR/locale_multi_first_el-GR.ini
diff --git a/_examples/miscellaneous/i18n/locales/locale_multi_second_el-GR.ini b/_examples/i18n/locales/el-GR/locale_multi_second_el-GR.ini
similarity index 100%
rename from _examples/miscellaneous/i18n/locales/locale_multi_second_el-GR.ini
rename to _examples/i18n/locales/el-GR/locale_multi_second_el-GR.ini
diff --git a/_examples/miscellaneous/i18n/locales/locale_en-US.ini b/_examples/i18n/locales/en-US/locale_en-US.ini
similarity index 100%
rename from _examples/miscellaneous/i18n/locales/locale_en-US.ini
rename to _examples/i18n/locales/en-US/locale_en-US.ini
diff --git a/_examples/miscellaneous/i18n/locales/locale_multi_first_en-US.ini b/_examples/i18n/locales/en-US/locale_multi_first_en-US.ini
similarity index 100%
rename from _examples/miscellaneous/i18n/locales/locale_multi_first_en-US.ini
rename to _examples/i18n/locales/en-US/locale_multi_first_en-US.ini
diff --git a/_examples/miscellaneous/i18n/locales/locale_multi_second_en-US.ini b/_examples/i18n/locales/en-US/locale_multi_second_en-US.ini
similarity index 100%
rename from _examples/miscellaneous/i18n/locales/locale_multi_second_en-US.ini
rename to _examples/i18n/locales/en-US/locale_multi_second_en-US.ini
diff --git a/_examples/miscellaneous/i18n/locales/locale_zh-CN.ini b/_examples/i18n/locales/zh-CN/locale_zh-CN.ini
similarity index 100%
rename from _examples/miscellaneous/i18n/locales/locale_zh-CN.ini
rename to _examples/i18n/locales/zh-CN/locale_zh-CN.ini
diff --git a/_examples/i18n/main.go b/_examples/i18n/main.go
new file mode 100644
index 0000000000..fa2dc68c94
--- /dev/null
+++ b/_examples/i18n/main.go
@@ -0,0 +1,82 @@
+package main
+
+import (
+ "github.com/kataras/iris/v12"
+)
+
+func newApp() *iris.Application {
+ app := iris.New()
+
+ // Configure i18n.
+ // First parameter: Glob filpath patern,
+ // Second variadic parameter: Optional language tags, the first one is the default/fallback one.
+ app.I18n.Load("./locales/*/*.ini", "en-US", "el-GR", "zh-CN")
+ // app.I18n.LoadAssets for go-bindata.
+
+ // Default values:
+ // app.I18n.URLParameter = "lang"
+ // app.I18n.Subdomain = true
+ //
+ // Set to false to disallow path (local) redirects,
+ // see https://github.com/kataras/iris/issues/1369.
+ // app.I18n.PathRedirect = true
+
+ app.Get("/", func(ctx iris.Context) {
+ hi := ctx.Tr("hi", "iris")
+
+ locale := ctx.GetLocale()
+
+ ctx.Writef("From the language %s translated output: %s", locale.Language(), hi)
+ })
+
+ app.Get("/some-path", func(ctx iris.Context) {
+ ctx.Writef("%s", ctx.Tr("hi", "iris"))
+ })
+
+ app.Get("/other", func(ctx iris.Context) {
+ language := ctx.GetLocale().Language()
+
+ fromFirstFileValue := ctx.Tr("key1")
+ fromSecondFileValue := ctx.Tr("key2")
+ ctx.Writef("From the language: %s, translated output:\n%s=%s\n%s=%s",
+ language, "key1", fromFirstFileValue,
+ "key2", fromSecondFileValue)
+ })
+
+ // using in inside your views:
+ view := iris.HTML("./views", ".html")
+ app.RegisterView(view)
+
+ app.Get("/templates", func(ctx iris.Context) {
+ ctx.View("index.html", iris.Map{
+ "tr": ctx.Tr, // word, arguments... {call .tr "hi" "iris"}}
+ })
+
+ // Note that,
+ // Iris automatically adds a "tr" global template function as well,
+ // the only differene is the way you call it inside your templates and
+ // that it accepts a language code as its first argument: {{ tr "el-GR" "hi" "iris"}}
+ })
+ //
+
+ return app
+}
+
+func main() {
+ app := newApp()
+
+ // go to http://localhost:8080/el-gr/some-path (by path prefix)
+ // or http://el.mydomain.com8080/some-path (by subdomain - test locally with the hosts file)
+ // or http://localhost:8080/zh-CN/templates (by path prefix with uppercase)
+ // or http://localhost:8080/some-path?lang=el-GR (by url parameter)
+ // or http://localhost:8080 (default is en-US)
+ // or http://localhost:8080/?lang=zh-CN
+ //
+ // go to http://localhost:8080/other?lang=el-GR
+ // or http://localhost:8080/other (default is en-US)
+ // or http://localhost:8080/other?lang=en-US
+ //
+ // or use cookies to set the language.
+ //
+ app.Run(iris.Addr(":8080"), iris.WithSitemap("http://localhost:8080"))
+}
diff --git a/_examples/miscellaneous/i18n/main_test.go b/_examples/i18n/main_test.go
similarity index 91%
rename from _examples/miscellaneous/i18n/main_test.go
rename to _examples/i18n/main_test.go
index 55594c8611..f625c29c5f 100644
--- a/_examples/miscellaneous/i18n/main_test.go
+++ b/_examples/i18n/main_test.go
@@ -68,15 +68,15 @@ func TestI18n(t *testing.T) {
Body().Equal(body)
}
- e.GET("/multi").WithQueryString("lang=el-GR").Expect().Status(httptest.StatusOK).
+ e.GET("/other").WithQueryString("lang=el-GR").Expect().Status(httptest.StatusOK).
Body().Equal(elgrMulti)
- e.GET("/multi").WithQueryString("lang=en-US").Expect().Status(httptest.StatusOK).
+ e.GET("/other").WithQueryString("lang=en-US").Expect().Status(httptest.StatusOK).
Body().Equal(enusMulti)
// test path prefix (i18n router wrapper).
- e.GET("/el-gr/multi").Expect().Status(httptest.StatusOK).
+ e.GET("/el-gr/other").Expect().Status(httptest.StatusOK).
Body().Equal(elgrMulti)
- e.GET("/en/multi").Expect().Status(httptest.StatusOK).
+ e.GET("/en/other").Expect().Status(httptest.StatusOK).
Body().Equal(enusMulti)
e.GET("/el-GRtemplates").Expect().Status(httptest.StatusNotFound)
diff --git a/_examples/miscellaneous/i18n/templates/index.html b/_examples/i18n/views/index.html
similarity index 63%
rename from _examples/miscellaneous/i18n/templates/index.html
rename to _examples/i18n/views/index.html
index f0dc0cad6f..32bc8a6b24 100644
--- a/_examples/miscellaneous/i18n/templates/index.html
+++ b/_examples/i18n/views/index.html
@@ -4,6 +4,6 @@ Test translate current locale template function [dynamic] ("word", ar
-Test translate of any language template function [static] ("language", "word", arguments...)
call .trLang "zh-CN" "hi" "iris"
+Test translate of any language template function [static] ("language", "word", arguments...)
tr "zh-CN" "hi" "iris"
-{{call .trLang "zh-CN" "hi" "iris"}}
+{{tr "zh-CN" "hi" "iris"}}
\ No newline at end of file
diff --git a/_examples/miscellaneous/i18n/main.go b/_examples/miscellaneous/i18n/main.go
deleted file mode 100644
index 0e42e50db0..0000000000
--- a/_examples/miscellaneous/i18n/main.go
+++ /dev/null
@@ -1,125 +0,0 @@
-package main
-
-import (
- "github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/middleware/i18n"
-)
-
-var i18nConfig = i18n.Config{
- Default: "en-US",
- Languages: map[string]string{
- "en-US": "./locales/locale_en-US.ini", // maps to en-US, en-us and en.
- "el-GR": "./locales/locale_el-GR.ini", // maps to el-GR, el-gr and el.
- "zh-CN": "./locales/locale_zh-CN.ini", // maps to zh-CN, zh-cn and zh.
- },
- // Optionals.
- // LanguagesMap: i18n.Map{
- // "en": "en-US", // now en maps to en-US
- // "el": "el-GR",
- // "zh": "zh-CN",
- // } or a custom i18n.MapFunc, defaults to accept all lowercase and [en] as [en-US] and e.t.c.
- URLParameter: "lang",
- Subdomain: true,
- // Cookie: "lang",
- // SetCookie: false,
- // Indentifier: func(ctx iris.Context) string { return "zh-CN" },
-}
-
-func newApp() *iris.Application {
- app := iris.New()
-
- i18nMiddleware := i18n.NewI18n(i18nConfig)
- app.Use(i18nMiddleware.Handler())
-
- // See https://github.com/kataras/iris/issues/1369
- // if you want to enable this (SEO) feature (OPTIONAL).
- app.WrapRouter(i18nMiddleware.Wrapper())
-
- app.Get("/", func(ctx iris.Context) {
- // Ir tries to find the language by:
- // ctx.Values().GetString("language")
- // if that was empty then
- // it tries to find from the URLParameter set on the configuration
- // if not found then
- // it tries to find the language by the "language" cookie
- // if didn't found then it it set to the Default set on the configuration
-
- // hi is the key/word, 'iris' is the %s on the .ini file
- // the second parameter is optional
-
- hi := ctx.Translate("hi", "iris")
-
- // GetTranslateLanguageContextKey() == "language"
- language := ctx.Values().GetString(ctx.Application().ConfigurationReadOnly().GetTranslateLanguageContextKey())
- // return is form of 'en-US'
-
- // The first succeed language found saved at the cookie with name ("language"),
- // you can change that by changing the value of the: iris.TranslateLanguageContextKey
- ctx.Writef("From the language %s translated output: %s", language, hi)
- })
-
- app.Get("/some-path", func(ctx iris.Context) {
- ctx.Writef("%s", ctx.Translate("hi", "iris"))
- })
-
- app.Get("/sitemap.xml", func(ctx iris.Context) {
- ctx.WriteString("sitemap")
- })
-
- // Note: It is highly recommended to use one and no more i18n middleware instances at a time,
- // the first one was already passed by `app.Use` above.
- // This middleware which registers on "/multi" route is here just for the shake of the example.
- multiLocale := i18n.New(i18n.Config{
- Default: "en-US",
- URLParameter: "lang",
- Languages: map[string]string{
- "en-US": "./locales/locale_multi_first_en-US.ini, ./locales/locale_multi_second_en-US.ini",
- "el-GR": "./locales/locale_multi_first_el-GR.ini, ./locales/locale_multi_second_el-GR.ini",
- },
- })
-
- app.Get("/multi", multiLocale, func(ctx iris.Context) {
- language := ctx.Values().GetString(ctx.Application().ConfigurationReadOnly().GetTranslateLanguageContextKey())
-
- fromFirstFileValue := ctx.Translate("key1")
- fromSecondFileValue := ctx.Translate("key2")
- ctx.Writef("From the language: %s, translated output:\n%s=%s\n%s=%s",
- language, "key1", fromFirstFileValue,
- "key2", fromSecondFileValue)
- })
-
- // using in inside your templates:
- view := iris.HTML("./templates", ".html")
- app.RegisterView(view)
-
- app.Get("/templates", func(ctx iris.Context) {
- ctx.View("index.html", iris.Map{
- "tr": ctx.Translate, // word, arguments...
- "trLang": ctx.TranslateLang, // locale, word, arguments...
- })
- // it will return "hello, iris"
- // when {{call .tr "hi" "iris"}}
- })
- //
-
- return app
-}
-
-func main() {
- app := newApp()
-
- // go to http://localhost:8080/el-gr/some-path (by path prefix)
- // or http://el.mydomain.com8080/some-path (by subdomain - test locally with the hosts file)
- // or http://localhost:8080/zh-CN/templates (by path prefix with uppercase)
- // or http://localhost:8080/some-path?lang=el-GR (by url parameter)
- // or http://localhost:8080 (default is en-US)
- // or http://localhost:8080/?lang=zh-CN
- //
- // go to http://localhost:8080/multi?lang=el-GR
- // or http://localhost:8080/multi (default is en-US)
- // or http://localhost:8080/multi?lang=en-US
- //
- // or use cookies to set the language.
- //
- app.Run(iris.Addr(":8080"))
-}
diff --git a/_examples/sitemap/main.go b/_examples/sitemap/main.go
new file mode 100644
index 0000000000..fc1d326173
--- /dev/null
+++ b/_examples/sitemap/main.go
@@ -0,0 +1,38 @@
+package main
+
+import (
+ "time"
+
+ "github.com/kataras/iris/v12"
+)
+
+const startURL = "http://localhost:8080"
+
+func main() {
+ app := newApp()
+
+ // http://localhost:8080/sitemap.xml
+ // Lists only online GET static routes.
+ //
+ // Reference: https://www.sitemaps.org/protocol.html
+ app.Run(iris.Addr(":8080"), iris.WithSitemap(startURL))
+}
+
+func newApp() *iris.Application {
+ app := iris.New()
+ app.Logger().SetLevel("debug")
+
+ lastModified, _ := time.Parse("2006-01-02T15:04:05-07:00", "2019-12-13T21:50:33+02:00")
+ app.Get("/home", handler).SetLastMod(lastModified).SetChangeFreq("hourly").SetPriority(1)
+ app.Get("/articles", handler).SetChangeFreq("daily")
+ app.Get("/path1", handler)
+ app.Get("/path2", handler)
+
+ app.Post("/this-should-not-be-listed", handler)
+ app.Get("/this/{myparam}/should/not/be/listed", handler)
+ app.Get("/this-should-not-be-listed-offline", handler).SetStatusOffline()
+
+ return app
+}
+
+func handler(ctx iris.Context) { ctx.WriteString(ctx.Path()) }
diff --git a/_examples/sitemap/main_test.go b/_examples/sitemap/main_test.go
new file mode 100644
index 0000000000..432fc9a5b5
--- /dev/null
+++ b/_examples/sitemap/main_test.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "testing"
+
+ "github.com/kataras/iris/v12"
+ "github.com/kataras/iris/v12/httptest"
+)
+
+func TestSitemap(t *testing.T) {
+ const expectedFullSitemapXML = `http://localhost:8080/home2019-12-13T21:50:33+02:00hourly1http://localhost:8080/articlesdailyhttp://localhost:8080/path1http://localhost:8080/path2`
+
+ app := newApp()
+ app.Configure(iris.WithSitemap(startURL))
+
+ e := httptest.New(t, app)
+ e.GET("/sitemap.xml").Expect().Status(httptest.StatusOK).Body().Equal(expectedFullSitemapXML)
+}
diff --git a/_examples/view/template_django_0/main.go b/_examples/view/template_django_0/main.go
index cc3af49933..6f2133b5de 100644
--- a/_examples/view/template_django_0/main.go
+++ b/_examples/view/template_django_0/main.go
@@ -6,7 +6,7 @@ import (
"github.com/kataras/iris/v12"
// optionally, registers filters like `timesince`.
- _ "github.com/flosch/pongo2-addons"
+ _ "github.com/iris-contrib/pongo2-addons"
)
var startTime = time.Now()
@@ -26,7 +26,7 @@ func main() {
app.Get("/", hi)
// http://localhost:8080
- app.Run(iris.Addr(":8080"), iris.WithCharset("UTF-8")) // defaults to that but you can change it.
+ app.Run(iris.Addr(":8080"))
}
func hi(ctx iris.Context) {
diff --git a/_examples/websocket/socketio/go.mod b/_examples/websocket/socketio/go.mod
index 3ceda6a194..f4b2d6778a 100644
--- a/_examples/websocket/socketio/go.mod
+++ b/_examples/websocket/socketio/go.mod
@@ -4,5 +4,5 @@ go 1.13
require (
github.com/googollee/go-socket.io v1.4.3-0.20191109153049-7451e2f8c2e0 // indirect
- github.com/kataras/iris/v12 v12.0.1
+ github.com/kataras/iris/v12 v12.1.0
)
diff --git a/_examples/websocket/socketio/go.sum b/_examples/websocket/socketio/go.sum
deleted file mode 100644
index 1fed304ac4..0000000000
--- a/_examples/websocket/socketio/go.sum
+++ /dev/null
@@ -1,250 +0,0 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.36.0/go.mod h1:RUoy9p/M4ge0HzT8L+SDZ8jg+Q6fth0CiBuhFJpSV40=
-dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU=
-dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU=
-dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4=
-dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU=
-git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
-github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5uPdBC/X17wanyJAMxM33+4ZhEIV96MIH8U=
-github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
-github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE=
-github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
-github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
-github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8=
-github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
-github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
-github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=
-github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
-github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
-github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
-github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
-github.com/golang/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
-github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
-github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
-github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg=
-github.com/googollee/go-engine.io v1.4.1 h1:m3WlZAug1SODuWT++UX2nbzk9IUCn9T1SnmHoqppdqo=
-github.com/googollee/go-engine.io v1.4.1/go.mod h1:26oFqHsnuWIzNOM0T08x21eQOydBosKOCgK3tyhzPPI=
-github.com/googollee/go-socket.io v1.4.3-0.20191109153049-7451e2f8c2e0 h1:eR1bDvxSmCVanIkiidLQ0K6oduB3rBKO4AuucZxdR6k=
-github.com/googollee/go-socket.io v1.4.3-0.20191109153049-7451e2f8c2e0/go.mod h1:yjlQxKcAZXZjpGwQVW/y1sgyL1ou+DdCpkswURDCRrU=
-github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gordonklaus/ineffassign v0.0.0-20180909121442-1003c8bd00dc/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
-github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4=
-github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
-github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
-github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
-github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA=
-github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
-github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
-github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=
-github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
-github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
-github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
-github.com/kataras/golog v0.0.9 h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM=
-github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
-github.com/kataras/iris/v12 v12.0.1 h1:Wo5S7GMWv5OAzJmvFTvss/C4TS1W0uo6LkDlSymT4rM=
-github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
-github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
-github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=
-github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
-github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY=
-github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
-github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
-github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
-github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
-github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
-github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
-github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
-github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo=
-github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM=
-github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
-github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
-github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
-github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0=
-github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
-github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
-github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw=
-github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI=
-github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU=
-github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag=
-github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg=
-github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw=
-github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y=
-github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
-github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q=
-github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ=
-github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I=
-github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0=
-github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ=
-github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk=
-github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4=
-github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw=
-github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE=
-github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA=
-go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE=
-golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw=
-golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190214204934-8dcb7bc8c7fe/go.mod h1:E6PF97AdD6v0s+fPshSmumCW1S1Ne85RbPQxELkKa44=
-golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
-google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
-google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
-google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
-google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
-gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck=
-sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
diff --git a/configuration.go b/configuration.go
index f928785978..54d4a91c53 100644
--- a/configuration.go
+++ b/configuration.go
@@ -12,11 +12,14 @@ import (
"os/user"
"path/filepath"
"runtime"
+ "strings"
+
+ "github.com/kataras/iris/core/netutil"
+ "github.com/kataras/iris/v12/context"
"github.com/BurntSushi/toml"
+ "github.com/kataras/sitemap"
"gopkg.in/yaml.v2"
-
- "github.com/kataras/iris/v12/context"
)
const globalConfigurationKeyword = "~"
@@ -359,11 +362,134 @@ func WithOtherValue(key string, val interface{}) Configurator {
}
}
+// WithSitemap enables the sitemap generator.
+// Use the Route's `SetLastMod`, `SetChangeFreq` and `SetPriority` to modify
+// the sitemap's URL child element properties.
+//
+// It accepts a "startURL" input argument which
+// is the prefix for the registered routes that will be included in the sitemap.
+//
+// If more than 50,000 static routes are registered then sitemaps will be splitted and a sitemap index will be served in
+// /sitemap.xml.
+//
+// If `Application.I18n.Load/LoadAssets` is called then the sitemap will contain translated links for each static route.
+//
+// If the result does not complete your needs you can take control
+// and use the github.com/kataras/sitemap package to generate a customized one instead.
+//
+// Example: https://github.com/kataras/iris/tree/master/_examples/sitemap.
+func WithSitemap(startURL string) Configurator {
+ sitemaps := sitemap.New(startURL)
+ return func(app *Application) {
+ var defaultLang string
+ if tags := app.I18n.Tags(); len(tags) > 0 {
+ defaultLang = tags[0].String()
+ sitemaps.DefaultLang(defaultLang)
+ }
+
+ for _, r := range app.GetRoutes() {
+ if !r.IsOnline() {
+ continue
+ }
+
+ if r.Subdomain != "" {
+ continue
+ }
+
+ if r.Method != MethodGet {
+ continue
+ }
+
+ if len(r.Tmpl().Params) > 0 {
+ continue
+ }
+
+ loc := r.StaticPath()
+ var translatedLinks []sitemap.Link
+
+ for _, tag := range app.I18n.Tags() {
+ lang := tag.String()
+ langPath := lang
+ href := ""
+ if lang == defaultLang {
+ // http://domain.com/en-US/path to just http://domain.com/path if en-US is the default language.
+ langPath = ""
+ }
+
+ if app.I18n.PathRedirect {
+ // then use the path prefix.
+ // e.g. http://domain.com/el-GR/path
+ if langPath == "" { // fix double slashes http://domain.com// when self-included default language.
+ href = loc
+ } else {
+ href = "/" + langPath + loc
+ }
+
+ } else if app.I18n.Subdomain {
+ // then use the subdomain.
+ // e.g. http://el.domain.com/path
+ scheme := netutil.ResolveSchemeFromVHost(startURL)
+ host := strings.TrimLeft(startURL, scheme)
+ if langPath != "" {
+ href = scheme + strings.Split(langPath, "-")[0] + "." + host + loc
+ } else {
+ href = loc
+ }
+
+ } else if p := app.I18n.URLParameter; p != "" {
+ // then use the URL parameter.
+ // e.g. http://domain.com/path?lang=el-GR
+ href = loc + "?" + p + "=" + lang
+ } else {
+ // then skip it, we can't generate the link at this state.
+ continue
+ }
+
+ translatedLinks = append(translatedLinks, sitemap.Link{
+ Rel: "alternate",
+ Hreflang: lang,
+ Href: href,
+ })
+ }
+
+ sitemaps.URL(sitemap.URL{
+ Loc: loc,
+ LastMod: r.LastMod,
+ ChangeFreq: r.ChangeFreq,
+ Priority: r.Priority,
+ Links: translatedLinks,
+ })
+ }
+
+ for _, s := range sitemaps.Build() {
+ contentCopy := make([]byte, len(s.Content))
+ copy(contentCopy, s.Content)
+
+ handler := func(ctx Context) {
+ ctx.ContentType(context.ContentXMLHeaderValue)
+ ctx.Write(contentCopy)
+ }
+ if app.builded {
+ routes := app.CreateRoutes([]string{MethodGet, MethodHead, MethodOptions}, s.Path, handler)
+
+ for _, r := range routes {
+ if err := app.Router.AddRouteUnsafe(r); err != nil {
+ app.Logger().Errorf("sitemap route: %v", err)
+ }
+ }
+ } else {
+ app.HandleMany("GET HEAD", s.Path, handler)
+ }
+
+ }
+ }
+}
+
// WithTunneling is the `iris.Configurator` for the `iris.Configuration.Tunneling` field.
// It's used to enable http tunneling for an Iris Application, per registered host
//
// Alternatively use the `iris.WithConfiguration(iris.Configuration{Tunneling: iris.TunnelingConfiguration{ ...}}}`.
-func WithTunneling(app *Application) {
+var WithTunneling = func(app *Application) {
conf := TunnelingConfiguration{
Tunnels: []Tunnel{{}}, // create empty tunnel, its addr and name are set right before host serve.
}
@@ -705,18 +831,10 @@ type Configuration struct {
// Context values' keys for various features.
//
- // TranslateLanguageContextKey & TranslateLangFunctionContextKey & TranslateFunctionContextKey are used by i18n handlers/middleware to set the selected locale's translate function.
+ // LocaleContextKey is used by i18n to get the current request's locale, which contains a translate function too.
//
- // Defaults to "iris.translate".
- TranslateFunctionContextKey string `json:"translateFunctionContextKey,omitempty" yaml:"TranslateFunctionContextKey" toml:"TranslateFunctionContextKey"`
- // TranslateLangFunctionContextKey & TranslateFunctionContextKey & TranslateLanguageContextKey are used by i18n handlers/middleware to set the global translate function.
- //
- // Defaults to "iris.languageGlobal".
- TranslateLangFunctionContextKey string `json:"translateLangFunctionContextKey,omitempty" yaml:"TranslateLangFunctionContextKey" toml:"TranslateLangFunctionContextKey"`
- // TranslateLanguageContextKey used to report the i18n selected locale.
- //
- // Defaults to "iris.language".
- TranslateLanguageContextKey string `json:"translateLanguageContextKey,omitempty" yaml:"TranslateLanguageContextKey" toml:"TranslateLanguageContextKey"`
+ // Defaults to "iris.locale".
+ LocaleContextKey string `json:"localeContextKey,omitempty" yaml:"LocaleContextKey" toml:"LocaleContextKey"`
// GetViewLayoutContextKey is the key of the context's user values' key
// which is being used to set the template
@@ -844,22 +962,10 @@ func (c Configuration) GetPostMaxMemory() int64 {
return c.PostMaxMemory
}
-// GetTranslateFunctionContextKey returns the configuration's TranslateFunctionContextKey value,
-// used for i18n inside templates.
-func (c Configuration) GetTranslateFunctionContextKey() string {
- return c.TranslateFunctionContextKey
-}
-
-// GetTranslateLangFunctionContextKey returns the configuration's TranslateLangFunctionContextKey value,
-// used for i18n inside templates.
-func (c Configuration) GetTranslateLangFunctionContextKey() string {
- return c.TranslateLangFunctionContextKey
-}
-
-// GetTranslateLanguageContextKey returns the configuration's TranslateLanguageContextKey value,
+// GetLocaleContextKey returns the configuration's LocaleContextKey value,
// used for i18n.
-func (c Configuration) GetTranslateLanguageContextKey() string {
- return c.TranslateLanguageContextKey
+func (c Configuration) GetLocaleContextKey() string {
+ return c.LocaleContextKey
}
// GetViewLayoutContextKey returns the key of the context's user values' key
@@ -972,12 +1078,8 @@ func WithConfiguration(c Configuration) Configurator {
main.PostMaxMemory = v
}
- if v := c.TranslateFunctionContextKey; v != "" {
- main.TranslateFunctionContextKey = v
- }
-
- if v := c.TranslateLanguageContextKey; v != "" {
- main.TranslateLanguageContextKey = v
+ if v := c.LocaleContextKey; v != "" {
+ main.LocaleContextKey = v
}
if v := c.ViewLayoutContextKey; v != "" {
@@ -1018,7 +1120,7 @@ func DefaultConfiguration() Configuration {
FireMethodNotAllowed: false,
DisableBodyConsumptionOnUnmarshal: false,
DisableAutoFireStatusCode: false,
- TimeFormat: "Mon, Jan 02 2006 15:04:05 GMT",
+ TimeFormat: "Mon, 02 Jan 2006 15:04:05 GMT",
Charset: "UTF-8",
// PostMaxMemory is for post body max memory.
@@ -1026,14 +1128,12 @@ func DefaultConfiguration() Configuration {
// The request body the size limit
// can be set by the middleware `LimitRequestBodySize`
// or `context#SetMaxRequestBodySize`.
- PostMaxMemory: 32 << 20, // 32MB
- TranslateFunctionContextKey: "iris.translate",
- TranslateLangFunctionContextKey: "iris.translateLang",
- TranslateLanguageContextKey: "iris.language",
- ViewLayoutContextKey: "iris.viewLayout",
- ViewDataContextKey: "iris.viewData",
- RemoteAddrHeaders: make(map[string]bool),
- EnableOptimizations: false,
- Other: make(map[string]interface{}),
+ PostMaxMemory: 32 << 20, // 32MB
+ LocaleContextKey: "iris.locale",
+ ViewLayoutContextKey: "iris.viewLayout",
+ ViewDataContextKey: "iris.viewData",
+ RemoteAddrHeaders: make(map[string]bool),
+ EnableOptimizations: false,
+ Other: make(map[string]interface{}),
}
}
diff --git a/configuration_test.go b/configuration_test.go
index f120c7c527..df9a052a26 100644
--- a/configuration_test.go
+++ b/configuration_test.go
@@ -147,7 +147,7 @@ EnablePathEscape: false
FireMethodNotAllowed: true
EnableOptimizations: true
DisableBodyConsumptionOnUnmarshal: true
-TimeFormat: "Mon, 01 Jan 2006 15:04:05 GMT"
+TimeFormat: "Mon, 02 Jan 2006 15:04:05 GMT"
Charset: "UTF-8"
RemoteAddrHeaders:
@@ -188,7 +188,7 @@ Other:
t.Fatalf("error on TestConfigurationYAML: Expected DisableBodyConsumptionOnUnmarshal %v but got %v", expected, c.DisableBodyConsumptionOnUnmarshal)
}
- if expected := "Mon, 01 Jan 2006 15:04:05 GMT"; c.TimeFormat != expected {
+ if expected := "Mon, 02 Jan 2006 15:04:05 GMT"; c.TimeFormat != expected {
t.Fatalf("error on TestConfigurationYAML: Expected TimeFormat %s but got %s", expected, c.TimeFormat)
}
@@ -244,7 +244,7 @@ EnablePathEscape = false
FireMethodNotAllowed = true
EnableOptimizations = true
DisableBodyConsumptionOnUnmarshal = true
-TimeFormat = "Mon, 01 Jan 2006 15:04:05 GMT"
+TimeFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
Charset = "UTF-8"
[RemoteAddrHeaders]
@@ -287,7 +287,7 @@ Charset = "UTF-8"
t.Fatalf("error on TestConfigurationTOML: Expected DisableBodyConsumptionOnUnmarshal %v but got %v", expected, c.DisableBodyConsumptionOnUnmarshal)
}
- if expected := "Mon, 01 Jan 2006 15:04:05 GMT"; c.TimeFormat != expected {
+ if expected := "Mon, 02 Jan 2006 15:04:05 GMT"; c.TimeFormat != expected {
t.Fatalf("error on TestConfigurationTOML: Expected TimeFormat %s but got %s", expected, c.TimeFormat)
}
diff --git a/context/application.go b/context/application.go
index 36c973a032..641d5fd02e 100644
--- a/context/application.go
+++ b/context/application.go
@@ -17,6 +17,9 @@ type Application interface {
// Logger returns the golog logger instance(pointer) that is being used inside the "app".
Logger() *golog.Logger
+ // I18nReadOnly returns the i18n's read-only features.
+ I18nReadOnly() I18nReadOnly
+
// View executes and write the result of a template file to the writer.
//
// Use context.View to render templates to the client instead.
diff --git a/context/configuration.go b/context/configuration.go
index 516de45082..2c9cd76e52 100644
--- a/context/configuration.go
+++ b/context/configuration.go
@@ -67,15 +67,9 @@ type ConfigurationReadOnly interface {
// Defaults to 32MB or 32 << 20 if you prefer.
GetPostMaxMemory() int64
- // GetTranslateLanguageContextKey returns the configuration's TranslateFunctionContextKey value,
- // used for i18n inside templates.
- GetTranslateFunctionContextKey() string
- // GetTranslateLangFunctionContextKey returns the configuration's TranslateLangFunctionContextKey value,
- // used for i18n inside templates.
- GetTranslateLangFunctionContextKey() string
- // GetTranslateLanguageContextKey returns the configuration's TranslateLanguageContextKey value,
- // used for i18n.
- GetTranslateLanguageContextKey() string
+ // GetTranslateLanguageContextKey returns the configuration's LocaleContextKey value,
+ // used for i18n. Defaults to "iris.locale".
+ GetLocaleContextKey() string
// GetViewLayoutContextKey returns the key of the context's user values' key
// which is being used to set the template
diff --git a/context/context.go b/context/context.go
index e6d6a6c12b..168934ba2c 100644
--- a/context/context.go
+++ b/context/context.go
@@ -76,7 +76,7 @@ func (u UnmarshalerFunc) Unmarshal(data []byte, v interface{}) error {
return u(data, v)
}
-// Context is the midle-man server's "object" for the clients.
+// Context is the midle-man server's "object" dealing with incoming requests.
//
// A New context is being acquired from a sync.Pool on each connection.
// The Context is the most important thing on the iris's http flow.
@@ -292,21 +292,9 @@ type Context interface {
// You can use this function to Set and Get local values
// that can be used to share information between handlers and middleware.
Values() *memstore.Store
- // Translate is the i18n (localization) middleware's function,
- // it calls the Values().Get(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey())
- // to execute the translate function and returns the current localized text value.
- //
- // Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
- Translate(format string, args ...interface{}) string
- // TranslateLang is the i18n (localization) middleware's function,
- // it calls the Values().Get(ctx.Application().ConfigurationReadOnly().GetTranslateLangFunctionContextKey())
- // to execute the translate function and returns the localized text value based on the "lang".
- //
- // Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
- TranslateLang(lang, format string, args ...interface{}) string
// +------------------------------------------------------------+
- // | Path, Host, Subdomain, IP, Headers etc... |
+ // | Path, Host, Subdomain, IP, Headers, Localization etc... |
// +------------------------------------------------------------+
// Method returns the request.Method, the client's http method to the server.
@@ -365,6 +353,14 @@ type Context interface {
// in https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy
// or by the URL query parameter "referer".
GetReferrer() Referrer
+ // GetLocale returns the current request's `Locale` found by i18n middleware.
+ // See `Tr` too.
+ GetLocale() Locale
+ // Tr returns a i18n localized message based on format with optional arguments.
+ // See `GetLocale` too.
+ // Example: https://github.com/kataras/iris/tree/master/_examples/i18n
+ Tr(format string, args ...interface{}) string
+
// +------------------------------------------------------------+
// | Headers helpers |
// +------------------------------------------------------------+
@@ -1503,32 +1499,6 @@ func (ctx *context) Values() *memstore.Store {
return &ctx.values
}
-// Translate is the i18n (localization) middleware's function,
-// it calls the Values().Get(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey())
-// to execute the translate function and return the current localized text value.
-//
-// Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
-func (ctx *context) Translate(format string, args ...interface{}) string {
- if cb, ok := ctx.values.Get(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey()).(func(string, ...interface{}) string); ok {
- return cb(format, args...)
- }
-
- return ""
-}
-
-// TranslateLang is the i18n (localization) middleware's function,
-// it calls the Values().Get(ctx.Application().ConfigurationReadOnly().GetTranslateLangFunctionContextKey())
-// to execute the translate function and returns the localized text value based on the "lang".
-//
-// Example: https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n
-func (ctx *context) TranslateLang(lang, format string, args ...interface{}) string {
- if cb, ok := ctx.values.Get(ctx.Application().ConfigurationReadOnly().GetTranslateLangFunctionContextKey()).(func(string, string, ...interface{}) string); ok {
- return cb(lang, format, args...)
- }
-
- return ""
-}
-
// +------------------------------------------------------------+
// | Path, Host, Subdomain, IP, Headers etc... |
// +------------------------------------------------------------+
@@ -1797,6 +1767,36 @@ func (ctx *context) GetReferrer() Referrer {
return emptyReferrer
}
+// GetLocale returns the current request's `Locale` found by i18n middleware.
+// See `Tr` too.
+func (ctx *context) GetLocale() Locale {
+ contextKey := ctx.app.ConfigurationReadOnly().GetLocaleContextKey()
+ if v := ctx.Values().Get(contextKey); v != nil {
+ if locale, ok := v.(Locale); ok {
+ return locale
+ }
+ }
+
+ if locale := ctx.Application().I18nReadOnly().GetLocale(ctx); locale != nil {
+ ctx.Values().Set(contextKey, locale)
+ return locale
+ }
+
+ return nil
+}
+
+// Tr returns a i18n localized message based on format with optional arguments.
+// See `GetLocale` too.
+//
+// Example: https://github.com/kataras/iris/tree/master/_examples/i18n
+func (ctx *context) Tr(format string, args ...interface{}) string { // other name could be: Localize.
+ if locale := ctx.GetLocale(); locale != nil { // TODO: here... I need to change the logic, if not found then call the i18n's get locale and set the value in order to be fastest on routes that are not using (no need to reigster a middleware.)
+ return locale.GetMessage(format, args...)
+ }
+
+ return fmt.Sprintf(format, args...)
+}
+
// +------------------------------------------------------------+
// | Response Headers helpers |
// +------------------------------------------------------------+
diff --git a/context/i18n.go b/context/i18n.go
new file mode 100644
index 0000000000..407ef0bee9
--- /dev/null
+++ b/context/i18n.go
@@ -0,0 +1,28 @@
+package context
+
+import "golang.org/x/text/language"
+
+// I18nReadOnly is the interface which ontains the read-only i18n features.
+// Read the "i18n" package fo details.
+type I18nReadOnly interface {
+ Tags() []language.Tag
+ GetLocale(ctx Context) Locale
+ Tr(lang string, format string, args ...interface{}) string
+}
+
+// Locale is the interface which returns from a `Localizer.GetLocale` metod.
+// It serves the transltions based on "key" or format. See `GetMessage`.
+type Locale interface {
+ // Index returns the current locale index from the languages list.
+ Index() int
+ // Tag returns the full language Tag attached tothis Locale,
+ // it should be uniue across different Locales.
+ Tag() *language.Tag
+ // Language should return the exact languagecode of this `Locale`
+ //that the user provided on `New` function.
+ //
+ // Same as `Tag().String()` but it's static.
+ Language() string
+ // GetMessage should return translated text based n the given "key".
+ GetMessage(key string, args ...interface{}) string
+}
diff --git a/context/route.go b/context/route.go
index 04dea463c3..f67761289a 100644
--- a/context/route.go
+++ b/context/route.go
@@ -5,6 +5,7 @@ import (
"path"
"path/filepath"
"strings"
+ "time"
"github.com/kataras/iris/v12/macro"
)
@@ -56,6 +57,15 @@ type RouteReadOnly interface {
// route, manually or automatic by the framework,
// get the route by `Application#GetRouteByPath(staticSite.RequestPath)`.
StaticSites() []StaticSite
+
+ // Sitemap properties: https://www.sitemaps.org/protocol.html
+
+ // GetLastMod returns the date of last modification of the file served by this route.
+ GetLastMod() time.Time
+ // GetChangeFreq returns the the page frequently is likely to change.
+ GetChangeFreq() string
+ // GetPriority returns the priority of this route's URL relative to other URLs on your site.
+ GetPriority() float32
}
// StaticSite is a structure which is used as field on the `Route`
diff --git a/core/router/api_builder.go b/core/router/api_builder.go
index b789bb3b22..04a444773f 100644
--- a/core/router/api_builder.go
+++ b/core/router/api_builder.go
@@ -283,7 +283,11 @@ func (api *APIBuilder) SetExecutionRules(executionRules ExecutionRules) Party {
return api
}
-func (api *APIBuilder) createRoutes(methods []string, relativePath string, handlers ...context.Handler) []*Route {
+// CreateRoutes returns a list of Party-based Routes.
+// It does NOT registers the route. Use `Handle, Get...` methods instead.
+// This method can be used for third-parties Iris helpers packages and tools
+// that want a more detailed view of Party-based Routes before take the decision to register them.
+func (api *APIBuilder) CreateRoutes(methods []string, relativePath string, handlers ...context.Handler) []*Route {
// if relativePath[0] != '/' {
// return nil, errors.New("path should start with slash and should not be empty")
// }
@@ -393,7 +397,7 @@ func getCaller() (string, int) {
//
// Returns a *Route, app will throw any errors later on.
func (api *APIBuilder) Handle(method string, relativePath string, handlers ...context.Handler) *Route {
- routes := api.createRoutes([]string{method}, relativePath, handlers...)
+ routes := api.CreateRoutes([]string{method}, relativePath, handlers...)
var route *Route // the last one is returned.
for _, route = range routes {
@@ -473,7 +477,7 @@ func (api *APIBuilder) HandleDir(requestPath, directory string, opts ...DirOptio
}
requestPath = joinPath(requestPath, WildcardFileParam())
- routes := api.createRoutes([]string{http.MethodGet, http.MethodHead}, requestPath, h)
+ routes := api.CreateRoutes([]string{http.MethodGet, http.MethodHead}, requestPath, h)
getRoute = routes[0]
// we get all index, including sub directories even if those
// are already managed by the static handler itself.
@@ -489,7 +493,7 @@ func (api *APIBuilder) HandleDir(requestPath, directory string, opts ...DirOptio
}
requestPath := s.RequestPath[strings.Index(s.RequestPath, api.relativePath)+len(api.relativePath):]
- routes = append(routes, api.createRoutes([]string{http.MethodGet}, requestPath, h)...)
+ routes = append(routes, api.CreateRoutes([]string{http.MethodGet}, requestPath, h)...)
getRoute.StaticSites = append(getRoute.StaticSites, s)
}
diff --git a/core/router/handler.go b/core/router/handler.go
index c09504b4e9..03fd3a1593 100644
--- a/core/router/handler.go
+++ b/core/router/handler.go
@@ -42,7 +42,8 @@ func (h *routerHandler) getTree(method, subdomain string) *trie {
return nil
}
-func (h *routerHandler) addRoute(r *Route) error {
+// AddRoute registers a route. See `Router.AddRouteUnsafe`.
+func (h *routerHandler) AddRoute(r *Route) error {
var (
routeName = r.Name
method = r.Method
@@ -136,7 +137,7 @@ func (h *routerHandler) Build(provider RoutesProvider) error {
// on route, it will be stacked shown in this build state
// and no in the lines of the user's action, they should read
// the docs better. Or TODO: add a link here in order to help new users.
- if err := h.addRoute(r); err != nil {
+ if err := h.AddRoute(r); err != nil {
// node errors:
rp.Addf("%s: %w", r.String(), err)
continue
diff --git a/core/router/party.go b/core/router/party.go
index 5f6909e9da..9f92b770e5 100644
--- a/core/router/party.go
+++ b/core/router/party.go
@@ -183,6 +183,11 @@ type Party interface {
// Any registers a route for ALL of the http methods
// (Get,Post,Put,Head,Patch,Options,Connect,Delete).
Any(registeredPath string, handlers ...context.Handler) []*Route
+ // CreateRoutes returns a list of Party-based Routes.
+ // It does NOT registers the route. Use `Handle, Get...` methods instead.
+ // This method can be used for third-parties Iris helpers packages and tools
+ // that want a more detailed view of Party-based Routes before take the decision to register them.
+ CreateRoutes(methods []string, relativePath string, handlers ...context.Handler) []*Route
// StaticContent registers a GET and HEAD method routes to the requestPath
// that are ready to serve raw static bytes, memory cached.
//
diff --git a/core/router/route.go b/core/router/route.go
index 8571824c10..a1540b8e1d 100644
--- a/core/router/route.go
+++ b/core/router/route.go
@@ -3,6 +3,7 @@ package router
import (
"fmt"
"strings"
+ "time"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/macro"
@@ -44,8 +45,12 @@ type Route struct {
// route, manually or automatic by the framework,
// get the route by `Application#GetRouteByPath(staticSite.RequestPath)`.
StaticSites []context.StaticSite `json:"staticSites"`
+ topLink *Route
- topLink *Route
+ // Sitemap properties: https://www.sitemaps.org/protocol.html
+ LastMod time.Time `json:"lastMod,omitempty"`
+ ChangeFreq string `json:"changeFreq,omitempty"`
+ Priority float32 `json:"priority,omitempty"`
}
// NewRoute returns a new route based on its method,
@@ -175,6 +180,32 @@ func (r *Route) DeepEqual(other *Route) bool {
return r.Equal(other) && r.tmpl.Src == other.tmpl.Src
}
+// SetLastMod sets the date of last modification of the file served by this static GET route.
+func (r *Route) SetLastMod(t time.Time) *Route {
+ r.LastMod = t
+ return r
+}
+
+// SetChangeFreq sets how frequently this static GET route's page is likely to change,
+// possible values:
+// - "always"
+// - "hourly"
+// - "daily"
+// - "weekly"
+// - "monthly"
+// - "yearly"
+// - "never"
+func (r *Route) SetChangeFreq(freq string) *Route {
+ r.ChangeFreq = freq
+ return r
+}
+
+// SetPriority sets the priority of this static GET route's URL relative to other URLs on your site.
+func (r *Route) SetPriority(prio float32) *Route {
+ r.Priority = prio
+ return r
+}
+
// Tmpl returns the path template,
// it contains the parsed template
// for the route's path.
@@ -339,3 +370,15 @@ func (rd routeReadOnlyWrapper) MainHandlerName() string {
func (rd routeReadOnlyWrapper) StaticSites() []context.StaticSite {
return rd.Route.StaticSites
}
+
+func (rd routeReadOnlyWrapper) GetLastMod() time.Time {
+ return rd.Route.LastMod
+}
+
+func (rd routeReadOnlyWrapper) GetChangeFreq() string {
+ return rd.Route.ChangeFreq
+}
+
+func (rd routeReadOnlyWrapper) GetPriority() float32 {
+ return rd.Route.Priority
+}
diff --git a/core/router/router.go b/core/router/router.go
index 8497ffd8e9..b9649c9bf5 100644
--- a/core/router/router.go
+++ b/core/router/router.go
@@ -34,6 +34,26 @@ func (router *Router) RefreshRouter() error {
return router.BuildRouter(router.cPool, router.requestHandler, router.routesProvider, true)
}
+// ErrNotRouteAdder throws on `AddRouteUnsafe` when a registered `RequestHandler`
+// does not implements the optional `AddRoute(*Route) error` method.
+var ErrNotRouteAdder = errors.New("request handler does not implement AddRoute method")
+
+// AddRouteUnsafe adds a route directly to the router's request handler.
+// Works before or after Build state.
+// Mainly used for internal cases like `iris.WithSitemap`.
+// Do NOT use it on serve-time.
+func (router *Router) AddRouteUnsafe(r *Route) error {
+ if h := router.requestHandler; h != nil {
+ if v, ok := h.(interface {
+ AddRoute(*Route) error
+ }); ok {
+ return v.AddRoute(r)
+ }
+ }
+
+ return ErrNotRouteAdder
+}
+
// BuildRouter builds the router based on
// the context factory (explicit pool in this case),
// the request handler which manages how the main handler will multiplexes the routes
diff --git a/doc.go b/doc.go
index 29b991895d..7b5235fa27 100644
--- a/doc.go
+++ b/doc.go
@@ -38,7 +38,7 @@ Source code and other details for the project are available at GitHub:
Current Version
-12.0.2
+12.1.0
Installation
diff --git a/go.mod b/go.mod
index fda5dd86b4..a0b1fb108c 100644
--- a/go.mod
+++ b/go.mod
@@ -4,33 +4,31 @@ go 1.13
require (
github.com/BurntSushi/toml v0.3.1
- github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a // indirect
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398
github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible
- github.com/dgraph-io/badger v1.6.0 // indirect
+ github.com/dgraph-io/badger v1.6.0
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385
- github.com/etcd-io/bbolt v1.3.3 // indirect
+ github.com/etcd-io/bbolt v1.3.3
github.com/fatih/structs v1.1.0
- github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4
github.com/gavv/httpexpect v2.0.0+incompatible
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38
- github.com/hashicorp/go-version v1.2.0 // indirect
+ github.com/hashicorp/go-version v1.2.0
github.com/iris-contrib/blackfriday v2.0.0+incompatible
github.com/iris-contrib/go.uuid v2.0.0+incompatible
+ github.com/iris-contrib/pongo2 v0.0.1
github.com/iris-contrib/schema v0.0.1
github.com/json-iterator/go v1.1.6
- github.com/kataras/golog v0.0.9
- github.com/kataras/neffos v0.0.10
+ github.com/kataras/golog v0.0.10
+ github.com/kataras/neffos v0.0.12
+ github.com/kataras/sitemap v0.0.5
github.com/klauspost/compress v1.9.0
github.com/mediocregopher/radix/v3 v3.3.0
github.com/microcosm-cc/bluemonday v1.0.2
- github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
- github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/ryanuber/columnize v2.1.0+incompatible
- github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
- golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
+ golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413
+ golang.org/x/text v0.3.0
gopkg.in/ini.v1 v1.51.0
gopkg.in/yaml.v2 v2.2.2
)
diff --git a/go.sum b/go.sum
deleted file mode 100644
index 9d2fd18124..0000000000
--- a/go.sum
+++ /dev/null
@@ -1,122 +0,0 @@
-github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5uPdBC/X17wanyJAMxM33+4ZhEIV96MIH8U=
-github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
-github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE=
-github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
-github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
-github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8=
-github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=
-github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible h1:Ppm0npCCsmuR9oQaBtRuZcmILVE74aXE+AmrJj8L2ns=
-github.com/aymerick/raymond v2.0.3-0.20180322193309-b565731e1464+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dgraph-io/badger v1.6.0/go.mod h1:zwt7syl517jmP8s94KqSxTlM6IMsdhYy6psNgSztDR4=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385 h1:clC1lXBpe2kTj2VHdaIu9ajZQe4kcEY9j0NsnDDBZ3o=
-github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
-github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
-github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=
-github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/gavv/httpexpect v2.0.0+incompatible/go.mod h1:x+9tiU1YnrOvnB725RkpoLv1M62hOWzwo5OXotisrKc=
-github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
-github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
-github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38 h1:y0Wmhvml7cGnzPa9nocn/fMraMH/lMDdeG+rkx4VgYY=
-github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
-github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4=
-github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
-github.com/iris-contrib/go.uuid v2.0.0+incompatible h1:XZubAYg61/JwnJNbZilGjf3b3pB80+OQg2qf6c8BfWE=
-github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
-github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA=
-github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
-github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
-github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
-github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=
-github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
-github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
-github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
-github.com/kataras/golog v0.0.9 h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM=
-github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
-github.com/kataras/neffos v0.0.10 h1:O06dvQlxjdWvzWbm2Bq+Si6psUhvSmEctAMk9Xujqms=
-github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
-github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=
-github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
-github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY=
-github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
-github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
-github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
-github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
-github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
-github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
-github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
-github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
-github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
-github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
-github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
-github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
-github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
-github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
-github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
-github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
-github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
-gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
-gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/i18n/i18n.go b/i18n/i18n.go
new file mode 100644
index 0000000000..ee019692ae
--- /dev/null
+++ b/i18n/i18n.go
@@ -0,0 +1,439 @@
+// Package i18n provides internalization and localization features for Iris.
+// To use with net/http see https://github.com/kataras/i18n instead.
+package i18n
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "strings"
+ "sync"
+
+ "github.com/kataras/iris/v12/context"
+ "github.com/kataras/iris/v12/core/router"
+
+ "golang.org/x/text/language"
+)
+
+type (
+ // Loader accepts a `Matcher` and should return a `Localizer`.
+ // Functions that implement this type should load locale files.
+ Loader func(m *Matcher) (Localizer, error)
+
+ // Localizer is the interface which returned from a `Loader`.
+ // Types that implement this interface should be able to retrieve a `Locale`
+ // based on the language index.
+ Localizer interface {
+ // GetLocale should return a valid `Locale` based on the language index.
+ // It will always match the Loader.Matcher.Languages[index].
+ // It may return the default language if nothing else matches based on custom localizer's criteria.
+ GetLocale(index int) context.Locale
+ }
+)
+
+// I18n is the structure which keeps the i18n configuration and implements localization and internationalization features.
+type I18n struct {
+ localizer Localizer
+ matcher *Matcher
+
+ loader Loader
+ mu sync.Mutex
+
+ // ExtractFunc is the type signature for declaring custom logic
+ // to extract the language tag name.
+ // Defaults to nil.
+ ExtractFunc func(ctx context.Context) string
+ // If not empty, it is language identifier by url query.
+ //
+ // Defaults to "lang".
+ URLParameter string
+ // If not empty, it is language identifier by cookie of this name.
+ //
+ // Defaults to empty.
+ Cookie string
+ // If true then a subdomain can be a language identifier.
+ //
+ // Defaults to true.
+ Subdomain bool
+ // If true then it will return empty string when translation for a a specific language's key was not found.
+ // Defaults to false, fallback defaultLang:key will be used.
+ Strict bool
+
+ // If true then Iris will wrap its router with the i18n router wrapper on its Build state.
+ // It will (local) redirect requests like:
+ // 1. /$lang_prefix/$path to /$path with the language set to $lang_prefix part.
+ // 2. $lang_subdomain.$domain/$path to $domain/$path with the language set to $lang_subdomain part.
+ //
+ // Defaults to true.
+ PathRedirect bool
+}
+
+var _ context.I18nReadOnly = (*I18n)(nil)
+
+// makeTags converts language codes to language Tags.
+func makeTags(languages ...string) (tags []language.Tag) {
+ for _, lang := range languages {
+ tag, err := language.Parse(lang)
+ if err == nil && tag != language.Und {
+ tags = append(tags, tag)
+ }
+ }
+
+ return
+}
+
+// New returns a new `I18n` instance. Use its `Load` or `LoadAssets` to load languages.
+func New() *I18n {
+ return &I18n{
+ URLParameter: "lang",
+ Subdomain: true,
+ PathRedirect: true,
+ }
+}
+
+// Load is a method shortcut to load files using a filepath.Glob pattern.
+// It returns a non-nil error on failure.
+//
+// See `New` and `Glob` package-level functions for more.
+func (i *I18n) Load(globPattern string, languages ...string) error {
+ return i.Reset(Glob(globPattern), languages...)
+}
+
+// LoadAssets is a method shortcut to load files using go-bindata.
+// It returns a non-nil error on failure.
+//
+// See `New` and `Asset` package-level functions for more.
+func (i *I18n) LoadAssets(assetNames func() []string, asset func(string) ([]byte, error), languages ...string) error {
+ return i.Reset(Assets(assetNames, asset), languages...)
+}
+
+// Reset sets the locales loader and languages.
+// It is not meant to be used by users unless
+// a custom `Loader` must be used instead of the default one.
+func (i *I18n) Reset(loader Loader, languages ...string) error {
+ tags := makeTags(languages...)
+
+ i.loader = loader
+ i.matcher = &Matcher{
+ strict: len(tags) > 0,
+ Languages: tags,
+ matcher: language.NewMatcher(tags),
+ }
+
+ return i.reload()
+}
+
+// reload loads the language files from the provided Loader,
+// the `New` package-level function preloads those files already.
+func (i *I18n) reload() error { // May be an exported function, if requested.
+ i.mu.Lock()
+ defer i.mu.Unlock()
+
+ if i.loader == nil {
+ return fmt.Errorf("nil loader")
+ }
+
+ localizer, err := i.loader(i.matcher)
+ if err != nil {
+ return err
+ }
+
+ i.localizer = localizer
+ return nil
+}
+
+// Loaded reports whether `New` or `Load/LoadAssets` called.
+func (i *I18n) Loaded() bool {
+ return i != nil && i.loader != nil && i.localizer != nil && i.matcher != nil
+}
+
+// Tags returns the registered languages or dynamically resolved by files.
+// Use `Load` or `LoadAssets` first.
+func (i *I18n) Tags() []language.Tag {
+ if !i.Loaded() {
+ return nil
+ }
+
+ return i.matcher.Languages
+}
+
+// SetDefault changes the default language.
+// Please avoid using this method; the default behavior will accept
+// the first language of the registered tags as the default one.
+func (i *I18n) SetDefault(langCode string) bool {
+ t, err := language.Parse(langCode)
+ if err != nil {
+ return false
+ }
+
+ if tag, index, conf := i.matcher.Match(t); conf > language.Low {
+ if l, ok := i.localizer.(interface {
+ SetDefault(int) bool
+ }); ok {
+ if l.SetDefault(index) {
+ tags := i.matcher.Languages
+ // set the order
+ tags[index] = tags[0]
+ tags[0] = tag
+
+ i.matcher.Languages = tags
+ i.matcher.matcher = language.NewMatcher(tags)
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+// Matcher implements the languae.Matcher.
+// It contains the original language Matcher and keeps an ordered
+// list of the registered languages for further use (see `Loader` implementation).
+type Matcher struct {
+ strict bool
+ Languages []language.Tag
+ matcher language.Matcher
+}
+
+var _ language.Matcher = (*Matcher)(nil)
+
+// Match returns the best match for any of the given tags, along with
+// a unique index associated with the returned tag and a confidence
+// score.
+func (m *Matcher) Match(t ...language.Tag) (language.Tag, int, language.Confidence) {
+ return m.matcher.Match(t...)
+}
+
+// MatchOrAdd acts like Match but it checks and adds a language tag, if not found,
+// when the `Matcher.strict` field is true (when no tags are provided by the caller)
+// and they should be dynamically added to the list.
+func (m *Matcher) MatchOrAdd(t language.Tag) (tag language.Tag, index int, conf language.Confidence) {
+ tag, index, conf = m.Match(t)
+ if conf <= language.Low && !m.strict {
+ // not found, add it now.
+ m.Languages = append(m.Languages, t)
+ tag = t
+ index = len(m.Languages) - 1
+ conf = language.Exact
+ m.matcher = language.NewMatcher(m.Languages) // reset matcher to include the new language.
+ }
+
+ return
+}
+
+// ParseLanguageFiles returns a map of language indexes and
+// their associated files based on the "fileNames".
+func (m *Matcher) ParseLanguageFiles(fileNames []string) (map[int][]string, error) {
+ languageFiles := make(map[int][]string)
+
+ for _, fileName := range fileNames {
+ index := parsePath(m, fileName)
+ if index == -1 {
+ continue
+ }
+
+ languageFiles[index] = append(languageFiles[index], fileName)
+ }
+
+ return languageFiles, nil
+}
+
+func parsePath(m *Matcher, path string) int {
+ if t, ok := parseLanguage(path); ok {
+ if _, index, conf := m.MatchOrAdd(t); conf > language.Low {
+ return index
+ }
+ }
+
+ return -1
+}
+
+func parseLanguage(path string) (language.Tag, bool) {
+ if idx := strings.LastIndexByte(path, '.'); idx > 0 {
+ path = path[0:idx]
+ }
+
+ // path = strings.ReplaceAll(path, "..", "")
+
+ names := strings.FieldsFunc(path, func(r rune) bool {
+ return r == '_' || r == os.PathSeparator || r == '/' || r == '.'
+ })
+
+ for _, s := range names {
+ t, err := language.Parse(s)
+ if err != nil {
+ continue
+ }
+
+ return t, true
+ }
+
+ return language.Und, false
+}
+
+// TryMatchString will try to match the "s" with a registered language tag.
+// It returns -1 as the language index and false if not found.
+func (i *I18n) TryMatchString(s string) (language.Tag, int, bool) {
+ if tag, err := language.Parse(s); err == nil {
+ if tag, index, conf := i.matcher.Match(tag); conf > language.Low {
+ return tag, index, true
+ }
+ }
+
+ return language.Und, -1, false
+}
+
+// Tr returns a translated message based on the "lang" language code
+// and its key(format) with any optional arguments attached to it.
+//
+// It returns an empty string if "format" not matched.
+func (i *I18n) Tr(lang, format string, args ...interface{}) string {
+ _, index, ok := i.TryMatchString(lang)
+ if !ok {
+ index = 0
+ }
+
+ loc := i.localizer.GetLocale(index)
+ if loc != nil {
+ msg := loc.GetMessage(format, args...)
+ if msg == "" && !i.Strict && index > 0 {
+ // it's not the default/fallback language and not message found for that lang:key.
+ return i.localizer.GetLocale(0).GetMessage(format, args...)
+ }
+ return msg
+ }
+
+ return fmt.Sprintf(format, args...)
+}
+
+const acceptLanguageHeaderKey = "Accept-Language"
+
+// GetLocale returns the found locale of a request.
+// It will return the first registered language if nothing else matched.
+func (i *I18n) GetLocale(ctx context.Context) context.Locale {
+ // if v := ctx.Values().Get(ctx.Application().ConfigurationReadOnly().GetLocaleContextKey()); v != nil {
+ // if locale, ok := v.(context.Locale); ok {
+ // return locale
+ // }
+ // }
+
+ var (
+ index int
+ ok bool
+ )
+
+ if !ok && i.ExtractFunc != nil {
+ if v := i.ExtractFunc(ctx); v != "" {
+ _, index, ok = i.TryMatchString(v)
+
+ }
+ }
+
+ if !ok && i.URLParameter != "" {
+ if v := ctx.URLParam(i.URLParameter); v != "" {
+ _, index, ok = i.TryMatchString(v)
+ }
+ }
+
+ if !ok && i.Cookie != "" {
+ if v := ctx.GetCookie(i.Cookie); v != "" {
+ _, index, ok = i.TryMatchString(v) // url.QueryUnescape(cookie.Value)
+ }
+ }
+
+ if !ok && i.Subdomain {
+ if v := ctx.Subdomain(); v != "" {
+ _, index, ok = i.TryMatchString(v)
+ }
+ }
+
+ if !ok {
+ if v := ctx.GetHeader(acceptLanguageHeaderKey); v != "" {
+ desired, _, err := language.ParseAcceptLanguage(v)
+ if err == nil {
+ if _, idx, conf := i.matcher.Match(desired...); conf > language.Low {
+ index = idx
+ }
+ }
+ }
+ }
+
+ // locale := i.localizer.GetLocale(index)
+ // ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetLocaleContextKey(), locale)
+
+ // // if 0 then it defaults to the first language.
+ // return locale
+ locale := i.localizer.GetLocale(index)
+ if locale == nil {
+ return nil
+ }
+
+ return locale
+}
+
+// GetMessage returns the localized text message for this "r" request based on the key "format".
+func (i *I18n) GetMessage(ctx context.Context, format string, args ...interface{}) string {
+ loc := i.GetLocale(ctx)
+ if loc != nil {
+ // it's not the default/fallback language and not message found for that lang:key.
+ msg := loc.GetMessage(format, args...)
+ if msg == "" && !i.Strict && loc.Index() > 0 {
+ return i.localizer.GetLocale(0).GetMessage(format, args...)
+ }
+ }
+
+ return fmt.Sprintf(format, args...)
+}
+
+// Wrapper returns a new router wrapper.
+// The result function can be passed on `Application.WrapRouter`.
+// It compares the path prefix for translated language and
+// local redirects the requested path with the selected (from the path) language to the router.
+//
+// You do NOT have to call it manually, just set the `I18n.PathRedirect` field to true.
+func (i *I18n) Wrapper() router.WrapperFunc {
+ if !i.PathRedirect {
+ return nil
+ }
+ return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
+ found := false
+ path := r.URL.Path[1:]
+
+ if idx := strings.IndexByte(path, '/'); idx > 0 {
+ path = path[:idx]
+ }
+
+ if path != "" {
+ if tag, _, ok := i.TryMatchString(path); ok {
+ lang := tag.String()
+
+ path = r.URL.Path[len(path)+1:]
+ if path == "" {
+ path = "/"
+ }
+
+ r.RequestURI = path
+ r.URL.Path = path
+ r.Header.Set(acceptLanguageHeaderKey, lang)
+ found = true
+ }
+ }
+
+ if !found && i.Subdomain {
+ host := context.GetHost(r)
+ if dotIdx := strings.IndexByte(host, '.'); dotIdx > 0 {
+ if subdomain := host[0:dotIdx]; subdomain != "" {
+ if tag, _, ok := i.TryMatchString(subdomain); ok {
+ host = host[dotIdx+1:]
+ r.URL.Host = host
+ r.Host = host
+ r.Header.Set(acceptLanguageHeaderKey, tag.String())
+ }
+ }
+ }
+
+ }
+
+ next(w, r)
+ }
+}
diff --git a/i18n/loader.go b/i18n/loader.go
new file mode 100644
index 0000000000..fceed8b95b
--- /dev/null
+++ b/i18n/loader.go
@@ -0,0 +1,266 @@
+package i18n
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+ "text/template"
+
+ "github.com/kataras/iris/v12/context"
+
+ "github.com/BurntSushi/toml"
+ "golang.org/x/text/language"
+ "gopkg.in/ini.v1"
+ "gopkg.in/yaml.v2"
+)
+
+// LoaderConfig is an optional configuration structure which contains
+// some options about how the template loader should act.
+//
+// See `Glob` and `Assets` package-level functions.
+type LoaderConfig struct {
+ // Template delimeters, defaults to {{ }}.
+ Left, Right string
+ // Template functions map, defaults to nil.
+ FuncMap template.FuncMap
+ // If true then it will return error on invalid templates instead of moving them to simple string-line keys.
+ // Also it will report whether the registered languages matched the loaded ones.
+ // Defaults to false.
+ Strict bool
+}
+
+// LoaderOption is a type which accepts a pointer to `LoaderConfig`
+// and can be optionally passed to the second variadic input argument of the `Glob` and `Assets` functions.
+type LoaderOption func(*LoaderConfig)
+
+// Glob accepts a glob pattern (see: https://golang.org/pkg/path/filepath/#Glob)
+// and loads the locale files based on any "options".
+//
+// The "globPattern" input parameter is a glob pattern which the default loader should
+// search and load for locale files.
+//
+// See `New` and `LoaderConfig` too.
+func Glob(globPattern string, options ...LoaderOption) Loader {
+ assetNames, err := filepath.Glob(globPattern)
+ if err != nil {
+ panic(err)
+ }
+
+ return load(assetNames, ioutil.ReadFile, options...)
+}
+
+// Assets accepts a function that returns a list of filenames (physical or virtual),
+// another a function that should return the contents of a specific file
+// and any Loader options. Go-bindata usage.
+// It returns a valid `Loader` which loads and maps the locale files.
+//
+// See `Glob`, `Assets`, `New` and `LoaderConfig` too.
+func Assets(assetNames func() []string, asset func(string) ([]byte, error), options ...LoaderOption) Loader {
+ return load(assetNames(), asset, options...)
+}
+
+// load accepts a list of filenames (physical or virtual),
+// a function that should return the contents of a specific file
+// and any Loader options.
+// It returns a valid `Loader` which loads and maps the locale files.
+//
+// See `Glob`, `Assets` and `LoaderConfig` too.
+func load(assetNames []string, asset func(string) ([]byte, error), options ...LoaderOption) Loader {
+ var c = LoaderConfig{
+ Left: "{{",
+ Right: "}}",
+ Strict: false,
+ }
+
+ for _, opt := range options {
+ opt(&c)
+ }
+
+ return func(m *Matcher) (Localizer, error) {
+ languageFiles, err := m.ParseLanguageFiles(assetNames)
+ if err != nil {
+ return nil, err
+ }
+
+ locales := make(MemoryLocalizer)
+
+ for langIndex, langFiles := range languageFiles {
+ keyValues := make(map[string]interface{})
+
+ for _, fileName := range langFiles {
+ unmarshal := yaml.Unmarshal
+ if idx := strings.LastIndexByte(fileName, '.'); idx > 1 {
+ switch fileName[idx:] {
+ case ".toml", ".tml":
+ unmarshal = toml.Unmarshal
+ case ".json":
+ unmarshal = json.Unmarshal
+ case ".ini":
+ unmarshal = unmarshalINI
+ }
+ }
+
+ b, err := asset(fileName)
+ if err != nil {
+ return nil, err
+ }
+
+ if err = unmarshal(b, &keyValues); err != nil {
+ return nil, err
+ }
+ }
+
+ var (
+ templateKeys = make(map[string]*template.Template)
+ lineKeys = make(map[string]string)
+ other = make(map[string]interface{})
+ )
+
+ for k, v := range keyValues {
+ // fmt.Printf("[%d] %s = %v of type: [%T]\n", langIndex, k, v, v)
+
+ switch value := v.(type) {
+ case string:
+ if leftIdx, rightIdx := strings.Index(value, c.Left), strings.Index(value, c.Right); leftIdx != -1 && rightIdx > leftIdx {
+ // we assume it's template?
+ if t, err := template.New(k).Delims(c.Left, c.Right).Funcs(c.FuncMap).Parse(value); err == nil {
+ templateKeys[k] = t
+ continue
+ } else if c.Strict {
+ return nil, err
+ }
+ }
+
+ lineKeys[k] = value
+ default:
+ other[k] = v
+ }
+
+ }
+
+ t := m.Languages[langIndex]
+ locales[langIndex] = &defaultLocale{
+ index: langIndex,
+ id: t.String(),
+ tag: &t,
+ templateKeys: templateKeys,
+ lineKeys: lineKeys,
+ other: other,
+ }
+ }
+
+ if n := len(locales); n == 0 {
+ return nil, fmt.Errorf("locales not found in %s", strings.Join(assetNames, ", "))
+ } else if c.Strict && n < len(m.Languages) {
+ return nil, fmt.Errorf("locales expected to be %d but %d parsed", len(m.Languages), n)
+ }
+
+ return locales, nil
+ }
+}
+
+// MemoryLocalizer is a map which implements the `Localizer`.
+type MemoryLocalizer map[int]context.Locale
+
+// GetLocale returns a valid `Locale` based on the "index".
+func (l MemoryLocalizer) GetLocale(index int) context.Locale {
+ // loc, ok := l[index]
+ // if !ok {
+ // panic(fmt.Sprintf("locale of index [%d] not found", index))
+ // }
+ // return loc
+
+ return l[index]
+}
+
+// SetDefault changes the default language based on the "index".
+// See `I18n#SetDefault` method for more.
+func (l MemoryLocalizer) SetDefault(index int) bool {
+ // callers should protect with mutex if called at serve-time.
+ if loc, ok := l[index]; ok {
+ f := l[0]
+ l[0] = loc
+ l[index] = f
+ return true
+ }
+
+ return false
+}
+
+type defaultLocale struct {
+ index int
+ id string
+ tag *language.Tag
+ // templates *template.Template // we could use the ExecuteTemplate too.
+ templateKeys map[string]*template.Template
+ lineKeys map[string]string
+ other map[string]interface{}
+}
+
+func (l *defaultLocale) Index() int {
+ return l.index
+}
+
+func (l *defaultLocale) Tag() *language.Tag {
+ return l.tag
+}
+
+func (l *defaultLocale) Language() string {
+ return l.id
+}
+
+func (l *defaultLocale) GetMessage(key string, args ...interface{}) string {
+ n := len(args)
+ if n > 0 {
+ // search on templates.
+ if tmpl, ok := l.templateKeys[key]; ok {
+ buf := new(bytes.Buffer)
+ if err := tmpl.Execute(buf, args[0]); err == nil {
+ return buf.String()
+ }
+ }
+ }
+
+ if text, ok := l.lineKeys[key]; ok {
+ return fmt.Sprintf(text, args...)
+ }
+
+ if v, ok := l.other[key]; ok {
+ if n > 0 {
+ return fmt.Sprintf("%v [%v]", v, args)
+ }
+ return fmt.Sprintf("%v", v)
+ }
+
+ return ""
+}
+
+func unmarshalINI(data []byte, v interface{}) error {
+ f, err := ini.Load(data)
+ if err != nil {
+ return err
+ }
+
+ m := *v.(*map[string]interface{})
+
+ // Includes the ini.DefaultSection which has the root keys too.
+ // We don't have to iterate to each section to find the subsection,
+ // the Sections() returns all sections, sub-sections are separated by dot '.'
+ // and we match the dot with a section on the translate function, so we just save the values as they are,
+ // so we don't have to do section lookup on every translate call.
+ for _, section := range f.Sections() {
+ keyPrefix := ""
+ if name := section.Name(); name != ini.DefaultSection {
+ keyPrefix = name + "."
+ }
+
+ for _, key := range section.Keys() {
+ m[keyPrefix+key.Name()] = key.Value()
+ }
+ }
+
+ return nil
+}
diff --git a/iris.go b/iris.go
index 768ec2a7ad..37303325f5 100644
--- a/iris.go
+++ b/iris.go
@@ -10,6 +10,7 @@ import (
"log"
"net"
"net/http"
+ "os"
"strings"
"sync"
"time"
@@ -30,14 +31,15 @@ import (
"github.com/kataras/iris/v12/cache"
// view
"github.com/kataras/iris/v12/view"
- // middleware used in Default method
-
+ // i18n
+ "github.com/kataras/iris/v12/i18n"
+ // handlers used in `Default` function
requestLogger "github.com/kataras/iris/v12/middleware/logger"
"github.com/kataras/iris/v12/middleware/recover"
)
// Version is the current version number of the Iris Web Framework.
-const Version = "12.0.0"
+const Version = "12.0.1"
// HTTP status codes as registered with IANA.
// See: http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml.
@@ -143,10 +145,16 @@ type Application struct {
// the golog logger instance, defaults to "Info" level messages (all except "Debug")
logger *golog.Logger
+ // I18n contains localization and internationalization support.
+ // Use the `Load` or `LoadAssets` to locale language files.
+ //
+ // See `Context#Tr` method for request-based translations.
+ I18n *i18n.I18n
+
// view engine
view view.View
// used for build
- once sync.Once
+ builded bool
mu sync.Mutex
// Hosts contains a list of all servers (Host Supervisors) that this app is running on.
@@ -168,6 +176,7 @@ func New() *Application {
app := &Application{
config: &config,
logger: golog.Default,
+ I18n: i18n.New(),
APIBuilder: router.NewAPIBuilder(),
Router: router.NewRouter(),
}
@@ -179,13 +188,37 @@ func New() *Application {
return app
}
-// Default returns a new Application instance which, unlike `New`,
-// recovers on panics and logs the incoming http requests.
+// Default returns a new Application instance which preloads
+// html view engine on "./views" and
+// locales from "./locales/*/*" filepath glob pattern by current working directory.
+// The return instance recovers on panics and logs the incoming http requests too.
func Default() *Application {
app := New()
app.Use(recover.New())
app.Use(requestLogger.New())
+ for _, s := range []string{"./locales/*/*", "./locales/*", "./translations"} {
+ if _, err := os.Stat(s); os.IsNotExist(err) {
+ continue
+ }
+
+ if err := app.I18n.Load(s); err != nil {
+ continue
+ }
+
+ app.I18n.SetDefault("en-US")
+ break
+ }
+
+ for _, s := range []string{"./views", "./templates", "./web/views"} {
+ if _, err := os.Stat(s); os.IsNotExist(err) {
+ continue
+ }
+
+ app.RegisterView(HTML(s, ".html"))
+ break
+ }
+
return app
}
@@ -287,6 +320,12 @@ func (app *Application) Logger() *golog.Logger {
return app.logger
}
+// I18nReadOnly returns the i18n's read-only features.
+// See `I18n` method for more.
+func (app *Application) I18nReadOnly() context.I18nReadOnly {
+ return app.I18n
+}
+
var (
// HTML view engine.
// Shortcut of the kataras/iris/view.HTML.
@@ -817,9 +856,16 @@ func Raw(f func() error) Runner {
func (app *Application) Build() error {
rp := errgroup.New("Application Builder")
- app.once.Do(func() {
+ if !app.builded {
+ app.builded = true
rp.Err(app.APIBuilder.GetReporter())
+ if app.I18n.Loaded() {
+ // {{ tr "lang" "key" arg1 arg2 }}
+ app.view.AddFunc("tr", app.I18n.Tr)
+ app.WrapRouter(app.I18n.Wrapper())
+ }
+
if !app.Router.Downgraded() {
// router
// create the request handler, the default routing handler
@@ -828,7 +874,6 @@ func (app *Application) Build() error {
if err != nil {
rp.Err(err)
}
-
// re-build of the router from outside can be done with
// app.RefreshRouter()
}
@@ -845,7 +890,7 @@ func (app *Application) Build() error {
rp.Group("View Builder").Err(err)
}
}
- })
+ }
return errgroup.Check(rp)
}
diff --git a/middleware/README.md b/middleware/README.md
index 46b6f3ecef..8a2ff130a4 100644
--- a/middleware/README.md
+++ b/middleware/README.md
@@ -4,7 +4,6 @@ Builtin Handlers
| Middleware | Example |
| -----------|-------------|
| [basic authentication](basicauth) | [iris/_examples/authentication/basicauth](https://github.com/kataras/iris/tree/master/_examples/authentication/basicauth) |
-| [localization and internationalization](i18n) | [iris/_examples/miscellaneous/i81n](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/i18n) |
| [request logger](logger) | [iris/_examples/http_request/request-logger](https://github.com/kataras/iris/tree/master/_examples/http_request/request-logger) |
| [HTTP method override](methodoverride) | [iris/middleware/methodoverride/methodoverride_test.go](https://github.com/kataras/iris/blob/master/middleware/methodoverride/methodoverride_test.go) |
| [profiling (pprof)](pprof) | [iris/_examples/miscellaneous/pprof](https://github.com/kataras/iris/tree/master/_examples/miscellaneous/pprof) |
diff --git a/middleware/i18n/i18n.go b/middleware/i18n/i18n.go
deleted file mode 100644
index 3447fbb8a1..0000000000
--- a/middleware/i18n/i18n.go
+++ /dev/null
@@ -1,442 +0,0 @@
-// Package i18n provides internalization and localization via middleware.
-// See _examples/miscellaneous/i18n
-package i18n
-
-import (
- "fmt"
- "net/http"
- "reflect"
- "strings"
-
- "github.com/kataras/iris/v12/context"
-
- "gopkg.in/ini.v1"
-)
-
-// Config the i18n options.
-type Config struct {
- // Default set it if you want a default language.
- //
- // Checked: Configuration state, not at runtime.
- Default string
- // URLParameter is the name of the url parameter which the language can be indentified,
- // e.g. "lang" for ?lang=.
- //
- // Checked: Serving state, runtime.
- URLParameter string
- // Cookie is the key of the request cookie which the language can be indentified,
- // e.g. "lang".
- //
- // Checked: Serving state, runtime.
- Cookie string
- // If SetCookie is true and Cookie field is not empty
- // then it will set the cookie to the language found by Context's Value's "lang" key or URLParameter or Cookie or Indentifier.
- // Defaults to false.
- SetCookie bool
-
- // If Subdomain is true then it will try to map a subdomain
- // with a valid language from the language list or a valid map to a language.
- Subdomain bool
-
- // Indentifier is a function which the language can be indentified if the above URLParameter and Cookie failed to.
- Indentifier func(context.Context) string
-
- // Languages is a map[string]string which the key is the language i81n and the value is the file location.
- //
- // Example of key is: 'en-US'.
- // Example of value is: './locales/en-US.ini'.
- Languages map[string]string
- // LanguagesMap is a language map which if it's filled,
- // it tries to associate an incoming possible language code to a key of "Languages" field
- // when the value of "Language" was not present as it is at serve-time.
- //
- // Defaults to a non-nil LanguagesMap which accepts all lowercase and [en] as [en-US] and e.t.c.
- LanguagesMap LanguagesMap
-}
-
-// LanguagesMap the type for mapping an incoming word to a locale.
-type LanguagesMap interface {
- Map(lang string) (locale string, found bool)
-}
-
-// Map is a Go map[string]string type which is a LanguagesMap that
-// matches literal key with value as the found locale.
-type Map map[string]string
-
-// Map loops through its registered alternative language codes
-// and reports if it is valid registered locale one.
-func (m Map) Map(lang string) (string, bool) {
- locale, ok := m[lang]
- return locale, ok
-}
-
-// MapFunc is a function shortcut for the LanguagesMap.
-type MapFunc func(lang string) (locale string, found bool)
-
-// Map should report if a given "lang" is valid registered locale.
-func (m MapFunc) Map(lang string) (string, bool) {
- return m(lang)
-}
-
-func makeDefaultLanguagesMap(languages map[string]string) MapFunc {
- return func(lang string) (string, bool) {
- lang = strings.ToLower(lang)
- for locale := range languages {
- if lang == strings.ToLower(locale) {
- return locale, true
- }
-
- // this matches "en-anything" too, which can be accepted too on some cases, but not here.
- // if sep := strings.IndexRune(lang, '-'); sep > 0 {
- // lang = lang[0:sep]
- // }
-
- if len(lang) == 2 {
- if strings.Contains(locale, lang) {
- return locale, true
- }
- }
- }
-
- return "", false
- }
-}
-
-// I18n is the structure which keeps the i18n configuration and implement all Iris i18n features.
-type I18n struct {
- config Config
-
- locales map[string][]*ini.File
-}
-
-// If `Config.Default` is missing and `Config.Languages` or `Config.LanguagesMap` contains this key then it will set as the default locale,
-// no need to be exported(see `Config.Default`).
-const defLangCode = "en-US"
-
-// NewI18n returns a new i18n middleware which contains
-// the middleware itself and a router wrapper.
-func NewI18n(c Config) *I18n {
- if len(c.Languages) == 0 {
- panic("field Languages is empty")
- }
-
- // check and validate (if possible) languages map.
- if c.LanguagesMap == nil {
- c.LanguagesMap = makeDefaultLanguagesMap(c.Languages)
- }
-
- if mTyp, ok := c.LanguagesMap.(Map); ok {
- for k, v := range mTyp {
- if _, ok := c.Languages[v]; !ok {
- panic(fmt.Sprintf("language alternative '%s' does not map to a valid language '%s'", k, v))
- }
- }
- }
-
- i := new(I18n)
-
- // load messages.
- i.locales = make(map[string][]*ini.File)
- for locale, src := range c.Languages {
- if err := i.AddSource(locale, src); err != nil {
- panic(err)
- }
- }
-
- // validate and set default lang code.
- if c.Default == "" {
- c.Default = defLangCode
- }
-
- if locale, _, ok := i.Exists(c.Default); !ok {
- panic(fmt.Sprintf("default language '%s' does not match any of the registered language", c.Default))
- } else {
- c.Default = locale
- }
-
- i.config = c
-
- return i
-}
-
-// AddSource adds a source file to the lang locale.
-// It is called on NewI18n, New and NewWrapper.
-//
-// If you wish to use this at serve-time please protect the process with a mutex.
-func (i *I18n) AddSource(locale, src string) error {
- // remove all spaces.
- src = strings.Replace(src, " ", "", -1)
- // note: if only one, then the first element is the "v".
- languageFiles := strings.Split(src, ",")
-
- for _, fileName := range languageFiles {
- if !strings.HasSuffix(fileName, ".ini") {
- fileName += ".ini"
- }
-
- f, err := ini.Load(fileName)
- if err != nil {
- return err
- }
-
- i.locales[locale] = append(i.locales[locale], f)
- }
-
- return nil
-}
-
-// GetMessage returns a message from a locale, locale is case-sensitivity and languages map does not playing its part here.
-func (i *I18n) GetMessage(locale, section, format string, args ...interface{}) (string, bool) {
- files, ok := i.locales[locale]
- if !ok {
- return "", false
- }
-
- return i.getMessage(files, section, format, args)
-}
-
-func (i *I18n) getMessage(files []*ini.File, section, format string, args []interface{}) (string, bool) {
- for _, f := range files {
- // returns the first available.
- // section is the same for both files if key(format) exists.
- s, err := f.GetSection(section)
- if err != nil {
- return "", false
- }
-
- k, err := s.GetKey(format)
- if err != nil {
- continue
- }
-
- format = k.Value()
- if len(args) > 0 {
- return fmt.Sprintf(format, args...), true
- }
-
- return format, true
- }
-
- return "", false
-}
-
-// Translate translates and returns a message based on any language code
-// and its key(format) with any optional arguments attached to it.
-func (i *I18n) Translate(lang, format string, args ...interface{}) string {
- if _, files, ok := i.Exists(lang); ok {
- return i.translate(files, format, args)
- }
-
- return ""
-}
-
-func (i *I18n) translate(files []*ini.File, format string, args []interface{}) string {
- section := ""
-
- if idx := strings.IndexRune(format, '.'); idx > 0 {
- section = format[:idx]
- format = format[idx+1:]
- }
-
- msg, ok := i.getMessage(files, section, format, args)
- if !ok {
- return fmt.Sprintf(format, args...)
- }
-
- return msg
-}
-
-// Exists reports whether a language code is a valid registered locale through its Languages list and Languages mapping.
-func (i *I18n) Exists(lang string) (string, []*ini.File, bool) {
- if lang == "" {
- return "", nil, false
- }
-
- files, ok := i.locales[lang]
- if ok {
- return lang, files, true
- }
-
- for locale, files := range i.locales {
- if locale == lang {
- return locale, files, true
- }
- }
-
- if i.config.LanguagesMap != nil {
- if locale, ok := i.config.LanguagesMap.Map(lang); ok {
- if files, ok := i.locales[locale]; ok {
- return locale, files, true
- }
- }
- }
-
- return "", nil, false
-}
-
-func (i *I18n) newTranslateLanguageFunc(files []*ini.File) func(format string, args ...interface{}) string {
- return func(format string, args ...interface{}) string {
- return i.translate(files, format, args)
- }
-}
-
-const acceptLanguageHeaderKey = "Accept-Language"
-
-// Handler returns the middleware handler.
-func (i *I18n) Handler() context.Handler {
- return func(ctx context.Context) {
- wasByCookie := false
-
- langKey := ctx.Application().ConfigurationReadOnly().GetTranslateLanguageContextKey()
-
- language, files, ok := i.Exists(ctx.Values().GetString(langKey))
-
- if !ok {
- if i.config.URLParameter != "" {
- language, files, ok = i.Exists(ctx.URLParam(i.config.URLParameter))
- }
-
- if !ok {
- // then try to take the lang field from the cookie
- if i.config.Cookie != "" {
- if language, files, ok = i.Exists(ctx.GetCookie(i.config.Cookie)); ok {
- wasByCookie = true
- }
- }
-
- if !ok && i.config.Subdomain {
- language, files, ok = i.Exists(ctx.Subdomain())
- }
-
- if !ok {
- // try to get by the request headers.
- if langHeader := ctx.GetHeader(acceptLanguageHeaderKey); langHeader != "" {
- idx := strings.IndexRune(langHeader, ';')
- if idx > 0 {
- langHeader = langHeader[:idx]
- }
-
- language, files, ok = i.Exists(langHeader)
- }
- }
-
- if !ok && i.config.Indentifier != nil {
- language, files, ok = i.Exists(i.config.Indentifier(ctx))
- }
- }
- }
-
- if !ok {
- language, files, ok = i.Exists(i.config.Default)
- }
-
- // if it was not taken by the cookie, then set the cookie in order to have it.
- if !wasByCookie && i.config.SetCookie && i.config.Cookie != "" {
- ctx.SetCookieKV(i.config.Cookie, language)
- }
-
- ctx.Values().Set(langKey, language)
-
- // Set iris.translate and iris.translateLang functions (they can be passed to templates as they are later on).
- ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetTranslateFunctionContextKey(), i.newTranslateLanguageFunc(files))
- ctx.Values().Set(ctx.Application().ConfigurationReadOnly().GetTranslateLangFunctionContextKey(), i.Translate)
-
- ctx.Next()
- }
-}
-
-// Wrapper returns a new router wrapper.
-// The result function can be passed on `Application.WrapRouter`.
-// It compares the path prefix for translated language and
-// local redirects the requested path with the selected (from the path) language to the router.
-//
-// In order this to work as expected, it should be combined with `Application.Use(i.Handler())`
-// which registers the i18n middleware itself.
-func (i *I18n) Wrapper() func(http.ResponseWriter, *http.Request, http.HandlerFunc) {
- return func(w http.ResponseWriter, r *http.Request, routerHandler http.HandlerFunc) {
- found := false
- reqPath := r.URL.Path[1:]
- path := reqPath
-
- if idx := strings.IndexByte(path, '/'); idx > 0 {
- path = path[:idx]
- }
-
- if path != "" {
- if lang, _, ok := i.Exists(path); ok {
- path = r.URL.Path[len(path)+1:]
- if path == "" {
- path = "/"
- }
-
- r.RequestURI = path
- r.URL.Path = path
- r.Header.Set(acceptLanguageHeaderKey, lang)
- found = true
- }
- }
-
- if !found && i.config.Subdomain {
- host := context.GetHost(r)
- if dotIdx := strings.IndexByte(host, '.'); dotIdx > 0 {
- subdomain := host[0:dotIdx]
- if subdomain != "" {
- if lang, _, ok := i.Exists(subdomain); ok {
- host = host[dotIdx+1:]
- r.URL.Host = host
- r.Host = host
- r.Header.Set(acceptLanguageHeaderKey, lang)
- }
- }
- }
- }
-
- routerHandler(w, r)
- }
-}
-
-// New returns a new i18n middleware.
-func New(c Config) context.Handler {
- return NewI18n(c).Handler()
-}
-
-// NewWrapper accepts a Config and returns a new router wrapper.
-// The result function can be passed on `Application.WrapRouter`.
-// It compares the path prefix for translated language and
-// local redirects the requested path with the selected (from the path) language to the router.
-//
-// In order this to work as expected, it should be combined with `Application.Use(New)`
-// which registers the i18n middleware itself.
-func NewWrapper(c Config) func(http.ResponseWriter, *http.Request, http.HandlerFunc) {
- return NewI18n(c).Wrapper()
-}
-
-// Translate returns the translated word from a context based on the current selected locale.
-// The second parameter is the key of the world or line inside the .ini file and
-// the third parameter is the '%s' of the world or line inside the .ini file
-func Translate(ctx context.Context, format string, args ...interface{}) string {
- return ctx.Translate(format, args...)
-}
-
-// TranslateLang returns the translated word from a context based on the given "lang".
-// The second parameter is the language key which the word "format" is translated to and
-// the third parameter is the key of the world or line inside the .ini file and
-// the forth parameter is the '%s' of the world or line inside the .ini file
-func TranslateLang(ctx context.Context, lang, format string, args ...interface{}) string {
- return ctx.TranslateLang(lang, format, args...)
-}
-
-// TranslatedMap returns translated map[string]interface{} from i18n structure.
-func TranslatedMap(ctx context.Context, sourceInterface interface{}) map[string]interface{} {
- iType := reflect.TypeOf(sourceInterface).Elem()
- result := make(map[string]interface{})
-
- for i := 0; i < iType.NumField(); i++ {
- fieldName := reflect.TypeOf(sourceInterface).Elem().Field(i).Name
- fieldValue := reflect.ValueOf(sourceInterface).Elem().Field(i).String()
-
- result[fieldName] = Translate(ctx, fieldValue)
- }
-
- return result
-}
diff --git a/view/README.md b/view/README.md
index 1b96bdeaf3..1f83075df2 100644
--- a/view/README.md
+++ b/view/README.md
@@ -7,7 +7,7 @@ All of these six template engines have common features with common API,
like Layout, Template Funcs, Party-specific layout, partial rendering and more.
- The standard html, its template parser is the [golang.org/pkg/html/template/](https://golang.org/pkg/html/template/)
-- Django, its template parser is the [github.com/flosch/pongo2](https://github.com/flosch/pongo2)
+- Django, its template parser is the [github.com/iris-contrib/pongo2](https://github.com/iris-contrib/pongo2)
- Pug(Jade), its template parser is the [github.com/Joker/jade](https://github.com/Joker/jade)
- Handlebars, its template parser is the [github.com/aymerick/raymond](https://github.com/aymerick/raymond)
- Amber, its template parser is the [github.com/eknkc/amber](https://github.com/eknkc/amber)
diff --git a/view/django.go b/view/django.go
index 686cebf42e..90d72b2e16 100644
--- a/view/django.go
+++ b/view/django.go
@@ -13,7 +13,7 @@ import (
"github.com/kataras/iris/v12/context"
- "github.com/flosch/pongo2"
+ "github.com/iris-contrib/pongo2"
)
type (
@@ -100,7 +100,7 @@ type DjangoEngine struct {
rmu sync.RWMutex // locks for filters, globals and `ExecuteWiter` when `reload` is true.
// filters for pongo2, map[name of the filter] the filter function . The filters are auto register
filters map[string]FilterFunction
- // globals share context fields between templates. https://github.com/flosch/pongo2/issues/35
+ // globals share context fields between templates.
globals map[string]interface{}
mu sync.Mutex // locks for template cache
templateCache map[string]*pongo2.Template