11package processing.app.ui.theme
22
3- import androidx.compose.runtime.Composable
4- import androidx.compose.runtime.CompositionLocalProvider
5- import androidx.compose.runtime.compositionLocalOf
6- import processing.app.LocalPreferences
7- import processing.app.Messages
8- import processing.app.Platform
9- import processing.app.PlatformStart
10- import processing.app.watchFile
3+ import androidx.compose.runtime.*
4+ import androidx.compose.ui.platform.LocalLayoutDirection
5+ import androidx.compose.ui.unit.LayoutDirection
6+ import processing.app.*
117import java.io.File
128import java.io.InputStream
139import java.util.*
1410
15- class Locale (language : String = " " ) : Properties() {
11+ /* *
12+ * The Locale class extends the standard Java Properties class
13+ * to provide localization capabilities.
14+ * It loads localization resources from property files based on the specified language code.
15+ * The class also provides a method to change the current locale and update the application accordingly.
16+ * Usage:
17+ * ```
18+ * val locale = Locale("es") { newLocale ->
19+ * // Handle locale change, e.g., update UI or restart application
20+ * }
21+ * val localizedString = locale["someKey"]
22+ * ```
23+ */
24+ class Locale (language : String = " " , val setLocale : ((java.util.Locale ) -> Unit )? = null ) : Properties() {
25+ var locale: java.util.Locale = java.util.Locale .getDefault()
26+
1627 init {
17- val locale = java.util.Locale .getDefault()
18- load(ClassLoader .getSystemResourceAsStream(" PDE.properties" ))
19- load(ClassLoader .getSystemResourceAsStream(" PDE_${locale.language} .properties" ) ? : InputStream .nullInputStream())
20- load(ClassLoader .getSystemResourceAsStream(" PDE_${locale.toLanguageTag()} .properties" ) ? : InputStream .nullInputStream())
21- load(ClassLoader .getSystemResourceAsStream(" PDE_${language} .properties" ) ? : InputStream .nullInputStream())
28+ loadResourceUTF8(" PDE.properties" )
29+ loadResourceUTF8(" PDE_${locale.language} .properties" )
30+ loadResourceUTF8(" PDE_${locale.toLanguageTag()} .properties" )
31+ loadResourceUTF8(" PDE_${language} .properties" )
32+ }
33+
34+ fun loadResourceUTF8 (path : String ) {
35+ val stream = ClassLoader .getSystemResourceAsStream(path)
36+ stream?.reader(charset = Charsets .UTF_8 )?.use { reader ->
37+ load(reader)
38+ }
2239 }
2340
2441 @Deprecated(" Use get instead" , ReplaceWith (" get(key)" ))
@@ -28,18 +45,86 @@ class Locale(language: String = "") : Properties() {
2845 return value
2946 }
3047 operator fun get (key : String ): String = getProperty(key, key)
48+ fun set (locale : java.util.Locale ) {
49+ setLocale?.invoke(locale)
50+ }
3151}
32- val LocalLocale = compositionLocalOf { Locale () }
52+ /* *
53+ * A CompositionLocal to provide access to the Locale instance
54+ * throughout the composable hierarchy. see [LocaleProvider]
55+ * Usage:
56+ * ```
57+ * val locale = LocalLocale.current
58+ * val localizedString = locale["someKey"]
59+ * ```
60+ */
61+ val LocalLocale = compositionLocalOf<Locale > { error(" No Locale Set" ) }
62+
63+ /* *
64+ * This composable function sets up a locale provider that manages application localization.
65+ * It initializes the locale from a language file, watches for changes to that file, and updates
66+ * the locale accordingly. It uses a [Locale] class to handle loading of localized resources.
67+ *
68+ * Usage:
69+ * ```
70+ * LocaleProvider {
71+ * // Your app content here
72+ * }
73+ * ```
74+ *
75+ * To access the locale:
76+ * ```
77+ * val locale = LocalLocale.current
78+ * val localizedString = locale["someKey"]
79+ * ```
80+ *
81+ * To change the locale:
82+ * ```
83+ * locale.set(java.util.Locale("es"))
84+ * ```
85+ * This will update the `language.txt` file and reload the locale.
86+ */
3387@Composable
3488fun LocaleProvider (content : @Composable () -> Unit ) {
35- PlatformStart ()
89+ val preferencesFolderOverride: File ? = System .getProperty(" processing.app.preferences.folder" )?.let { File (it) }
90+
91+ val settingsFolder = preferencesFolderOverride ? : remember{
92+ Platform .init ()
93+ Platform .getSettingsFolder()
94+ }
95+ val languageFile = settingsFolder.resolve(" language.txt" )
96+ remember(languageFile){
97+ if (languageFile.exists()) return @remember
3698
37- val settingsFolder = Platform .getSettingsFolder()
38- val languageFile = File (settingsFolder, " language.txt" )
39- watchFile(languageFile)
99+ Messages .log(" Creating language file at ${languageFile.absolutePath} " )
100+ settingsFolder.mkdirs()
101+ languageFile.writeText(java.util.Locale .getDefault().language)
102+ }
103+
104+ val update = watchFile(languageFile)
105+ var code by remember(languageFile, update){ mutableStateOf(languageFile.readText().substring(0 , 2 )) }
106+ remember(code) {
107+ val locale = java.util.Locale (code)
108+ java.util.Locale .setDefault(locale)
109+ }
110+
111+ fun setLocale (locale : java.util.Locale ) {
112+ Messages .log(" Setting locale to ${locale.language} " )
113+ languageFile.writeText(locale.language)
114+ code = locale.language
115+ }
116+
117+
118+ val locale = Locale (code, ::setLocale)
119+ remember(code) { Messages .log(" Loaded Locale: $code " ) }
120+ val dir = when (locale[" locale.direction" ]) {
121+ " rtl" -> LayoutDirection .Rtl
122+ else -> LayoutDirection .Ltr
123+ }
40124
41- val locale = Locale (languageFile.readText().substring(0 , 2 ))
42- CompositionLocalProvider (LocalLocale provides locale) {
43- content()
125+ CompositionLocalProvider (LocalLayoutDirection provides dir) {
126+ CompositionLocalProvider (LocalLocale provides locale) {
127+ content()
128+ }
44129 }
45130}
0 commit comments