├── .gitignore ├── LICENSE ├── README.md ├── django_translation ├── Dockerfile ├── django_translation │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── locale │ └── zh_Hant │ │ └── LC_MESSAGES │ │ ├── django.po │ │ └── djangojs.po ├── manage.py ├── requirements.txt └── tutorial │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ └── __init__.py │ ├── models.py │ ├── static │ └── js │ │ └── index.js │ ├── templates │ └── tutorial │ │ └── index.html │ ├── tests.py │ ├── urls.py │ └── views.py └── docker-compose.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # django-translation-tutorial 2 | 3 | 如何使用 Django 實作 translation 📝 4 | 5 | * [Youtube Tutorial PART 1 - django-translation-tutorial](https://youtu.be/9zFCfnVgXjs) 6 | 7 | * [Youtube Tutorial PART 2 - django-translation-tutorial](https://youtu.be/sz0cpt8I1fM) 8 | 9 | * [Youtube Tutorial PART 3 - django-translation-tutorial](https://youtu.be/9njecageJvM) 10 | 11 | ## 簡介 12 | 13 | 本篇文章將介紹如何使用 Django 實作 translation ,我參考了 Django 官網的 [translation 文件](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/), 14 | 15 | 並且紀錄了一些細節。如果你想用 Flask 實作的話,可參考我之前寫的文章 [Flask-Babel-example](https://github.com/twtrubiks/Flask-Babel-example)。 16 | 17 | 建議閱讀此篇文章之前,要對 docker 有一些基本的認識,如果你對 docker 不熟,建議可參考 18 | 19 | [Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://github.com/twtrubiks/docker-tutorial),為什麼會使用到 docker :question: 20 | 21 | 因為本身電腦是 windows,而 Django translation 需要安裝 `gettext`,我在 windows 中一直裝不起來, 22 | 23 | 所以最後果斷使用 docker :sweat_smile: 24 | 25 | ## 建立環境 26 | 27 | 我使用 docker 建立環境,先來看一下 [Dockerfile](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/Dockerfile), 28 | 29 | ```text 30 | FROM python:3.6.2 31 | LABEL maintainer twtrubiks 32 | ENV PYTHONUNBUFFERED 1 33 | RUN mkdir /docker_tutorial 34 | WORKDIR /docker_tutorial 35 | COPY . /docker_tutorial/ 36 | RUN pip install -r requirements.txt 37 | RUN apt-get update && \ 38 | apt-get install -y gettext && \ 39 | apt-get clean && rm -rf /var/cache/apt/* && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/* 40 | ``` 41 | 42 | 最重要的就是 `apt-get install -y gettext` 這個,我會用 docker 也是因為這個原因,windows 一直裝不起來阿:cry: 43 | 44 | 如果你是 Linux 或是 MAC,應該就不需要用 docker 了,本機理論上很好安裝。 45 | 46 | 接著執行以下指令建立環境, 47 | 48 | ```cmd 49 | docker-compose build 50 | ``` 51 | 52 | 再啟動環境 ( 其實也可以直接執行這個就好 ), 53 | 54 | ```cmd 55 | docker-compose up 56 | ``` 57 | 58 | 再來進入 docker 環境中 migrate, 59 | 60 | ```python 61 | python manage.py migrate 62 | ``` 63 | 64 | 如果上述不了解,可參考 [Docker 基本教學 - 從無到有 Docker-Beginners-Guide](https://github.com/twtrubiks/docker-tutorial)。 65 | 66 | 來看一下 [requirements.txt](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/requirements.txt),這裡使用的是 `django==2.1.1`。 67 | 68 | 之前我寫的 django 教學文章,可參考 [Django 基本教學 - 從無到有 Django-Beginners-Guide 📝](https://github.com/twtrubiks/django-tutorial),不過要注意的是, 69 | 70 | 這篇教學是 `django <= 2.0`,django 2 有機會我會再寫篇文章介紹。 71 | 72 | 由於 django 2 改動蠻大的,所以我在程式碼中,有些地方會增加註解,說明這段設定可以參考官網的哪部分文件。 73 | 74 | ## 教學 75 | 76 | 接下來就要教大家如何進行翻譯了,首先,先進入 [django_translation/settings.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/django_translation/settings.py), 77 | 78 | 找到 MIDDLEWARE,並且加入 `django.middleware.locale.LocaleMiddleware`,這邊要注意擺放的位置, 79 | 80 | ```python 81 | MIDDLEWARE = [ 82 | ... 83 | 'django.contrib.sessions.middleware.SessionMiddleware', 84 | 85 | # https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#how-django-discovers-language-preference 86 | 'django.middleware.locale.LocaleMiddleware', 87 | 88 | 'django.middleware.common.CommonMiddleware', 89 | ... 90 | ] 91 | ``` 92 | 93 | 一定要放在 `django.contrib.sessions.middleware.SessionMiddleware` 之後, 94 | 95 | 以及 `django.middleware.common.CommonMiddleware` 之前,原因如下, 96 | 97 | 下方為官方說明, 98 | 99 | ```text 100 | It should come after SessionMiddleware, because LocaleMiddleware makes use of session 101 | data. And it should come before CommonMiddleware because CommonMiddleware needs an 102 | activated language in order to resolve the requested URL. 103 | ``` 104 | 105 | 詳細的官方文件,可參考 [How Django discovers language preference](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#how-django-discovers-language-preference)。 106 | 107 | 設定 LOCALE_PATHS, 可參考 [setting-LOCALE_PATHS](https://docs.djangoproject.com/en/2.1/ref/settings/#std:setting-LOCALE_PATHS), 108 | 109 | 在 [django_translation/settings.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/django_translation/settings.py) 中增加以下 code,這資料夾到時候會擺放翻譯的 `django.po` 以及 `django.mo` 檔案。 110 | 111 | ```python 112 | LOCALE_PATHS = [ 113 | os.path.join(BASE_DIR, 'locale'), 114 | ] 115 | ``` 116 | 117 | 在 [django_translation/settings.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/django_translation/settings.py) 中的 LANGUAGE_CODE 為預設的語言 118 | 119 | ```python 120 | LANGUAGE_CODE = 'en-us' 121 | ``` 122 | 123 | 如果你不知道國家的 LANGUAGE_CODE,可到 [language-identifiers.html](http://www.i18nguy.com/unicode/language-identifiers.html) 查詢各國家的 LANGUAGE_CODE 124 | 。 125 | 126 | 接著在 [django_translation/settings.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/django_translation/settings.py) 中設定可以顯示的語言清單,增加下列 code, 127 | 128 | ```python 129 | from django.utils.translation import gettext_lazy as _ 130 | LANGUAGES = [ 131 | ('en-us', _('English')), 132 | ('zh-hant', _('Traditional Chinese')), 133 | ('zh-cn', _('Simplified Chinese')), 134 | ] 135 | ``` 136 | 137 | `from django.utils.translation import gettext_lazy as _` 為翻譯,可參考 [standard-translation](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#standard-translation) , 138 | 139 | 然後非常建議大家在看一下 [lazy-translation](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#lazy-translation) 這篇,了解哪時候要使用 `gettext_lazy` 以及為什麼要使用 140 | 141 | `gettext_lazy`,通常是 defining models, forms and model forms 這些地方。 142 | 143 | 更多詳細設定,可參考 144 | [How Django discovers language preference](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#how-django-discovers-language-preference)。 145 | 146 | [django_translation/settings.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/django_translation/settings.py) 的設定到這邊就算告一個段落了:relaxed: 147 | 148 | 接著設定 [django_translation/urls.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/django_translation/urls.py) ,我們要增加 `path('i18n/', include('django.conf.urls.i18n'))` 149 | 150 | 到 urlpatterns 中,這個主要目的是 Activate this view, 151 | 152 | 以下為官方文件說明 153 | 154 | ```text 155 | As a convenience, Django comes with a view, django.views.i18n.set_language(), that sets 156 | a user’s language preference and redirects to a given URL or, by default, back to the 157 | previous page. 158 | Activate this view by adding the following line to your URLconf: 159 | ``` 160 | 161 | 詳細可參考 [the-set-language-redirect-view](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#the-set-language-redirect-view)。 162 | 163 | ```python 164 | urlpatterns = [ 165 | # https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#the-set-language-redirect-view 166 | path('i18n/', include('django.conf.urls.i18n')), 167 | path('admin/', admin.site.urls), 168 | path('tutorial/', include('tutorial.urls', namespace='tutorial' )), 169 | ] 170 | ``` 171 | 172 | 接著設定 [tutorial/urls.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/urls.py),設定好了之後,來看 [tutorial/views.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/views.py), 173 | 174 | 讓我們來看在 view 中要怎麼實現翻譯, code 如下, 175 | 176 | ```python 177 | from django.shortcuts import render 178 | from django.utils.translation import gettext as _ 179 | 180 | # Create your views here. 181 | def index(request): 182 | data = _('Hello') 183 | 184 | return render(request, 'tutorial/index.html', { 185 | "data" : data 186 | }) 187 | ``` 188 | 189 | `_('Hello')` 這個就是翻譯。 190 | 191 | ( 像這邊就是使用 `from django.utils.translation import gettext as _`,而不是 `gettext_lazy`。) 192 | 193 | 有 view 之後,那接下來就是設定 [tutorial/templates/tutorial/index.html](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/templates/tutorial/index.html)。 194 | 195 | 首先,我們先來設定可以切換語言的 select,可參考 [the-set-language-redirect-view](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#the-set-language-redirect-view), 196 | 197 | 以下為官方範例 code, 198 | 199 | ```django 200 | {% load i18n %} 201 | 202 |
{% csrf_token %} 203 | 204 | 214 | 215 |
216 | ``` 217 | 218 | `{% load i18n %}` 很重要 ( 可參考 [internationalization-in-template-code](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#internationalization-in-template-code) 這邊的說明 ),記得要載入, 219 | 220 | 我自己有簡單的使用 bootstrap3,可參考 [tutorial/templates/tutorial/index.html](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/templates/tutorial/index.html),直接將翻譯文字顯示出來, 221 | 222 | 如下方 code, 223 | 224 | ```html 225 |
{{data}}
226 | ``` 227 | 228 | 到這邊,我們終於可以開始進行翻譯了:satisfied: ( 這邊我就只翻譯繁體,其他的以此類推 )。 229 | 230 | 首先需要先執行 [makemessages](https://docs.djangoproject.com/en/2.1/ref/django-admin/#makemessages) 指令,建立出 `django.po` 檔案,指令如下, 231 | 232 | ```cmd 233 | django-admin makemessages --locale=zh_Hant 234 | ``` 235 | 236 | 這段 code ,會去 scan 你的 code ,將需要翻譯的找出來。 ( 例如 `_('Hello')` 就會被 scan 出來 )。 237 | 238 | ![alt tag](https://i.imgur.com/X5FtFfc.png) 239 | 240 | 注意,如果出現如下圖錯誤, 241 | 242 | ![alt tag](https://i.imgur.com/HAdvlGe.png) 243 | 244 | ```text 245 | CommandError: Can't find msguniq. Make sure you have GNU gettext tools 0.15 or newer installed. 246 | ``` 247 | 248 | 這就是在 windows 上為什麼我用 docker 的原因,雖然網路上有人說 windows 可安裝 [gettext-iconv-windows](https://mlocati.github.io/articles/gettext-iconv-windows.html) 解決, 249 | 250 | 但我一直遇到問題,最後果斷使用 docker:smiley: 251 | 252 | 目錄中應該會有個 locale 的資料夾,因為我們在 LOCALE_PATHS 有設定,如果沒有請自行建立一個 253 | 254 | ( 當 django run 起來的時候應該就會自己建立了 )。 255 | 256 | 執行後會看到如下,產生了 zh_Hant 的 `django.po` 檔案, 257 | 258 | ![alt tag](https://i.imgur.com/TMnsHaD.png) 259 | 260 | 現在就是要對 `django.po` 進行翻譯,打開 `django.po`,你會發現 `'Hello'` 在裡面, 261 | 262 | ![alt tag](https://i.imgur.com/tbCKEEI.png) 263 | 264 | 將它翻譯後,再執行 compilemessages,可參考 [compilemessages](https://docs.djangoproject.com/en/2.1/ref/django-admin/#compilemessages),指令如下 265 | 266 | ```python 267 | django-admin compilemessages 268 | ``` 269 | 270 | ![alt tag](https://i.imgur.com/Jk0TmrB.png) 271 | 272 | 執行後,如果沒任何錯誤訊息,就是成功 compilemessages,`django.mo` 就是 compilemessages 過後的檔案。 273 | 274 | ![alt tag](https://i.imgur.com/XrV9ah4.png) 275 | 276 | 接著我們到網頁上觀看 [http://127.0.0.1:8000/tutorial/](http://127.0.0.1:8000/tutorial/), 277 | 278 | 英文 279 | 280 | ![alt tag](https://i.imgur.com/NuMoW6k.png) 281 | 282 | 中文 283 | 284 | ![alt tag](https://i.imgur.com/UPhJnuK.png) 285 | 286 | 我們也可以這樣寫, 287 | 288 | ```python 289 | m=1 290 | d= 20 291 | output = _('Today is %(month)s / %(day)s.') % {'month': m, 'day': d} 292 | ``` 293 | 294 | [django.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/django.po) 如下, 295 | 296 | ![alt tag](https://i.imgur.com/ihIlByc.png) 297 | 298 | 這邊要提醒大家,假如你有做任何修改時,重新執行了 `django-admin makemessages --locale=zh_Hant` 時, 299 | 300 | 你可能會看到像上圖 A 的部份,就是你修改之前的東西會幫你註解起來,我建議把這個都刪除,也就是 A 的部份。 301 | 302 | ( 會請大家刪除的原因是,有時候它會導致你翻譯翻不出來,最後我是把那部份都刪除後,再執行 compilemessages 就正常了 ) 303 | 304 | ![alt tag](https://i.imgur.com/qI3tY3W.png) 305 | 306 | ### contextual-markers 307 | 308 | 什麼時候會用到它呢 ? 在英文翻中文常常會有這種況狀,就是一個英文的詞,在中文有很多意思的時候。 309 | 310 | 舉個例子, blue 是 藍色 的意思,但 blue 也可以是 鬱悶 的意思,這時候,就需要使用 contextual-markers, 311 | 312 | 參考以下 code ( 更多說明請參考 [contextual-markers](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#contextual-markers) ),code 在 [tutorial/views.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/views.py), 313 | 314 | ```python 315 | ... 316 | from django.utils.translation import pgettext 317 | 318 | # Create your views here. 319 | def index(request): 320 | ... 321 | # Translators: contextual-markers 322 | p_blue_color = pgettext("color", "blue") 323 | # Translators: contextual-markers 324 | p_blue_mood = pgettext("mood", "blue") 325 | ... 326 | return render(request, 'tutorial/index.html', { 327 | ... 328 | "p_blue_color": p_blue_color, 329 | "p_blue_mood": p_blue_mood, 330 | .... 331 | }) 332 | ``` 333 | 334 | 然後如果們執行 `django-admin makemessages --locale=zh_Hant`,你會發現 [django.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/django.po) 如下, 335 | 336 | ![alt tag](https://i.imgur.com/zvTbh4D.png) 337 | 338 | 你會發現它被拆成兩個,將對應要翻譯的內容填進去就可以了。另外注意一下這個註解,也就是 339 | 340 | `# Translators: contextual-markers` 這個,如果你要在翻譯中註解,你可以在 python 中使用 341 | 342 | `# Translators` key 開頭,這樣 [django.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/django.po) 就會有註解,更多詳細介紹可參考 [comments-for-translators](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#comments-for-translators)。 343 | 344 | 翻譯完成後,再執行 compilemessages, 345 | 346 | 如果是在 html 中想要使用 contextual-markers,則必須使用以下 code, 347 | 348 | ```django 349 | {# contextual-markers #} 350 |
{% trans "blue" context "color" %}
351 |
{% trans "blue" context "mood" %}
352 | ``` 353 | 354 | ![alt tag](https://i.imgur.com/viDCMKi.png) 355 | 356 | ### pluralization 357 | 358 | 有時候我們會有單數和複數顯示不同的需求,這時候就可以使用 359 | [pluralization](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#pluralization),官方說明如下 360 | 361 | ```text 362 | ngettext() takes three arguments: the singular translation string, the plural translation 363 | string and the number of objects. 364 | ``` 365 | 366 | 範例 code,code 在 [tutorial/views.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/views.py), 367 | 368 | ```python 369 | from django.utils.translation import ngettext 370 | # pluralization 371 | count = 2 372 | pluralization = ngettext( 373 | 'There is %(count)d %(name)s object available.', 374 | 'There are %(count)d %(name)s objects available.', 375 | count 376 | ) % { 377 | 'count': count, 378 | 'name':'test', 379 | } 380 | ``` 381 | 382 | 執行 makemessages, 383 | 384 | ![alt tag](https://i.imgur.com/AfoqZlv.png) 385 | 386 | 在 html 中, 387 | 388 | ```html 389 | {# pluralization #} 390 |
{{pluralization}}
391 | ``` 392 | 393 | ![alt tag](https://i.imgur.com/naaDKpt.png) 394 | 395 | 你可以把 count 改成 `count = 1`,這樣就會變成單數了。 396 | 397 | ### Internationalization: in template code 398 | 399 | 接著來看在 template 中要如何進行翻譯,請參考 [tutorial/templates/tutorial/index.html](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/templates/tutorial/index.html), 400 | 401 | ```django 402 | {% load i18n %} 403 | 404 | {% comment %}Translators: Hello Django{% endcomment %} 405 |
{% trans "Hello Django" %}
406 | 407 | {# Translators: comment #} 408 |
{% trans "comment" %}
409 | ``` 410 | 411 | 上面提供了兩種的註解方式,詳細可參考 [comments-for-translators-in-templates](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#comments-for-translators-in-templates)。 412 | 413 | `{% load i18n %}` 記得要載入, 414 | 415 | 接著執行 `django-admin makemessages --locale=zh_Hant` 產生 [django.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/django.po) 檔案 416 | 417 | ![alt tag](https://i.imgur.com/D8Hj7RG.png) 418 | 419 | 註解也會產生在你的 [django.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/django.po) 中,最後 compilemessages, 420 | 421 | ![alt tag](https://i.imgur.com/pGmmMaa.png) 422 | 423 | 另外還有一種是設定為變數,方法如下 424 | 425 | ```django 426 | {# Translators: var #} 427 | {% trans "This is the title" as the_title %} 428 |
{{ the_title }}
429 | ``` 430 | 431 | 剩下的部分和剛剛都一樣,這邊我就不再做一遍了。 432 | 433 | 接下來是可能有一種情況,例如,英文是顯示 `show Hello`,而中文要顯示 `哈摟顯示`, 434 | 435 | 這時候,我們就不能使用之前的 `{% trans "This is the title" %}` 的方法,因為中英的位置 436 | 437 | 不一樣,這時候,就必須使用 `Translators: "{% blocktrans %}....{% endblocktrans %}` 的方式, 438 | 439 | 下列為變數的方法,寫法有兩種,code 請參考 [tutorial/templates/tutorial/index.html](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/templates/tutorial/index.html), 440 | 441 | ```django 442 | {# Translators: "{% blocktrans %}....{% endblocktrans %} #} 443 |
{%blocktrans with d=data %}show {{d}}{%endblocktrans%}
444 |
{%blocktrans with data as d %}show {{d}}{%endblocktrans%}
445 | ``` 446 | 447 | 接著執行 `django-admin makemessages --locale=zh_Hant` 產生 [django.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/django.po) 檔案, 448 | 449 | ![alt tag](https://i.imgur.com/1LpeUEk.png) 450 | 451 | 剩下的步驟這邊就省略了:relaxed:前面都說很多次了。 452 | 453 | 再來說一下 `trimmed option`, 454 | 455 | 有時候,我們希望經過 `django-admin makemessages --locale=zh_Hant` 產生 [django.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/django.po) 的檔案不要有換行 456 | 457 | 字元 `\n` 這類的,這時候,就可以使用 trimmed 這個 option。 458 | 459 | ( 有時候 `\n` 這類的字元甚至會導致翻譯錯誤,所以建議能加 trimmed 就加吧 ) 460 | 461 | ```django 462 | {% blocktrans trimmed %} 463 | First sentence. 464 | Second sentence. 465 | {% endblocktrans %} 466 | ``` 467 | 468 | 再來說一下另一個 `noop option`,官方說明如下, 469 | 470 | ```text 471 | If the noop option is present, variable lookup still takes place but the translation is 472 | skipped. This is useful when “stubbing out” content that will require translation in 473 | the future: 474 | ``` 475 | 476 | 如果加上這個 `noop option`,它將不會被翻譯,經過 `django-admin makemessages --locale=zh_Hant` 477 | 478 | 產生 [django.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/django.po) 的檔案中,還是會有翻譯的內容,但不會被翻譯出來( skipped ),也就是說,可以使用在未來 479 | 480 | 會翻譯,但目前還不需要的情境下, 481 | 482 | ```django 483 | {# Translators: noop #} 484 |
{% trans "myvar" noop %}
485 | ``` 486 | 487 | ### Internationalization: in JavaScript code 488 | 489 | * [Youtube Tutorial PART 3 - django-translation-tutorial](https://youtu.be/9njecageJvM) 490 | 491 | 一定會有人問,那如果我是透過 javascript ,有辦法進行翻譯嗎:question: 492 | 493 | 是可以的:satisfied:這邊就來教大家如何設定, 494 | 495 | 先到 [django_translation/urls.py](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/django_translation/urls.py) 設定 [The JavaScriptCatalog view](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#module-django.views.i18n), 496 | 497 | ```python 498 | from django.views.i18n import JavaScriptCatalog 499 | 500 | urlpatterns = [ 501 | .... 502 | #https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#module-django.views.i18n 503 | path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'), 504 | ... 505 | ] 506 | ``` 507 | 508 | 接著在 [tutorial/templates/tutorial/index.html](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/templates/tutorial/index.html) 中新增以下 code, 509 | 510 | ```django 511 | {# Using the JavaScript translation catalog #} 512 | {# https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#using-the-javascript-translation-catalog #} 513 | 514 | ``` 515 | 516 | 更多詳細介紹可參考官方文件 [using-the-javascript-translation-catalog](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#using-the-javascript-translation-catalog)。 517 | 518 | 接下來請注意,請 **新增一個 js 檔案** ,不能直接將 js 寫在 [tutorial/templates/tutorial/index.html](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/templates/tutorial/index.html) 中, 519 | 520 | 會抓不到,所以我們新增一個 [tutorial/static/js/index.js](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/static/js/index.js) 檔案,並且在裡面填入以下 code, 521 | 522 | 使用方法也很簡單,和在 python 翻譯的時候差不多,考以直接使用 [gettext](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#gettext), 523 | 524 | ```javascript 525 | var data = gettext('this is to be translated') 526 | document.write( '
'+ data + '
'); 527 | ``` 528 | 529 | 之後再回到 [tutorial/templates/tutorial/index.html](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/tutorial/templates/tutorial/index.html) 中 import 它, 530 | 531 | ```django 532 | {% load static %} 533 | 534 | ``` 535 | 536 | 接著我們要建立 [djangojs.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/djangojs.po),指令有點不一樣, 537 | 538 | ```python 539 | django-admin makemessages -d djangojs -l zh_Hant 540 | ``` 541 | 542 | ![alt tag](https://i.imgur.com/NAN8l3r.png) 543 | 544 | 執行後你會發現多出 [djangojs.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/djangojs.po), 545 | 546 | ![alt tag](https://i.imgur.com/nsgq8n8.png) 547 | 548 | [djangojs.po](https://github.com/twtrubiks/django-translation-tutorial/blob/master/django_translation/locale/zh_Hant/LC_MESSAGES/djangojs.po) 的內容如下,這邊我們成功的抓到 js 裡面的翻譯, 549 | 550 | ![alt tag](https://i.imgur.com/BOAjA15.png) 551 | 552 | 更多詳細可參考 [Creating message files from JavaScript source code](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#creating-message-files-from-javascript-source-code), 553 | 554 | 接著執行 compilemessages,指令則是一樣的,`django-admin compilemessages` 555 | 556 | ![alt tag](https://i.imgur.com/bs2L6Pc.png) 557 | 558 | 最後再到網頁上觀看 [http://127.0.0.1:8000/tutorial/](http://127.0.0.1:8000/tutorial/),js 也成功翻譯了:smiley: 559 | 560 | ![alt tag](https://i.imgur.com/QbXvtuT.png) 561 | 562 | ## 後記: 563 | 564 | 這次一不小心寫了好多,很多地方基本上我都有在 code 的部分放上註解以及官方的參考網址, 565 | 566 | 整體來說,我覺得 [django-translation](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/) 蠻完善的,連 js 也整合了進來,這次就介紹到這邊,謝謝大家:heart_eyes: 567 | 568 | ## 執行環境 569 | 570 | * Python 3.6.2 571 | * windows 10 572 | 573 | ## Reference 574 | 575 | * [django-translation](https://docs.djangoproject.com/en/2.1/topics/i18n/translation/) 576 | 577 | * [django-bootstrap3](https://github.com/dyve/django-bootstrap3) 578 | 579 | ## Donation 580 | 581 | 文章都是我自己研究內化後原創,如果有幫助到您,也想鼓勵我的話,歡迎請我喝一杯咖啡:laughing: 582 | 583 | ![alt tag](https://i.imgur.com/LRct9xa.png) 584 | 585 | [贊助者付款](https://payment.opay.tw/Broadcaster/Donate/9E47FDEF85ABE383A0F5FC6A218606F8) 586 | 587 | ## License 588 | 589 | MIT license 590 | -------------------------------------------------------------------------------- /django_translation/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6.2 2 | LABEL maintainer twtrubiks 3 | ENV PYTHONUNBUFFERED 1 4 | RUN mkdir /docker_tutorial 5 | WORKDIR /docker_tutorial 6 | COPY . /docker_tutorial/ 7 | RUN pip install -r requirements.txt 8 | RUN apt-get update && \ 9 | apt-get install -y gettext && \ 10 | apt-get clean && rm -rf /var/cache/apt/* && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/* 11 | 12 | -------------------------------------------------------------------------------- /django_translation/django_translation/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twtrubiks/django-translation-tutorial/e76cbb0bf9f4c18b2f4159888a3e30d63bf8f34f/django_translation/django_translation/__init__.py -------------------------------------------------------------------------------- /django_translation/django_translation/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for django_translation project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.1.1. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.1/ref/settings/ 11 | """ 12 | 13 | import os 14 | from django.utils.translation import gettext_lazy as _ 15 | 16 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 17 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 18 | 19 | 20 | # Quick-start development settings - unsuitable for production 21 | # See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/ 22 | 23 | # SECURITY WARNING: keep the secret key used in production secret! 24 | SECRET_KEY = 'vf9ar&^ulzdg6*)vj5i=!k26^#=*v3)i3!(=41r9)*@!m5lgvd' 25 | 26 | # SECURITY WARNING: don't run with debug turned on in production! 27 | DEBUG = True 28 | 29 | ALLOWED_HOSTS = [] 30 | 31 | 32 | # Application definition 33 | 34 | INSTALLED_APPS = [ 35 | 'django.contrib.admin', 36 | 'django.contrib.auth', 37 | 'django.contrib.contenttypes', 38 | 'django.contrib.sessions', 39 | 'django.contrib.messages', 40 | 'django.contrib.staticfiles', 41 | 'bootstrap3', 42 | 'tutorial', 43 | ] 44 | 45 | MIDDLEWARE = [ 46 | 'django.middleware.security.SecurityMiddleware', 47 | 'django.contrib.sessions.middleware.SessionMiddleware', 48 | 49 | # https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#how-django-discovers-language-preference 50 | 'django.middleware.locale.LocaleMiddleware', 51 | 52 | 'django.middleware.common.CommonMiddleware', 53 | 'django.middleware.csrf.CsrfViewMiddleware', 54 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 55 | 'django.contrib.messages.middleware.MessageMiddleware', 56 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 57 | ] 58 | 59 | ROOT_URLCONF = 'django_translation.urls' 60 | 61 | TEMPLATES = [ 62 | { 63 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 64 | 65 | # https://docs.djangoproject.com/en/2.1/howto/overriding-templates/#overriding-from-the-project-s-templates-directory 66 | 'DIRS': [os.path.join(BASE_DIR, 'templates')], 67 | 68 | 'APP_DIRS': True, 69 | 'OPTIONS': { 70 | 'context_processors': [ 71 | 'django.template.context_processors.debug', 72 | 'django.template.context_processors.request', 73 | 'django.contrib.auth.context_processors.auth', 74 | 'django.contrib.messages.context_processors.messages', 75 | ], 76 | }, 77 | }, 78 | ] 79 | 80 | WSGI_APPLICATION = 'django_translation.wsgi.application' 81 | 82 | 83 | # Database 84 | # https://docs.djangoproject.com/en/2.1/ref/settings/#databases 85 | 86 | DATABASES = { 87 | 'default': { 88 | 'ENGINE': 'django.db.backends.sqlite3', 89 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 90 | } 91 | } 92 | 93 | 94 | # Password validation 95 | # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators 96 | 97 | AUTH_PASSWORD_VALIDATORS = [ 98 | { 99 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 100 | }, 101 | { 102 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 103 | }, 104 | { 105 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 106 | }, 107 | { 108 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 109 | }, 110 | ] 111 | 112 | 113 | # Internationalization 114 | # https://docs.djangoproject.com/en/2.1/topics/i18n/ 115 | 116 | # https://docs.djangoproject.com/en/2.1/ref/settings/#std:setting-LOCALE_PATHS 117 | LOCALE_PATHS = [ 118 | os.path.join(BASE_DIR, 'locale'), 119 | ] 120 | 121 | # https://docs.djangoproject.com/en/2.1/ref/settings/#std:setting-LANGUAGE_CODE 122 | LANGUAGE_CODE = 'en-us' 123 | 124 | # https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#how-django-discovers-language-preference 125 | # http://www.i18nguy.com/unicode/language-identifiers.html 126 | LANGUAGES = [ 127 | ('en-us', _('English')), 128 | ('zh-hant', _('Traditional Chinese')), 129 | ('zh-cn', _('Simplified Chinese')), 130 | ] 131 | 132 | TIME_ZONE = 'UTC' 133 | 134 | USE_I18N = True 135 | 136 | USE_L10N = True 137 | 138 | USE_TZ = True 139 | 140 | 141 | # Static files (CSS, JavaScript, Images) 142 | # https://docs.djangoproject.com/en/2.1/howto/static-files/ 143 | 144 | STATIC_URL = '/static/' 145 | -------------------------------------------------------------------------------- /django_translation/django_translation/urls.py: -------------------------------------------------------------------------------- 1 | """django_translation URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.1/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path,include 18 | from django.views.i18n import JavaScriptCatalog 19 | 20 | urlpatterns = [ 21 | # https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#the-set-language-redirect-view 22 | path('i18n/', include('django.conf.urls.i18n')), 23 | #https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#module-django.views.i18n 24 | path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'), 25 | path('admin/', admin.site.urls), 26 | path('tutorial/', include('tutorial.urls', namespace='tutorial' )), 27 | ] 28 | 29 | -------------------------------------------------------------------------------- /django_translation/django_translation/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for django_translation project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_translation.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /django_translation/locale/zh_Hant/LC_MESSAGES/django.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2018-09-05 10:17+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=1; plural=0;\n" 20 | 21 | #: django_translation/settings.py:127 22 | msgid "English" 23 | msgstr "" 24 | 25 | #: django_translation/settings.py:128 26 | msgid "Traditional Chinese" 27 | msgstr "" 28 | 29 | #: django_translation/settings.py:129 30 | msgid "Simplified Chinese" 31 | msgstr "" 32 | 33 | #. Translators: contextual-markers 34 | #: tutorial/templates/tutorial/index.html:54 tutorial/views.py:15 35 | msgctxt "color" 36 | msgid "blue" 37 | msgstr "藍色" 38 | 39 | #. Translators: contextual-markers 40 | #: tutorial/templates/tutorial/index.html:55 tutorial/views.py:17 41 | msgctxt "mood" 42 | msgid "blue" 43 | msgstr "鬱悶" 44 | 45 | #. Translators: Hello Django 46 | #: tutorial/templates/tutorial/index.html:61 47 | msgid "Hello Django" 48 | msgstr "哈摟 Django" 49 | 50 | #. Translators: comment 51 | #: tutorial/templates/tutorial/index.html:64 52 | msgid "comment" 53 | msgstr "註解" 54 | 55 | #. Translators: var 56 | #: tutorial/templates/tutorial/index.html:67 57 | msgid "This is the title" 58 | msgstr "這是標題" 59 | 60 | #. Translators: "{% blocktrans %}....{% endblocktrans %} 61 | #: tutorial/templates/tutorial/index.html:71 62 | #: tutorial/templates/tutorial/index.html:72 63 | #, python-format 64 | msgid "show %(d)s" 65 | msgstr "%(d)s 顯示" 66 | 67 | #: tutorial/templates/tutorial/index.html:76 68 | msgid "First sentence. Second sentence." 69 | msgstr "第一. 第二" 70 | 71 | #. Translators: noop 72 | #: tutorial/templates/tutorial/index.html:83 73 | msgid "myvar" 74 | msgstr "我的 var" 75 | 76 | #: tutorial/views.py:8 77 | msgid "Hello" 78 | msgstr "哈摟" 79 | 80 | #: tutorial/views.py:12 81 | #, python-format 82 | msgid "Today is %(month)s / %(day)s." 83 | msgstr "今天是 %(month)s 月 %(day)s 日" 84 | 85 | #: tutorial/views.py:22 86 | #, python-format 87 | msgid "There is %(count)d %(name)s object available." 88 | msgid_plural "There are %(count)d %(name)s objects available." 89 | msgstr[0] "有 %(count)d 個 %(name)s 物件可用" 90 | -------------------------------------------------------------------------------- /django_translation/locale/zh_Hant/LC_MESSAGES/djangojs.po: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER 3 | # This file is distributed under the same license as the PACKAGE package. 4 | # FIRST AUTHOR , YEAR. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PACKAGE VERSION\n" 10 | "Report-Msgid-Bugs-To: \n" 11 | "POT-Creation-Date: 2018-09-04 14:01+0000\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "Language: \n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=UTF-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Plural-Forms: nplurals=1; plural=0;\n" 20 | 21 | #: tutorial/static/index.js:1 22 | msgid "this is to be translated" 23 | msgstr "我將被翻譯" 24 | -------------------------------------------------------------------------------- /django_translation/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_translation.settings') 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /django_translation/requirements.txt: -------------------------------------------------------------------------------- 1 | django==2.1.1 2 | django-bootstrap3==11.0.0 3 | -------------------------------------------------------------------------------- /django_translation/tutorial/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twtrubiks/django-translation-tutorial/e76cbb0bf9f4c18b2f4159888a3e30d63bf8f34f/django_translation/tutorial/__init__.py -------------------------------------------------------------------------------- /django_translation/tutorial/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /django_translation/tutorial/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class TutorialConfig(AppConfig): 5 | name = 'tutorial' 6 | -------------------------------------------------------------------------------- /django_translation/tutorial/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twtrubiks/django-translation-tutorial/e76cbb0bf9f4c18b2f4159888a3e30d63bf8f34f/django_translation/tutorial/migrations/__init__.py -------------------------------------------------------------------------------- /django_translation/tutorial/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /django_translation/tutorial/static/js/index.js: -------------------------------------------------------------------------------- 1 | var data = gettext('this is to be translated') 2 | document.write( '
'+ data + '
'); 3 | -------------------------------------------------------------------------------- /django_translation/tutorial/templates/tutorial/index.html: -------------------------------------------------------------------------------- 1 | {% load i18n bootstrap3 %} 2 | 3 | 4 | 5 | 6 | 7 | Tutorial 8 | 12 | {# Load CSS and JavaScript #} 13 | {% bootstrap_css %} 14 | {% bootstrap_javascript %} 15 | {% load static %} 16 | 17 | 18 |
19 |
20 |

django-translation-tutorial

21 |
22 | {% get_current_language as LANGUAGE_CODE %} 23 |
LANGUAGE : {{LANGUAGE_CODE}}
24 | 25 |
26 | {% csrf_token %} 27 | 28 |
29 | 30 |
31 | 41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 |
49 | 50 |
{{data}}
51 |
{{output}}
52 | 53 | {# contextual-markers #} 54 |
{% trans "blue" context "color" %}
55 |
{% trans "blue" context "mood" %}
56 | 57 | {# pluralization #} 58 |
{{pluralization}}
59 | 60 | {% comment %}Translators: Hello Django{% endcomment %} 61 |
{% trans "Hello Django" %}
62 | 63 | {# Translators: comment #} 64 |
{% trans "comment" %}
65 | 66 | {# Translators: var #} 67 | {% trans "This is the title" as the_title %} 68 |
{{ the_title }}
69 | 70 | {# Translators: "{% blocktrans %}....{% endblocktrans %} #} 71 |
{%blocktrans with d=data %}show {{d}}{%endblocktrans%}
72 |
{%blocktrans with data as d %}show {{d}}{%endblocktrans%}
73 | 74 | {# Translators: trimmed option #} 75 |
76 | {% blocktrans trimmed %} 77 | First sentence. 78 | Second sentence. 79 | {% endblocktrans %} 80 |
81 | 82 | {# Translators: noop #} 83 |
{% trans "myvar" noop %}
84 | 85 | {# Using the JavaScript translation catalog #} 86 | {# https://docs.djangoproject.com/en/2.1/topics/i18n/translation/#using-the-javascript-translation-catalog #} 87 | 88 | 89 |
90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /django_translation/tutorial/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /django_translation/tutorial/urls.py: -------------------------------------------------------------------------------- 1 | from django.urls import path 2 | from . import views 3 | 4 | app_name = 'index' 5 | urlpatterns = [ 6 | path('', views.index,name='index'), 7 | ] 8 | -------------------------------------------------------------------------------- /django_translation/tutorial/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from django.utils.translation import gettext as _ 3 | from django.utils.translation import pgettext 4 | from django.utils.translation import ngettext 5 | 6 | # Create your views here. 7 | def index(request): 8 | data = _('Hello') 9 | 10 | m=1 11 | d= 20 12 | output = _('Today is %(month)s / %(day)s.') % {'month': m, 'day': d} 13 | 14 | # Translators: contextual-markers 15 | p_blue_color = pgettext("color", "blue") 16 | # Translators: contextual-markers 17 | p_blue_mood = pgettext("mood", "blue") 18 | 19 | # pluralization 20 | count = 2 21 | pluralization = ngettext( 22 | 'There is %(count)d %(name)s object available.', 23 | 'There are %(count)d %(name)s objects available.', 24 | count 25 | ) % { 26 | 'count': count, 27 | 'name':'test', 28 | } 29 | 30 | return render(request, 'tutorial/index.html', { 31 | "data" : data, 32 | "output" : output, 33 | "p_blue_color": p_blue_color, 34 | "p_blue_mood": p_blue_mood, 35 | "pluralization" : pluralization 36 | }) 37 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | 4 | web: 5 | build: ./django_translation 6 | command: python manage.py runserver 0.0.0.0:8000 7 | restart: always 8 | volumes: 9 | - ./django_translation:/docker_tutorial 10 | # (HOST:CONTAINER) 11 | ports: 12 | - "8000:8000" 13 | --------------------------------------------------------------------------------