commit d96e16de206c0ca80c0d39fc2fb279ad1d0fdfb8 Author: nixo Date: Sun Mar 8 12:04:18 2020 +0100 First working version diff --git a/Manifest.toml b/Manifest.toml new file mode 100644 index 0000000..b1511de --- /dev/null +++ b/Manifest.toml @@ -0,0 +1,12 @@ +# This file is machine-generated - editing it directly is not advised + +[[Dates]] +deps = ["Printf"] +uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" + +[[Printf]] +deps = ["Unicode"] +uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" + +[[Unicode]] +uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" diff --git a/Project.toml b/Project.toml new file mode 100644 index 0000000..22fcb06 --- /dev/null +++ b/Project.toml @@ -0,0 +1,7 @@ +name = "I18N" +uuid = "d6ed3431-2785-4dea-b371-f59d90030b18" +authors = ["nixo "] +version = "0.1.0" + +[deps] +Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" diff --git a/src/I18N.jl b/src/I18N.jl new file mode 100644 index 0000000..18d1a0c --- /dev/null +++ b/src/I18N.jl @@ -0,0 +1,110 @@ +module I18N + +using Dates + +language_map = include("codes.jl") + +translationpath(langcode, domain = "base") = + joinpath(realpath("."), "locales/$(langcode)/LC_MESSAGES/$(domain).pot") + +macro __str(phrase) + push!(Main.i18n_cache, (file = __source__.file, + line = __source__.line, + strid = phrase)) + return esc(quote + get(get(i18n, I18N.language(), Dict()), + $phrase, $phrase) + end) +end + +macro translations(languages...) + return esc(quote + i18n = Dict{String,Dict{String,String}}() + # (lang, file.jl, line) => translation + i18n_cache = Any[] + # lang => [(name, mail, year)] + i18n_translators = Dict{String,Array{Tuple{String,String,String}}}() + for language in $languages + i18n[string(language)] = Dict{String,String}() + end + end) +end + +macro translate(lang, id, translation) + return esc(:(i18n[string($lang)][$id] = $translation)) +end + +function translator_list(translators) + join(map(t -> string("# ", t[1], " ", "<", t[2], ">", " ", + t[3], "."), + translators), + "\n") +end + +function po_header(LANG, PROGRAM, VERSION, C_YEARS, C_AUTHORS, TRANSLATORS) + """# $LANG translation for $PROGRAM $VERSION +# Copyright (C) $C_YEARS $C_AUTHORS +# This file is distributed under the same license as $PROGRAM. +$(translator_list(TRANSLATORS)) +# +msgid "" +msgstr "" +""" +end + +function format(file, line, phrase, translation = "") + string("#: ", relpath(string(file)), ":", line, "\n", + "msgid ", "\"", phrase, "\"", "\n", + "msgstr ", "\"", translation, "\"", "\n\n") +end + +lang_expand(lang) = language_map[lang] + +current_year() = Dates.today() |> year + +macro write_po_files(name = nothing, version = nothing, + authors = nothing, year = nothing) + return esc(quote + unique!(i18n_cache) + # Sort by line & by file + sort!(i18n_cache, by = x -> x[2]) + sort!(i18n_cache, by = first) + # Write to file + for language in keys(i18n) + translationfile = I18N.translationpath(string(language)) + mkpath(dirname(translationfile)) + open(translationfile, "w") do io + translators = get(i18n_translators, language, []) + write(io, I18N.po_header(lang_expand(language), + something($name, uppercasefirst(basename(realpath(".")))), + something($version, "0.1.0-dev"), + something($year, I18N.current_year()), + join(something($authors, + first.(translators)), + ", "), translators)) + for tr in i18n_cache + translation = get(get(i18n, language, Dict()), tr.strid, "") + write(io, + I18N.format(tr.file, tr.line, tr.strid, translation)) + end + end + end + end) +end + +macro translator(lang, name, email, copyright) + # @show $lang + return esc(quote + if !($lang in keys(i18n_translators)) + i18n_translators[$lang] = [] + end + push!(i18n_translators[$lang], ($name, $email, $copyright)) + end) +end + +@inline language() = "en" + +export @__str, @translations, @translate, + @translator, @write_po_files, lang_expand + +end # module diff --git a/src/codes.jl b/src/codes.jl new file mode 100644 index 0000000..458bcf7 --- /dev/null +++ b/src/codes.jl @@ -0,0 +1,228 @@ +Dict("af" => "Afrikaans", + "af-ZA" => "Afrikaans (South Africa)", + "ar" => "Arabic", + "ar-AE" => "Arabic (U.A.E.)", + "ar-BH" => "Arabic (Bahrain)", + "ar-DZ" => "Arabic (Algeria)", + "ar-EG" => "Arabic (Egypt)", + "ar-IQ" => "Arabic (Iraq)", + "ar-JO" => "Arabic (Jordan)", + "ar-KW" => "Arabic (Kuwait)", + "ar-LB" => "Arabic (Lebanon)", + "ar-LY" => "Arabic (Libya)", + "ar-MA" => "Arabic (Morocco)", + "ar-OM" => "Arabic (Oman)", + "ar-QA" => "Arabic (Qatar)", + "ar-SA" => "Arabic (Saudi Arabia)", + "ar-SY" => "Arabic (Syria)", + "ar-TN" => "Arabic (Tunisia)", + "ar-YE" => "Arabic (Yemen)", + "az" => "Azeri (Latin)", + "az-AZ" => "Azeri (Latin) (Azerbaijan)", + "be" => "Belarusian", + "be-BY" => "Belarusian (Belarus)", + "bg" => "Bulgarian", + "bg-BG" => "Bulgarian (Bulgaria)", + "bs-BA" => "Bosnian (Bosnia and Herzegovina)", + "ca" => "Catalan", + "ca-ES" => "Catalan (Spain)", + "cs" => "Czech", + "cs-CZ" => "Czech (Czech Republic)", + "cy" => "Welsh", + "cy-GB" => "Welsh (United Kingdom)", + "da" => "Danish", + "da-DK" => "Danish (Denmark)", + "de" => "German", + "de-AT" => "German (Austria)", + "de-CH" => "German (Switzerland)", + "de-DE" => "German (Germany)", + "de-LI" => "German (Liechtenstein)", + "de-LU" => "German (Luxembourg)", + "dv" => "Divehi", + "dv-MV" => "Divehi (Maldives)", + "el" => "Greek", + "el-GR" => "Greek (Greece)", + "en" => "English", + "en-AU" => "English (Australia)", + "en-BZ" => "English (Belize)", + "en-CA" => "English (Canada)", + "en-CB" => "English (Caribbean)", + "en-GB" => "English (United Kingdom)", + "en-IE" => "English (Ireland)", + "en-JM" => "English (Jamaica)", + "en-NZ" => "English (New Zealand)", + "en-PH" => "English (Republic of the Philippines)", + "en-TT" => "English (Trinidad and Tobago)", + "en-US" => "English (United States)", + "en-ZA" => "English (South Africa)", + "en-ZW" => "English (Zimbabwe)", + "eo" => "Esperanto", + "es" => "Spanish", + "es-AR" => "Spanish (Argentina)", + "es-BO" => "Spanish (Bolivia)", + "es-CL" => "Spanish (Chile)", + "es-CO" => "Spanish (Colombia)", + "es-CR" => "Spanish (Costa Rica)", + "es-DO" => "Spanish (Dominican Republic)", + "es-EC" => "Spanish (Ecuador)", + "es-ES" => "Spanish (Spain)", + "es-GT" => "Spanish (Guatemala)", + "es-HN" => "Spanish (Honduras)", + "es-MX" => "Spanish (Mexico)", + "es-NI" => "Spanish (Nicaragua)", + "es-PA" => "Spanish (Panama)", + "es-PE" => "Spanish (Peru)", + "es-PR" => "Spanish (Puerto Rico)", + "es-PY" => "Spanish (Paraguay)", + "es-SV" => "Spanish (El Salvador)", + "es-UY" => "Spanish (Uruguay)", + "es-VE" => "Spanish (Venezuela)", + "et" => "Estonian", + "et-EE" => "Estonian (Estonia)", + "eu" => "Basque", + "eu-ES" => "Basque (Spain)", + "fa" => "Farsi", + "fa-IR" => "Farsi (Iran)", + "fi" => "Finnish", + "fi-FI" => "Finnish (Finland)", + "fo" => "Faroese", + "fo-FO" => "Faroese (Faroe Islands)", + "fr" => "French", + "fr-BE" => "French (Belgium)", + "fr-CA" => "French (Canada)", + "fr-CH" => "French (Switzerland)", + "fr-FR" => "French (France)", + "fr-LU" => "French (Luxembourg)", + "fr-MC" => "French (Principality of Monaco)", + "gl" => "Galician", + "gl-ES" => "Galician (Spain)", + "gu" => "Gujarati", + "gu-IN" => "Gujarati (India)", + "he" => "Hebrew", + "he-IL" => "Hebrew (Israel)", + "hi" => "Hindi", + "hi-IN" => "Hindi (India)", + "hr" => "Croatian", + "hr-BA" => "Croatian (Bosnia and Herzegovina)", + "hr-HR" => "Croatian (Croatia)", + "hu" => "Hungarian", + "hu-HU" => "Hungarian (Hungary)", + "hy" => "Armenian", + "hy-AM" => "Armenian (Armenia)", + "id" => "Indonesian", + "id-ID" => "Indonesian (Indonesia)", + "is" => "Icelandic", + "is-IS" => "Icelandic (Iceland)", + "it" => "Italian", + "it-CH" => "Italian (Switzerland)", + "it-IT" => "Italian (Italy)", + "ja" => "Japanese", + "ja-JP" => "Japanese (Japan)", + "ka" => "Georgian", + "ka-GE" => "Georgian (Georgia)", + "kk" => "Kazakh", + "kk-KZ" => "Kazakh (Kazakhstan)", + "kn" => "Kannada", + "kn-IN" => "Kannada (India)", + "ko" => "Korean", + "ko-KR" => "Korean (Korea)", + "kok" => "Konkani", + "kok-IN" => "Konkani (India)", + "ky" => "Kyrgyz", + "ky-KG" => "Kyrgyz (Kyrgyzstan)", + "lt" => "Lithuanian", + "lt-LT" => "Lithuanian (Lithuania)", + "lv" => "Latvian", + "lv-LV" => "Latvian (Latvia)", + "mi" => "Maori", + "mi-NZ" => "Maori (New Zealand)", + "mk" => "FYRO Macedonian", + "mk-MK" => "FYRO Macedonian (Former Yugoslav Republic of Macedonia)", + "mn" => "Mongolian", + "mn-MN" => "Mongolian (Mongolia)", + "mr" => "Marathi", + "mr-IN" => "Marathi (India)", + "ms" => "Malay", + "ms-BN" => "Malay (Brunei Darussalam)", + "ms-MY" => "Malay (Malaysia)", + "mt" => "Maltese", + "mt-MT" => "Maltese (Malta)", + "nb" => "Norwegian (Bokm?l)", + "nb-NO" => "Norwegian (Bokm?l) (Norway)", + "nl" => "Dutch", + "nl-BE" => "Dutch (Belgium)", + "nl-NL" => "Dutch (Netherlands)", + "nn-NO" => "Norwegian (Nynorsk) (Norway)", + "ns" => "Northern Sotho", + "ns-ZA" => "Northern Sotho (South Africa)", + "pa" => "Punjabi", + "pa-IN" => "Punjabi (India)", + "pl" => "Polish", + "pl-PL" => "Polish (Poland)", + "ps" => "Pashto", + "ps-AR" => "Pashto (Afghanistan)", + "pt" => "Portuguese", + "pt-BR" => "Portuguese (Brazil)", + "pt-PT" => "Portuguese (Portugal)", + "qu" => "Quechua", + "qu-BO" => "Quechua (Bolivia)", + "qu-EC" => "Quechua (Ecuador)", + "qu-PE" => "Quechua (Peru)", + "ro" => "Romanian", + "ro-RO" => "Romanian (Romania)", + "ru" => "Russian", + "ru-RU" => "Russian (Russia)", + "sa" => "Sanskrit", + "sa-IN" => "Sanskrit (India)", + "se" => "Sami (Northern)", + "se-FI" => "Sami (Finland)", + "se-NO" => "Sami (Norway)", + "se-SE" => "Sami (Sweden)", + "sk" => "Slovak", + "sk-SK" => "Slovak (Slovakia)", + "sl" => "Slovenian", + "sl-SI" => "Slovenian (Slovenia)", + "sq" => "Albanian", + "sq-AL" => "Albanian (Albania)", + "sr-BA" => "Serbian (Latin) (Bosnia and Herzegovina)", + "sr-SP" => "Serbian (Latin) (Serbia and Montenegro)", + "sv" => "Swedish", + "sv-FI" => "Swedish (Finland)", + "sv-SE" => "Swedish (Sweden)", + "sw" => "Swahili", + "sw-KE" => "Swahili (Kenya)", + "syr" => "Syriac", + "syr-SY" => "Syriac (Syria)", + "ta" => "Tamil", + "ta-IN" => "Tamil (India)", + "te" => "Telugu", + "te-IN" => "Telugu (India)", + "th" => "Thai", + "th-TH" => "Thai (Thailand)", + "tl" => "Tagalog", + "tl-PH" => "Tagalog (Philippines)", + "tn" => "Tswana", + "tn-ZA" => "Tswana (South Africa)", + "tr" => "Turkish", + "tr-TR" => "Turkish (Turkey)", + "tt" => "Tatar", + "tt-RU" => "Tatar (Russia)", + "ts" => "Tsonga", + "uk" => "Ukrainian", + "uk-UA" => "Ukrainian (Ukraine)", + "ur" => "Urdu", + "ur-PK" => "Urdu (Islamic Republic of Pakistan)", + "uz" => "Uzbek (Latin)", + "uz-UZ" => "Uzbek (Latin) (Uzbekistan)", + "vi" => "Vietnamese", + "vi-VN" => "Vietnamese (Viet Nam)", + "xh" => "Xhosa", + "xh-ZA" => "Xhosa (South Africa)", + "zh" => "Chinese", + "zh-CN" => "Chinese (S)", + "zh-HK" => "Chinese (Hong Kong)", + "zh-MO" => "Chinese (Macau)", + "zh-SG" => "Chinese (Singapore)", + "zh-TW" => "Chinese (T)", + "zu" => "Zulu", + "zu-ZA" => "Zulu (South Africa)") diff --git a/test/hello.jl b/test/hello.jl new file mode 100644 index 0000000..31e646b --- /dev/null +++ b/test/hello.jl @@ -0,0 +1,3 @@ +_"hello" +_"hi" +_"hola" diff --git a/test/numbers.jl b/test/numbers.jl new file mode 100644 index 0000000..af4991f --- /dev/null +++ b/test/numbers.jl @@ -0,0 +1,3 @@ +_"first" +_"second" +_"third" diff --git a/test/test.jl b/test/test.jl new file mode 100644 index 0000000..cac79b5 --- /dev/null +++ b/test/test.jl @@ -0,0 +1,23 @@ +push!(LOAD_PATH, realpath("..")) + +using I18N +@translations it en + +# Custom function used to get the program language. +# Must return a 2-char language code +req = Dict(:params => Dict(:lang => "it")) +@inline function I18N.language() + req[:params][:lang] +end + +@translate "it" "first" "primo" +@translate "it" "third" "terzo" + +include("numbers.jl") +include("hello.jl") + +@translate "it" "hello" "ciao" + +@translator "it" "Nicolò Balzarotti" "nicolo@nixo.xyz" "2020" + +@write_po_files "Test" "0.0.0-dev" ["Nicolò Balzarotti "] "2020"