Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

L10N module (for discussion only) #5059

Draft
wants to merge 16 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
123 changes: 51 additions & 72 deletions compiler.r

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions environment/console/CLI/console.red
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Red [
Distributed under the Boost Software License, Version 1.0.
See https://github.com/red/red/blob/master/BSL-License.txt
}
Needs: [L10N]
]

#include %input.red
Expand Down
2 changes: 1 addition & 1 deletion environment/console/GUI/gui-console.red
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Red [
Tabs: 4
Icon: %app.ico
Version: 0.0.1
Needs: View
Needs: [View L10N]
Config: [gui-console?: yes red-help?: yes]
Rights: "Copyright (C) 2014-2018 Red Foundation. All rights reserved."
License: {
Expand Down
5 changes: 5 additions & 0 deletions environment/console/engine.red
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,11 @@ system/console: context [
]

launch: function [/local result][
;@@ temporary locale init code, until a better way is possible:
;-- populate system/locale
;-- (has to be done after all locales are loaded because 'best' locale depends on what's available)
if value? 'load-locale [do [load-locale system/locale/tools/get-best-locale-id]]

either script: src: read-argument [
parse/case script [some [[pos: "Red" opt "/System" any ws #"[" to end] | skip]]
either script: pos [
Expand Down
42 changes: 26 additions & 16 deletions environment/system.red
Original file line number Diff line number Diff line change
Expand Up @@ -310,26 +310,33 @@ system: context [
ports: context []

locale: context [
language:
language*: ;-- in locale language
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the * names because IMO they are very cryptic. I couldn't figure out what they are for until I found comments in the code.

locale:
locale*: none ;-- in locale language

;; data for chosen locale:
name: none ;-- "language (region)" spelled in locale's language
lang-name: none ;-- language name only (e.g. "English")
region-name: none ;-- region name only (e.g. "United States")
locale: none ;-- full locale tag (e.g. 'en_US)
language: none ;-- language tag only (e.g. 'en)
region: none ;-- abbreviated word name of the region (e.g. 'US)
currency: none ;-- default currency for locale
numbers: none ;-- digits, symbols, numeric masks
calendar: none ;-- standalone, format, date masks
months: none ;-- shortcut for standalone month names (R2-compatibility)
days: none ;-- shortcut for standalone day names (R2-compatibility)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

months and days seems to come from R2, but I should question their usefulness.
We have data for both standalone (used in calendar) and formatted (used in dates) month and day names as system/locale/calendar/format/months/full and ../standalone/months/full (and days), but these two are shortcuts for the standalone version only.
Moreover, in our data we have days as a map: #(sun "Sunday" .. mon "Monday") etc, because first day of the week is different in different locales (in fact, about 50/50 split between Monday and Sunday), and days order as a block of 1-7 indexes where 1=Monday (as it came from R2) may be confusing.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe, that this area is not easy to get right in al its complexity. But having months / days available under calendar/format/months/full makes me ask - what is format here? What is full here? Sounds quite cryptic, but I can understand that most probably inner structure is not something for an end user to care about, if there are accessor functions to easily get such elements.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be too big to include here. Just see for example cs.red file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Data is meant not only for format functions (in fact, only format branch is used by them), but also if you want to localize your UI or smth. Or you can write your own locale or modify already existing (e.g. by adding strings: map for all UI elements text). So it's for more involved users.


;; collective data:
list: #() ;-- locale data for all supported (loaded) locales
numbering-systems: none ;-- all numbering systems from CLDR (they're small)
cardinal: none ;-- cardinal quantities spelling rules
ordinal: none ;-- ordinal quantities spelling rules
tools: none ;-- place for l10n functions (needed by boot.red)

;collation: context [
; lower-to-upper: #system [stack/set-last as cell! case-folding/lower-to-upper]
; upper-to-lower: #system [stack/set-last as cell! case-folding/upper-to-lower]
;]

months: [
"January" "February" "March" "April" "May" "June"
"July" "August" "September" "October" "November" "December"
]

days: [
"Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"
]

currencies: context [
names: none ;-- full names in current locale
;-- ISO currencies + BTC, ETH, RED
list: [
AED AFN ALL AMD ANG AOA ARS AUD AWG AZN BAM BBD BDT BTC BGN BHD BIF BMD BND BOB BRL BSD
Expand All @@ -342,10 +349,13 @@ system: context [
USD UYU UZS VES VND VUV WST CFA XAF XCD XOF CFP XPF YER ZAR ZMW
]
on-change*: func [word old new][
set-quiet in self word old
cause-error 'script 'protected []
if word <> 'names [
set-quiet in self word old
cause-error 'script 'protected []
]
]
on-deep-change*: func [owner word target action new index part][
if word = 'names [exit]
if any [
word <> 'list
not find [append appended] action
Expand Down
131 changes: 131 additions & 0 deletions modules/l10n/core.red
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
Red [
Title: "Localization core functions and data"
Author: @hiiamboris
Rights: "Copyright (C) 2021 Red Foundation. All rights reserved."
License: {
Distributed under the Boost Software License, Version 1.0.
See https://github.com/red/red/blob/master/BSL-License.txt
}
]

#include %numbering-systems.red
#include %plural.red

system/locale/tools: context [
#either config/OS = 'Windows [
;; setlocale is useless on Windows, will just always return "C", so have to use winape
#system [
#define LOCALE_NAME_MAX_LENGTH 85 ;-- in Wchars
#import [
"kernel32.dll" stdcall [
GetUserDefaultLocaleName: "GetUserDefaultLocaleName" [
lpLocaleName [byte-ptr!]
cchLocaleName [integer!]
return: [integer!]
]
]
]
]

get-user-locale-id*: routine [
return: [string!]
/local wchars [byte-ptr!] len [integer!] str [red-string!]
][
wchars: allocate LOCALE_NAME_MAX_LENGTH * 2
len: GetUserDefaultLocaleName wchars LOCALE_NAME_MAX_LENGTH
assert len > 0
str: string/load as c-string! wchars len - 1 UTF-16LE
free wchars
str
]
][
get-user-locale-id*: routine [
return: [string!]
/local s [c-string!]
][
s: setlocale __LC_CTYPE null
string/load s length? s UTF-8
]
]

get-user-locale-id: function [/local lang regn] [ ;-- returns 'en_US or something
lower: charset [#"a" - #"z"]
upper: charset [#"A" - #"Z"]
non-alpha: negate union lower upper
sep: [#"_" | #"-"]
=language=: [2 lower ahead [non-alpha | end]]
=region=: [2 upper ahead [non-alpha | end]]
parse s: get-user-locale-id* [
["C" | "POSIX"] opt ["." to end] end (return 'red) ;-- portable POSIX locale, 'red' is our portable locale
| copy lang =language= opt [to =region= copy regn =region=] (
if regn [repend lang ["_" regn]]
return to word! lang
)
| (return 'red) ;-- unindentified, default to 'red'
]
]

get-best-locale-id: function [] [ ;-- returns best locale from those supported
loc: get-user-locale-id
case [
system/locale/list/:loc [loc]
all [
formed: form loc
clear find loc "_"
lang: to word! formed
system/locale/list/:lang
] [lang]
'fallback ['red]
]
]

inherit: function [src dst] [ ;-- links data between maps without override
foreach [key srcval] src [
case [
not find dst key [dst/:key: srcval] ;-- carry over as reference when possible
all [map? dst/:key map? srcval] [
inherit srcval dst/:key
]
]
]
]

;; useful when we want to use a locale without loading it as default
expand-locale: function [
"Expand given locale from minimized form into a working state"
name [word!]
][
loc: system/locale/list/:name
unless loc/parent [exit] ;-- already expanded

expand-locale loc/parent
inherit system/locale/list/(loc/parent) loc
remove/key loc 'parent ;-- mark as expanded
]

load-locale: function [
"Load given locale as default into system/locale"
name [word!]
][
expand-locale name
sl: system/locale
unless data: sl/list/:name [
do make error! rejoin ["Data for locale '" name "' is not loaded"]
]
foreach [key val] data [if word: in sl key [set word val]]
sl/locale: name
set bind [language region] sl split form name #"_"
sl/name: copy data/lang-name
if sl/region [repend sl/name [" (" data/region-name ")"]]
sl/currencies/names: data/currency-names
;; for R2 compatibility:
sl/months: data/calendar/standalone/months/full
m: data/calendar/standalone/days/full
sl/days: reduce [m/mon m/tue m/wed m/thu m/fri m/sat m/sun] ;-- in R2 it started from monday always
() ;-- no return value
]

system/words/expand-locale: :expand-locale
system/words/load-locale: :load-locale
]

12 changes: 12 additions & 0 deletions modules/l10n/l10n.red
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Red [
Title: "Full localization module"
Author: @hiiamboris
Rights: "Copyright (C) 2021 Red Foundation. All rights reserved."
License: {
Distributed under the Boost Software License, Version 1.0.
See https://github.com/red/red/blob/master/BSL-License.txt
}
]

#include %core.red
#include %locales.red
52 changes: 52 additions & 0 deletions modules/l10n/locales.red
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
Red [
title: "All-in-one locale data"
notes: "DO NOT MODIFY! Generated automatically"
license: https://github.com/red/red/blob/master/BSL-License.txt
]

#include %locales/af.red
#include %locales/af_ZA.red
#include %locales/ar.red
#include %locales/ar_AE.red
#include %locales/ar_EG.red
#include %locales/ar_SA.red
#include %locales/bg.red
#include %locales/bg_BG.red
#include %locales/cs.red
#include %locales/cs_CZ.red
#include %locales/de.red
#include %locales/de_DE.red
#include %locales/en.red
#include %locales/en_AU.red
#include %locales/en_CA.red
#include %locales/en_GB.red
#include %locales/en_US.red
#include %locales/es.red
#include %locales/es_ES.red
#include %locales/es_MX.red
#include %locales/fr.red
#include %locales/fr_CA.red
#include %locales/fr_FR.red
#include %locales/he.red
#include %locales/he_IL.red
#include %locales/hi.red
#include %locales/hi_IN.red
#include %locales/it.red
#include %locales/it_IT.red
#include %locales/ja.red
#include %locales/ja_JP.red
#include %locales/ko.red
#include %locales/ko_KR.red
#include %locales/pl.red
#include %locales/pl_PL.red
#include %locales/pt.red
#include %locales/pt_BR.red
#include %locales/root.red
#include %locales/ru.red
#include %locales/ru_BY.red
#include %locales/ru_RU.red
#include %locales/ru_UA.red
#include %locales/tr.red
#include %locales/tr_TR.red
#include %locales/zh.red
#include %locales/red.red
3 changes: 3 additions & 0 deletions modules/l10n/locales/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Red locale data

Files here with the exception of `red.red` were *generated from* CLDR data using [these tools](https://gitlab.com/hiiamboris/icu) and as such are subject to original [Unicode.org license](https://github.com/unicode-cldr/cldr-core/blob/master/LICENSE)