mirror of
https://github.com/we-promise/sure.git
synced 2026-04-08 06:44:52 +00:00
* feat(zh-TW): add Traditional Chinese localization support Integrates comprehensive zh-TW locale files across UI, models, emails, and helpers. Updates language mapping for Chinese (Traditional) and adds translations for various modules. Establishes full Traditional Chinese support in the app. * feat(locales): add zh-TW translations Add comprehensive Traditional Chinese (zh-TW) translations for UI, defaults, Doorkeeper, mailers, models, and views to provide full Taiwanese localization and improve wording consistency. Replace and update several existing zh-TW entries for clarity and consistency. Also expose the Postgres port in the example compose for easier local development and apply minor locale/typo/whitespace fixes. * feat(locales): add zh-TW translations Add Traditional Chinese (zh-TW) locale files across many views and settings to provide Taiwanese localization. Introduce updated translations for authentication, onboarding, settings, integrations (Plaid, SimpleFin, Lunch Flow), accounts, reports, and various resource pages. Remove or replace legacy locale files to align with the revamped i18n structure and copy organization. This enables full zh-TW support for the UI. * chore(docker): remove published Postgres port Remove the published Postgres port mapping (5432) from the example docker-compose file to avoid exposing the database to the host and to prevent accidental port conflicts. Keeps the example more secure and focused on internal service networking. * docs(i18n): 統一 SimpleFIN 在繁體中文翻譯的大小寫 將 zh-TW 翻譯中所有出現的 "SimpleFin" 更新為品牌正確的 "SimpleFIN", 包含標題、提示文字、成功/錯誤訊息及表單標籤,以維持品牌名稱一致性 並提升使用者介面的翻譯準確性。
390 lines
11 KiB
Ruby
390 lines
11 KiB
Ruby
module LanguagesHelper
|
|
LANGUAGE_MAPPING = {
|
|
en: "English",
|
|
ru: "Russian",
|
|
ar: "Arabic",
|
|
bg: "Bulgarian",
|
|
'ca-CAT': "Catalan (Catalonia)",
|
|
ca: "Catalan",
|
|
'da-DK': "Danish (Denmark)",
|
|
'de-AT': "German (Austria)",
|
|
'de-CH': "German (Switzerland)",
|
|
de: "German",
|
|
ee: "Ewe",
|
|
'en-AU': "English (Australia)",
|
|
'en-BORK': "English (Bork)",
|
|
'en-CA': "English (Canada)",
|
|
'en-GB': "English (United Kingdom)",
|
|
'en-IND': "English (India)",
|
|
'en-KE': "English (Kenya)",
|
|
'en-MS': "English (Malaysia)",
|
|
'en-NEP': "English (Nepal)",
|
|
'en-NG': "English (Nigeria)",
|
|
'en-NZ': "English (New Zealand)",
|
|
'en-PAK': "English (Pakistan)",
|
|
'en-SG': "English (Singapore)",
|
|
'en-TH': "English (Thailand)",
|
|
'en-UG': "English (Uganda)",
|
|
'en-US': "English (United States)",
|
|
'en-ZA': "English (South Africa)",
|
|
'en-au-ocker': "English (Australian Ocker)",
|
|
'es-AR': "Spanish (Argentina)",
|
|
'es-MX': "Spanish (Mexico)",
|
|
es: "Spanish",
|
|
fa: "Persian",
|
|
'fi-FI': "Finnish (Finland)",
|
|
fr: "French",
|
|
'fr-CA': "French (Canada)",
|
|
'fr-CH': "French (Switzerland)",
|
|
he: "Hebrew",
|
|
hy: "Armenian",
|
|
id: "Indonesian",
|
|
it: "Italian",
|
|
ja: "Japanese",
|
|
ko: "Korean",
|
|
lt: "Lithuanian",
|
|
lv: "Latvian",
|
|
'mi-NZ': "Maori (New Zealand)",
|
|
'nb-NO': "Norwegian Bokmål (Norway)",
|
|
nl: "Dutch",
|
|
'no-NO': "Norwegian (Norway)",
|
|
pl: "Polish",
|
|
'pt-BR': "Portuguese (Brazil)",
|
|
pt: "Portuguese",
|
|
sk: "Slovak",
|
|
sv: "Swedish",
|
|
th: "Thai",
|
|
tr: "Turkish",
|
|
uk: "Ukrainian",
|
|
vi: "Vietnamese",
|
|
'zh-CN': "简体中文",
|
|
'zh-TW': "繁體中文",
|
|
af: "Afrikaans",
|
|
az: "Azerbaijani",
|
|
be: "Belarusian",
|
|
bn: "Bengali",
|
|
bs: "Bosnian",
|
|
cs: "Czech",
|
|
cy: "Welsh",
|
|
da: "Danish",
|
|
'de-DE': "German (Germany)",
|
|
dz: "Dzongkha",
|
|
'el-CY': "Greek (Cyprus)",
|
|
el: "Greek",
|
|
'en-CY': "English (Cyprus)",
|
|
'en-IE': "English (Ireland)",
|
|
'en-IN': "English (India)",
|
|
'en-TT': "English (Trinidad and Tobago)",
|
|
eo: "Esperanto",
|
|
'es-419': "Spanish (Latin America)",
|
|
'es-CL': "Spanish (Chile)",
|
|
'es-CO': "Spanish (Colombia)",
|
|
'es-CR': "Spanish (Costa Rica)",
|
|
'es-EC': "Spanish (Ecuador)",
|
|
'es-ES': "Spanish (Spain)",
|
|
'es-NI': "Spanish (Nicaragua)",
|
|
'es-PA': "Spanish (Panama)",
|
|
'es-PE': "Spanish (Peru)",
|
|
'es-US': "Spanish (United States)",
|
|
'es-VE': "Spanish (Venezuela)",
|
|
et: "Estonian",
|
|
eu: "Basque",
|
|
fi: "Finnish",
|
|
'fr-FR': "French (France)",
|
|
fy: "Western Frisian",
|
|
gd: "Scottish Gaelic",
|
|
gl: "Galician",
|
|
'hi-IN': "Hindi (India)",
|
|
hi: "Hindi",
|
|
hr: "Croatian",
|
|
hu: "Hungarian",
|
|
is: "Icelandic",
|
|
'it-CH': "Italian (Switzerland)",
|
|
ka: "Georgian",
|
|
kk: "Kazakh",
|
|
km: "Khmer",
|
|
kn: "Kannada",
|
|
lb: "Luxembourgish",
|
|
lo: "Lao",
|
|
mg: "Malagasy",
|
|
mk: "Macedonian",
|
|
ml: "Malayalam",
|
|
mn: "Mongolian",
|
|
'mr-IN': "Marathi (India)",
|
|
ms: "Malay",
|
|
nb: "Norwegian Bokmål",
|
|
ne: "Nepali",
|
|
nn: "Norwegian Nynorsk",
|
|
oc: "Occitan",
|
|
or: "Odia",
|
|
pa: "Punjabi",
|
|
rm: "Romansh",
|
|
ro: "Romanian",
|
|
sc: "Sardinian",
|
|
sl: "Slovenian",
|
|
sq: "Albanian",
|
|
sr: "Serbian",
|
|
st: "Southern Sotho",
|
|
'sv-FI': "Swedish (Finland)",
|
|
'sv-SE': "Swedish (Sweden)",
|
|
sw: "Swahili",
|
|
ta: "Tamil",
|
|
te: "Telugu",
|
|
tl: "Tagalog",
|
|
tt: "Tatar",
|
|
ug: "Uyghur",
|
|
ur: "Urdu",
|
|
uz: "Uzbek",
|
|
wo: "Wolof"
|
|
}.freeze
|
|
|
|
EXCLUDED_LOCALES = [
|
|
# Test locales
|
|
"en-BORK",
|
|
"en-au-ocker",
|
|
# Duplicate locales
|
|
"fr-FR",
|
|
"de-DE",
|
|
"hi-IN",
|
|
"sv-SE",
|
|
"ca-CAT",
|
|
"en-US",
|
|
"fi-FI",
|
|
"en-IND"
|
|
].freeze
|
|
|
|
# Locales with complete/extensive translations
|
|
SUPPORTED_LOCALES = [
|
|
"en", # English - 62 translation files
|
|
"de", # German - 62 translation files
|
|
"es", # Spanish - 61 translation files
|
|
"tr", # Turkish - 58 translation files
|
|
"nb", # Norwegian Bokmål - 57 translation files
|
|
"ca", # Catalan - 57 translation files
|
|
"ro", # Romanian - 62 translation files
|
|
"pt-BR", # Brazilian Portuguese - 60 translation files
|
|
"zh-CN", # Chinese (Simplified) - 59 translation files
|
|
"zh-TW" # Chinese (Traditional) - 63 translation files
|
|
].freeze
|
|
|
|
COUNTRY_MAPPING = {
|
|
AF: "🇦🇫 Afghanistan",
|
|
AL: "🇦🇱 Albania",
|
|
DZ: "🇩🇿 Algeria",
|
|
AD: "🇦🇩 Andorra",
|
|
AO: "🇦🇴 Angola",
|
|
AG: "🇦🇬 Antigua and Barbuda",
|
|
AR: "🇦🇷 Argentina",
|
|
AM: "🇦🇲 Armenia",
|
|
AU: "🇦🇺 Australia",
|
|
AT: "🇦🇹 Austria",
|
|
AZ: "🇦🇿 Azerbaijan",
|
|
BS: "🇧🇸 Bahamas",
|
|
BH: "🇧🇭 Bahrain",
|
|
BD: "🇧🇩 Bangladesh",
|
|
BB: "🇧🇧 Barbados",
|
|
BY: "🇧🇾 Belarus",
|
|
BE: "🇧🇪 Belgium",
|
|
BZ: "🇧🇿 Belize",
|
|
BJ: "🇧🇯 Benin",
|
|
BT: "🇧🇹 Bhutan",
|
|
BO: "🇧🇴 Bolivia",
|
|
BA: "🇧🇦 Bosnia and Herzegovina",
|
|
BW: "🇧🇼 Botswana",
|
|
BR: "🇧🇷 Brazil",
|
|
BN: "🇧🇳 Brunei",
|
|
BG: "🇧🇬 Bulgaria",
|
|
BF: "🇧🇫 Burkina Faso",
|
|
BI: "🇧🇮 Burundi",
|
|
KH: "🇰🇭 Cambodia",
|
|
CM: "🇨🇲 Cameroon",
|
|
CA: "🇨🇦 Canada",
|
|
CV: "🇨🇻 Cape Verde",
|
|
CF: "🇨🇫 Central African Republic",
|
|
TD: "🇹🇩 Chad",
|
|
CL: "🇨🇱 Chile",
|
|
CN: "🇨🇳 China",
|
|
CO: "🇨🇴 Colombia",
|
|
KM: "🇰🇲 Comoros",
|
|
CG: "🇨🇬 Congo",
|
|
CD: "🇨🇩 Congo, Democratic Republic of the",
|
|
CR: "🇨🇷 Costa Rica",
|
|
CI: "🇨🇮 Côte d'Ivoire",
|
|
HR: "🇭🇷 Croatia",
|
|
CU: "🇨🇺 Cuba",
|
|
CY: "🇨🇾 Cyprus",
|
|
CZ: "🇨🇿 Czech Republic",
|
|
DK: "🇩🇰 Denmark",
|
|
DJ: "🇩🇯 Djibouti",
|
|
DM: "🇩🇲 Dominica",
|
|
DO: "🇩🇴 Dominican Republic",
|
|
EC: "🇪🇨 Ecuador",
|
|
EG: "🇪🇬 Egypt",
|
|
SV: "🇸🇻 El Salvador",
|
|
GQ: "🇬🇶 Equatorial Guinea",
|
|
ER: "🇪🇷 Eritrea",
|
|
EE: "🇪🇪 Estonia",
|
|
ET: "🇪🇹 Ethiopia",
|
|
FJ: "🇫🇯 Fiji",
|
|
FI: "🇫🇮 Finland",
|
|
FR: "🇫🇷 France",
|
|
GA: "🇬🇦 Gabon",
|
|
GM: "🇬🇲 Gambia",
|
|
GE: "🇬🇪 Georgia",
|
|
DE: "🇩🇪 Germany",
|
|
GH: "🇬🇭 Ghana",
|
|
GR: "🇬🇷 Greece",
|
|
GD: "🇬🇩 Grenada",
|
|
GT: "🇬🇹 Guatemala",
|
|
GN: "🇬🇳 Guinea",
|
|
GW: "🇬🇼 Guinea-Bissau",
|
|
GY: "🇬🇾 Guyana",
|
|
HT: "🇭🇹 Haiti",
|
|
HN: "🇭🇳 Honduras",
|
|
HU: "🇭🇺 Hungary",
|
|
IS: "🇮🇸 Iceland",
|
|
IN: "🇮🇳 India",
|
|
ID: "🇮🇩 Indonesia",
|
|
IR: "🇮🇷 Iran",
|
|
IQ: "🇮🇶 Iraq",
|
|
IE: "🇮🇪 Ireland",
|
|
IL: "🇮🇱 Israel",
|
|
IT: "🇮🇹 Italy",
|
|
JM: "🇯🇲 Jamaica",
|
|
JP: "🇯🇵 Japan",
|
|
JO: "🇯🇴 Jordan",
|
|
KZ: "🇰🇿 Kazakhstan",
|
|
KE: "🇰🇪 Kenya",
|
|
KI: "🇰🇮 Kiribati",
|
|
KP: "🇰🇵 North Korea",
|
|
KR: "🇰🇷 South Korea",
|
|
KW: "🇰🇼 Kuwait",
|
|
KG: "🇰🇬 Kyrgyzstan",
|
|
LA: "🇱🇦 Laos",
|
|
LV: "🇱🇻 Latvia",
|
|
LB: "🇱🇧 Lebanon",
|
|
LS: "🇱🇸 Lesotho",
|
|
LR: "🇱🇷 Liberia",
|
|
LY: "🇱🇾 Libya",
|
|
LI: "🇱🇮 Liechtenstein",
|
|
LT: "🇱🇹 Lithuania",
|
|
LU: "🇱🇺 Luxembourg",
|
|
MK: "🇲🇰 North Macedonia",
|
|
MG: "🇲🇬 Madagascar",
|
|
MW: "🇲🇼 Malawi",
|
|
MY: "🇲🇾 Malaysia",
|
|
MV: "🇲🇻 Maldives",
|
|
ML: "🇲🇱 Mali",
|
|
MT: "🇲🇹 Malta",
|
|
MH: "🇲🇭 Marshall Islands",
|
|
MR: "🇲🇷 Mauritania",
|
|
MU: "🇲🇺 Mauritius",
|
|
MX: "🇲🇽 Mexico",
|
|
FM: "🇫🇲 Micronesia",
|
|
MD: "🇲🇩 Moldova",
|
|
MC: "🇲🇨 Monaco",
|
|
MN: "🇲🇳 Mongolia",
|
|
ME: "🇲🇪 Montenegro",
|
|
MA: "🇲🇦 Morocco",
|
|
MZ: "🇲🇿 Mozambique",
|
|
MM: "🇲🇲 Myanmar",
|
|
NA: "🇳🇦 Namibia",
|
|
NR: "🇳🇷 Nauru",
|
|
NP: "🇳🇵 Nepal",
|
|
NL: "🇳🇱 Netherlands",
|
|
NZ: "🇳🇿 New Zealand",
|
|
NI: "🇳🇮 Nicaragua",
|
|
NE: "🇳🇪 Niger",
|
|
NG: "🇳🇬 Nigeria",
|
|
NO: "🇳🇴 Norway",
|
|
OM: "🇴🇲 Oman",
|
|
PK: "🇵🇰 Pakistan",
|
|
PW: "🇵🇼 Palau",
|
|
PA: "🇵🇦 Panama",
|
|
PG: "🇵🇬 Papua New Guinea",
|
|
PY: "🇵🇾 Paraguay",
|
|
PE: "🇵🇪 Peru",
|
|
PH: "🇵🇭 Philippines",
|
|
PL: "🇵🇱 Poland",
|
|
PT: "🇵🇹 Portugal",
|
|
QA: "🇶🇦 Qatar",
|
|
RO: "🇷🇴 Romania",
|
|
RU: "🇷🇺 Russia",
|
|
RW: "🇷🇼 Rwanda",
|
|
KN: "🇰🇳 Saint Kitts and Nevis",
|
|
LC: "🇱🇨 Saint Lucia",
|
|
VC: "🇻🇨 Saint Vincent and the Grenadines",
|
|
WS: "🇼🇸 Samoa",
|
|
SM: "🇸🇲 San Marino",
|
|
ST: "🇸🇹 Sao Tome and Principe",
|
|
SA: "🇸🇦 Saudi Arabia",
|
|
SN: "🇸🇳 Senegal",
|
|
RS: "🇷🇸 Serbia",
|
|
SC: "🇸🇨 Seychelles",
|
|
SL: "🇸🇱 Sierra Leone",
|
|
SG: "🇸🇬 Singapore",
|
|
SK: "🇸🇰 Slovakia",
|
|
SI: "🇸🇮 Slovenia",
|
|
SB: "🇸🇧 Solomon Islands",
|
|
SO: "🇸🇴 Somalia",
|
|
ZA: "🇿🇦 South Africa",
|
|
SS: "🇸🇸 South Sudan",
|
|
ES: "🇪🇸 Spain",
|
|
LK: "🇱🇰 Sri Lanka",
|
|
SD: "🇸🇩 Sudan",
|
|
SR: "🇸🇷 Suriname",
|
|
SE: "🇸🇪 Sweden",
|
|
CH: "🇨🇭 Switzerland",
|
|
SY: "🇸🇾 Syria",
|
|
TW: "🇹🇼 Taiwan",
|
|
TJ: "🇹🇯 Tajikistan",
|
|
TZ: "🇹🇿 Tanzania",
|
|
TH: "🇹🇭 Thailand",
|
|
TL: "🇹🇱 Timor-Leste",
|
|
TG: "🇹🇬 Togo",
|
|
TO: "🇹🇴 Tonga",
|
|
TT: "🇹🇹 Trinidad and Tobago",
|
|
TN: "🇹🇳 Tunisia",
|
|
TR: "🇹🇷 Turkey",
|
|
TM: "🇹🇲 Turkmenistan",
|
|
TV: "🇹🇻 Tuvalu",
|
|
UG: "🇺🇬 Uganda",
|
|
UA: "🇺🇦 Ukraine",
|
|
AE: "🇦🇪 United Arab Emirates",
|
|
GB: "🇬🇧 United Kingdom",
|
|
US: "🇺🇸 United States",
|
|
UY: "🇺🇾 Uruguay",
|
|
UZ: "🇺🇿 Uzbekistan",
|
|
VU: "🇻🇺 Vanuatu",
|
|
VA: "🇻🇦 Vatican City",
|
|
VE: "🇻🇪 Venezuela",
|
|
VN: "🇻🇳 Vietnam",
|
|
YE: "🇾🇪 Yemen",
|
|
ZM: "🇿🇲 Zambia",
|
|
ZW: "🇿🇼 Zimbabwe"
|
|
}.freeze
|
|
|
|
def country_options
|
|
COUNTRY_MAPPING.keys.map { |key| [ COUNTRY_MAPPING[key], key ] }
|
|
end
|
|
|
|
def language_options
|
|
I18n.available_locales
|
|
.select { |locale| SUPPORTED_LOCALES.include?(locale.to_s) }
|
|
.map do |locale|
|
|
label = LANGUAGE_MAPPING[locale.to_sym] || locale.to_s.humanize
|
|
[ "#{label} (#{locale})", locale ]
|
|
end
|
|
.sort_by { |label, locale| label }
|
|
end
|
|
|
|
def timezone_options
|
|
ActiveSupport::TimeZone.all
|
|
.sort_by { |tz| [ tz.utc_offset, tz.name ] }
|
|
.map do |tz|
|
|
name = tz.name.split(" - ").first.gsub(" (US & Canada)", "")
|
|
[ "(#{tz.formatted_offset}) #{name}", tz.tzinfo.identifier ]
|
|
end
|
|
end
|
|
end
|